diff options
author | Kenny Root <kroot@google.com> | 2013-12-11 16:35:05 -0800 |
---|---|---|
committer | Kenny Root <kroot@google.com> | 2013-12-12 16:48:48 -0800 |
commit | 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96 (patch) | |
tree | ba9d9a42f9ed5478b4205c83c13a0e94b55a8c6c /bcprov | |
parent | c0444a1be12b67cbad8b4858f0d65a0d75db15a9 (diff) | |
download | android_external_bouncycastle-5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96.tar.gz android_external_bouncycastle-5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96.tar.bz2 android_external_bouncycastle-5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96.zip |
Upgrade to Bouncycastle 1.50
SHA256 sums of source packages:
0be5bb948ec481b3d1f30ee80ef593b298b3782697f9eeee5c74cf270689b520 bcpkix-jdk15on-150.tar.gz
468259c9166fbcf87ad284ae46fae45408cb7cfc9c406862ea75d5b8696f4f2a bcprov-jdk15on-150.tar.gz
Change-Id: Id566e9137f85d8328e9f0cb0472ff2f6ae7a71d3
Diffstat (limited to 'bcprov')
135 files changed, 9333 insertions, 2762 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java index 7281a6a..98ab0d6 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java @@ -11,9 +11,9 @@ public interface BERTags public static final int EXTERNAL = 0x08; public static final int ENUMERATED = 0x0a; public static final int SEQUENCE = 0x10; - public static final int SEQUENCE_OF = 0x10; // for completeness + public static final int SEQUENCE_OF = 0x10; // for completeness - used to model a SEQUENCE of the same type. public static final int SET = 0x11; - public static final int SET_OF = 0x11; // for completeness + public static final int SET_OF = 0x11; // for completeness - used to model a SET of the same type. public static final int NUMERIC_STRING = 0x12; diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java index 74acda6..634f5a8 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java @@ -177,7 +177,7 @@ public class DERBoolean { if (value.length != 1) { - throw new IllegalArgumentException("byte value should have 1 byte in it"); + throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it"); } if (value[0] == 0) diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java b/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java index 2f299ee..9b1ef55 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java @@ -5,6 +5,9 @@ import java.math.BigInteger; import org.bouncycastle.util.Arrays; +/** + * Use ASN1Enumerated instead of this. + */ public class DEREnumerated extends ASN1Primitive { @@ -52,7 +55,7 @@ public class DEREnumerated * @exception IllegalArgumentException if the tagged object cannot * be converted. */ - public static DEREnumerated getInstance( + public static ASN1Enumerated getInstance( ASN1TaggedObject obj, boolean explicit) { @@ -68,18 +71,27 @@ public class DEREnumerated } } + /** + * @deprecated use ASN1Enumerated + */ public DEREnumerated( int value) { bytes = BigInteger.valueOf(value).toByteArray(); } + /** + * @deprecated use ASN1Enumerated + */ public DEREnumerated( BigInteger value) { bytes = value.toByteArray(); } + /** + * @deprecated use ASN1Enumerated + */ public DEREnumerated( byte[] bytes) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java index 3804450..57cc84a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java @@ -5,6 +5,9 @@ import java.math.BigInteger; import org.bouncycastle.util.Arrays; +/** + * Use ASN1Integer instead of this, + */ public class DERInteger extends ASN1Primitive { @@ -67,18 +70,27 @@ public class DERInteger } } + /** + * @deprecated use ASN1Integer constructor + */ public DERInteger( long value) { bytes = BigInteger.valueOf(value).toByteArray(); } + /** + * @deprecated use ASN1Integer constructor + */ public DERInteger( BigInteger value) { bytes = value.toByteArray(); } + /** + * @deprecated use ASN1Integer constructor + */ public DERInteger( byte[] bytes) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java index 13e1195..b82647e 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java @@ -6,6 +6,9 @@ import java.math.BigInteger; import org.bouncycastle.util.Arrays; +/** + * Use ASN1ObjectIdentifier instead of this, + */ public class DERObjectIdentifier extends ASN1Primitive { @@ -38,7 +41,22 @@ public class DERObjectIdentifier if (obj instanceof byte[]) { - return ASN1ObjectIdentifier.fromOctetString((byte[])obj); + byte[] enc = (byte[])obj; + if (enc[0] == BERTags.OBJECT_IDENTIFIER) + { + try + { + return (ASN1ObjectIdentifier)fromByteArray(enc); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage()); + } + } + else + { // TODO: this really shouldn't be supported here... + return ASN1ObjectIdentifier.fromOctetString((byte[])obj); + } } throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); @@ -154,6 +172,9 @@ public class DERObjectIdentifier this.body = Arrays.clone(bytes); } + /** + * @deprecated use ASN1ObjectIdentifier constructor. + */ public DERObjectIdentifier( String identifier) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java index bb8ec4e..b5cc59a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java @@ -3,20 +3,23 @@ package org.bouncycastle.asn1; import java.io.IOException; import java.util.Enumeration; +/** + * The DLSequence encodes a SEQUENCE using definite length form. + */ public class DLSequence extends ASN1Sequence { private int bodyLength = -1; /** - * create an empty sequence + * Create an empty sequence */ public DLSequence() { } /** - * create a sequence containing one object + * Create a sequence containing one object */ public DLSequence( ASN1Encodable obj) @@ -25,7 +28,7 @@ public class DLSequence } /** - * create a sequence containing a vector of objects. + * Create a sequence containing a vector of objects. */ public DLSequence( ASN1EncodableVector v) @@ -34,7 +37,7 @@ public class DLSequence } /** - * create a sequence containing an array of objects. + * Create a sequence containing an array of objects. */ public DLSequence( ASN1Encodable[] array) @@ -51,7 +54,7 @@ public class DLSequence for (Enumeration e = this.getObjects(); e.hasMoreElements();) { - Object obj = e.nextElement(); + Object obj = e.nextElement(); length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength(); } @@ -65,12 +68,12 @@ public class DLSequence int encodedLength() throws IOException { - int length = getBodyLength(); + int length = getBodyLength(); return 1 + StreamUtil.calculateBodyLength(length) + length; } - /* + /** * A note on the implementation: * <p> * As DL requires the constructed, definite-length model to @@ -82,17 +85,17 @@ public class DLSequence ASN1OutputStream out) throws IOException { - ASN1OutputStream dOut = out.getDLSubStream(); - int length = getBodyLength(); + ASN1OutputStream dOut = out.getDLSubStream(); + int length = getBodyLength(); out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); out.writeLength(length); for (Enumeration e = this.getObjects(); e.hasMoreElements();) { - Object obj = e.nextElement(); + Object obj = e.nextElement(); dOut.writeObject((ASN1Encodable)obj); } } -} +}
\ No newline at end of file diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java index 755754b..91e83fa 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java @@ -4,7 +4,52 @@ import java.io.IOException; import java.util.Enumeration; /** - * A DER encoded set object + * The DLSet encodes ASN.1 SET value without element ordering, + * and always using definite length form. + * <hr> + * <h2>X.690</h2> + * <h3>8: Basic encoding rules</h3> + * <h4>8.11 Encoding of a set value </h4> + * <b>8.11.1</b> The encoding of a set value shall be constructed + * <p/> + * <b>8.11.2</b> The contents octets shall consist of the complete + * encoding of a data value from each of the types listed in the + * ASN.1 definition of the set type, in an order chosen by the sender, + * unless the type was referenced with the keyword + * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>. + * <p/> + * <b>8.11.3</b> The encoding of a data value may, but need not, + * be present for a type which was referenced with the keyword + * <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>. + * <blockquote> + * NOTE — The order of data values in a set value is not significant, + * and places no constraints on the order during transfer + * </blockquote> + * <h3>9: Canonical encoding rules</h3> + * <h4>9.3 Set components</h4> + * The encodings of the component values of a set value shall + * appear in an order determined by their tags as specified + * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1. + * Additionally, for the purposes of determining the order in which + * components are encoded when one or more component is an untagged + * choice type, each untagged choice type is ordered as though it + * has a tag equal to that of the smallest tag in that choice type + * or any untagged choice types nested within. + * <h3>10: Distinguished encoding rules</h3> + * <h4>10.3 Set components</h4> + * The encodings of the component values of a set value shall appear + * in an order determined by their tags as specified + * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1. + * <blockquote> + * NOTE — Where a component of the set is an untagged choice type, + * the location of that component in the ordering will depend on + * the tag of the choice component being encoded. + * </blockquote> + * <h3>11: Restrictions on BER employed by both CER and DER</h3> + * <h4>11.5 Set and sequence components with default value </h4> + * The encoding of a set value or sequence value shall not include + * an encoding for any component value which is equal to + * its default value. */ public class DLSet extends ASN1Set @@ -54,7 +99,7 @@ public class DLSet for (Enumeration e = this.getObjects(); e.hasMoreElements();) { - Object obj = e.nextElement(); + Object obj = e.nextElement(); length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength(); } @@ -68,12 +113,12 @@ public class DLSet int encodedLength() throws IOException { - int length = getBodyLength(); + int length = getBodyLength(); return 1 + StreamUtil.calculateBodyLength(length) + length; } - /* + /** * A note on the implementation: * <p> * As DL requires the constructed, definite-length model to @@ -85,17 +130,17 @@ public class DLSet ASN1OutputStream out) throws IOException { - ASN1OutputStream dOut = out.getDLSubStream(); - int length = getBodyLength(); + ASN1OutputStream dOut = out.getDLSubStream(); + int length = getBodyLength(); out.write(BERTags.SET | BERTags.CONSTRUCTED); out.writeLength(length); for (Enumeration e = this.getObjects(); e.hasMoreElements();) { - Object obj = e.nextElement(); + Object obj = e.nextElement(); dOut.writeObject((ASN1Encodable)obj); } } -} +}
\ No newline at end of file diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java index 18fc66c..16a6768 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java @@ -2,50 +2,70 @@ package org.bouncycastle.asn1.bc; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +/** + * iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle + * <p> + * 1.3.6.1.4.1.22554 + */ public interface BCObjectIdentifiers { /** * iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle - * + *<p> * 1.3.6.1.4.1.22554 */ public static final ASN1ObjectIdentifier bc = new ASN1ObjectIdentifier("1.3.6.1.4.1.22554"); /** * pbe(1) algorithms + * <p> + * 1.3.6.1.4.1.22554.1 */ - public static final ASN1ObjectIdentifier bc_pbe = new ASN1ObjectIdentifier(bc.getId() + ".1"); + public static final ASN1ObjectIdentifier bc_pbe = bc.branch("1"); /** * SHA-1(1) + * <p> + * 1.3.6.1.4.1.22554.1.1 */ - public static final ASN1ObjectIdentifier bc_pbe_sha1 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".1"); + public static final ASN1ObjectIdentifier bc_pbe_sha1 = bc_pbe.branch("1"); - /** - * SHA-2(2) . (SHA-256(1)|SHA-384(2)|SHA-512(3)|SHA-224(4)) - */ - public static final ASN1ObjectIdentifier bc_pbe_sha256 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.1"); - public static final ASN1ObjectIdentifier bc_pbe_sha384 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.2"); - public static final ASN1ObjectIdentifier bc_pbe_sha512 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.3"); - public static final ASN1ObjectIdentifier bc_pbe_sha224 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.4"); + /** SHA-2.SHA-256; 1.3.6.1.4.1.22554.1.2.1 */ + public static final ASN1ObjectIdentifier bc_pbe_sha256 = bc_pbe.branch("2.1"); + /** SHA-2.SHA-384; 1.3.6.1.4.1.22554.1.2.2 */ + public static final ASN1ObjectIdentifier bc_pbe_sha384 = bc_pbe.branch("2.2"); + /** SHA-2.SHA-512; 1.3.6.1.4.1.22554.1.2.3 */ + public static final ASN1ObjectIdentifier bc_pbe_sha512 = bc_pbe.branch("2.3"); + /** SHA-2.SHA-224; 1.3.6.1.4.1.22554.1.2.4 */ + public static final ASN1ObjectIdentifier bc_pbe_sha224 = bc_pbe.branch("2.4"); /** * PKCS-5(1)|PKCS-12(2) */ - public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs5 = new ASN1ObjectIdentifier(bc_pbe_sha1.getId() + ".1"); - public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12 = new ASN1ObjectIdentifier(bc_pbe_sha1.getId() + ".2"); + /** SHA-1.PKCS5; 1.3.6.1.4.1.22554.1.1.1 */ + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs5 = bc_pbe_sha1.branch("1"); + /** SHA-1.PKCS12; 1.3.6.1.4.1.22554.1.1.2 */ + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12 = bc_pbe_sha1.branch("2"); - public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs5 = new ASN1ObjectIdentifier(bc_pbe_sha256.getId() + ".1"); - public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12 = new ASN1ObjectIdentifier(bc_pbe_sha256.getId() + ".2"); + /** SHA-256.PKCS12; 1.3.6.1.4.1.22554.1.2.1.1 */ + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs5 = bc_pbe_sha256.branch("1"); + /** SHA-256.PKCS12; 1.3.6.1.4.1.22554.1.2.1.2 */ + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12 = bc_pbe_sha256.branch("2"); /** * AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42)) */ - public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.2"); - public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.22"); - public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.42"); + /** 1.3.6.1.4.1.22554.1.1.2.1.2 */ + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = bc_pbe_sha1_pkcs12.branch("1.2"); + /** 1.3.6.1.4.1.22554.1.1.2.1.22 */ + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = bc_pbe_sha1_pkcs12.branch("1.22"); + /** 1.3.6.1.4.1.22554.1.1.2.1.42 */ + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = bc_pbe_sha1_pkcs12.branch("1.42"); - public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.2"); - public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.22"); - public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.42"); + /** 1.3.6.1.4.1.22554.1.1.2.2.2 */ + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = bc_pbe_sha256_pkcs12.branch("1.2"); + /** 1.3.6.1.4.1.22554.1.1.2.2.22 */ + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = bc_pbe_sha256_pkcs12.branch("1.22"); + /** 1.3.6.1.4.1.22554.1.1.2.2.42 */ + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = bc_pbe_sha256_pkcs12.branch("1.42"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java index b5a2f34..066cf69 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java @@ -10,6 +10,27 @@ import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; +/** + * <a href="http://tools.ietf.org/html/rfc5652#page-14">RFC 5652</a>: + * Attribute is a pair of OID (as type identifier) + set of values. + * <p> + * <pre> + * Attribute ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue + * } + * + * AttributeValue ::= ANY + * </pre> + * <p> + * General rule on values is that same AttributeValue must not be included + * multiple times into the set. That is, if the value is a SET OF INTEGERs, + * then having same value repeated is wrong: (1, 1), but different values is OK: (1, 2). + * Normally the AttributeValue syntaxes are more complicated than that. + * <p> + * General rule of Attribute usage is that the {@link Attributes} containers + * must not have multiple Attribute:s with same attrType (OID) there. + */ public class Attribute extends ASN1Object { @@ -17,7 +38,14 @@ public class Attribute private ASN1Set attrValues; /** - * return an Attribute object from the given object. + * Return an Attribute object from the given object. + * <p> + * Accepted inputs: + * <ul> + * <li> null → null + * <li> {@link Attribute} object + * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with Attribute structure inside + * </ul> * * @param o the object we want converted. * @exception IllegalArgumentException if the object cannot be converted. @@ -81,12 +109,6 @@ public class Attribute /** * Produce an object suitable for an ASN1OutputStream. - * <pre> - * Attribute ::= SEQUENCE { - * attrType OBJECT IDENTIFIER, - * attrValues SET OF AttributeValue - * } - * </pre> */ public ASN1Primitive toASN1Primitive() { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java index f114623..02b6cc1 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java @@ -11,6 +11,9 @@ import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSet; +/** + * This is helper tool to construct {@link Attributes} sets. + */ public class AttributeTable { private Hashtable attributes = new Hashtable(); diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java index 614e224..e21c8a7 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java @@ -6,6 +6,21 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.DLSet; +/** + * <a href="http://tools.ietf.org/html/rfc5652">RFC 5652</a> defines + * 5 "SET OF Attribute" entities with 5 different names. + * This is common implementation for them all: + * <pre> + * SignedAttributes ::= SET SIZE (1..MAX) OF Attribute + * UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute + * UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute + * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute + * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * Attributes ::= + * SET SIZE(1..MAX) OF Attribute + * </pre> + */ public class Attributes extends ASN1Object { @@ -21,6 +36,19 @@ public class Attributes attributes = new DLSet(v); } + /** + * Return an Attribute set object from the given object. + * <p> + * Accepted inputs: + * <ul> + * <li> null → null + * <li> {@link Attributes} object + * <li> {@link org.bouncycastle.asn1.ASN1Set#getInstance(java.lang.Object) ASN1Set} input formats with Attributes structure inside + * </ul> + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ public static Attributes getInstance(Object obj) { if (obj instanceof Attributes) @@ -47,12 +75,8 @@ public class Attributes return rv; } - /** - * <pre> - * Attributes ::= - * SET SIZE(1..MAX) OF Attribute -- according to RFC 5652 - * </pre> - * @return + /** + * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java index 5e97324..d2fc7d1 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java @@ -3,11 +3,28 @@ package org.bouncycastle.asn1.cms; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +/** + * <a href="http://tools.ietf.org/html/rfc5652">RFC 5652</a> CMS attribute OID constants. + * <pre> + * contentType ::= 1.2.840.113549.1.9.3 + * messageDigest ::= 1.2.840.113549.1.9.4 + * signingTime ::= 1.2.840.113549.1.9.5 + * counterSignature ::= 1.2.840.113549.1.9.6 + * + * contentHint ::= 1.2.840.113549.1.9.16.2.4 + * </pre> + */ + public interface CMSAttributes { + /** PKCS#9: 1.2.840.113549.1.9.3 */ public static final 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; + /** PKCS#9: 1.2.840.113549.1.9.5 */ public static final 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; + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */ public static final ASN1ObjectIdentifier contentHint = PKCSObjectIdentifiers.id_aa_contentHint; } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java index 6294d97..b88bf6e 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java @@ -5,24 +5,39 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; public interface CMSObjectIdentifiers { + /** PKCS#7: 1.2.840.113549.1.7.1 */ static final ASN1ObjectIdentifier data = PKCSObjectIdentifiers.data; + /** PKCS#7: 1.2.840.113549.1.7.2 */ static final ASN1ObjectIdentifier signedData = PKCSObjectIdentifiers.signedData; + /** PKCS#7: 1.2.840.113549.1.7.3 */ static final ASN1ObjectIdentifier envelopedData = PKCSObjectIdentifiers.envelopedData; + /** PKCS#7: 1.2.840.113549.1.7.4 */ static final ASN1ObjectIdentifier signedAndEnvelopedData = PKCSObjectIdentifiers.signedAndEnvelopedData; + /** PKCS#7: 1.2.840.113549.1.7.5 */ static final ASN1ObjectIdentifier digestedData = PKCSObjectIdentifiers.digestedData; + /** PKCS#7: 1.2.840.113549.1.7.6 */ static final ASN1ObjectIdentifier encryptedData = PKCSObjectIdentifiers.encryptedData; + /** PKCS#9: 1.2.840.113549.1.9.16.1.2 -- smime ct authData */ static final ASN1ObjectIdentifier authenticatedData = PKCSObjectIdentifiers.id_ct_authData; + /** PKCS#9: 1.2.840.113549.1.9.16.1.9 -- smime ct compressedData */ static final ASN1ObjectIdentifier compressedData = PKCSObjectIdentifiers.id_ct_compressedData; + /** PKCS#9: 1.2.840.113549.1.9.16.1.23 -- smime ct authEnvelopedData */ static final ASN1ObjectIdentifier authEnvelopedData = PKCSObjectIdentifiers.id_ct_authEnvelopedData; + /** PKCS#9: 1.2.840.113549.1.9.16.1.31 -- smime ct timestampedData*/ static final ASN1ObjectIdentifier timestampedData = PKCSObjectIdentifiers.id_ct_timestampedData; /** * The other Revocation Info arc + * <p> + * <pre> * id-ri OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) - * dod(6) internet(1) security(5) mechanisms(5) pkix(7) ri(16) } + * dod(6) internet(1) security(5) mechanisms(5) pkix(7) ri(16) } + * </pre> */ static final ASN1ObjectIdentifier id_ri = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.16"); + /** 1.3.6.1.5.5.7.16.2 */ static final ASN1ObjectIdentifier id_ri_ocsp_response = id_ri.branch("2"); + /** 1.3.6.1.5.5.7.16.4 */ static final ASN1ObjectIdentifier id_ri_scvp = id_ri.branch("4"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java index 688ac58..1592c75 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java @@ -10,6 +10,22 @@ import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.BERSequence; import org.bouncycastle.asn1.BERTaggedObject; +/** + * <a href="http://tools.ietf.org/html/rfc5652#section-3">RFC 5652</a> ContentInfo, and + * <a href="http://tools.ietf.org/html/rfc5652#section-5.2">RFC 5652</a> EncapsulatedContentInfo objects. + * + * <pre> + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL + * } + * + * EncapsulatedContentInfo ::= SEQUENCE { + * eContentType ContentType, + * eContent [0] EXPLICIT OCTET STRING OPTIONAL + * } + * </pre> + */ public class ContentInfo extends ASN1Object // BEGIN android-removed @@ -19,6 +35,19 @@ public class ContentInfo private ASN1ObjectIdentifier contentType; private ASN1Encodable content; + /** + * Return an ContentInfo object from the given object. + * <p> + * Accepted inputs: + * <ul> + * <li> null → null + * <li> {@link ContentInfo} object + * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with ContentInfo structure inside + * </ul> + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ public static ContentInfo getInstance( Object obj) { @@ -86,12 +115,6 @@ public class ContentInfo /** * Produce an object suitable for an ASN1OutputStream. - * <pre> - * ContentInfo ::= SEQUENCE { - * contentType ContentType, - * content - * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } - * </pre> */ public ASN1Primitive toASN1Primitive() { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/GCMParameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/GCMParameters.java new file mode 100644 index 0000000..0f03c87 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/GCMParameters.java @@ -0,0 +1,102 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.util.Arrays; + +/** + * <a href="http://tools.ietf.org/html/rfc5084">RFC 5084</a>: GCMParameters object. + * <p> + * <pre> + GCMParameters ::= SEQUENCE { + aes-nonce OCTET STRING, -- recommended size is 12 octets + aes-ICVlen AES-GCM-ICVlen DEFAULT 12 } + * </pre> + */ +public class GCMParameters + extends ASN1Object +{ + private byte[] nonce; + private int icvLen; + + /** + * Return an GCMParameters object from the given object. + * <p> + * Accepted inputs: + * <ul> + * <li> null → null + * <li> {@link org.bouncycastle.asn1.cms.GCMParameters} object + * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(Object) ASN1Sequence} input formats with GCMParameters structure inside + * </ul> + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static GCMParameters getInstance( + Object obj) + { + if (obj instanceof GCMParameters) + { + return (GCMParameters)obj; + } + else if (obj != null) + { + return new GCMParameters(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private GCMParameters( + ASN1Sequence seq) + { + this.nonce = ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets(); + + if (seq.size() == 2) + { + this.icvLen = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().intValue(); + } + else + { + this.icvLen = 12; + } + } + + public GCMParameters( + byte[] nonce, + int icvLen) + { + this.nonce = Arrays.clone(nonce); + this.icvLen = icvLen; + } + + public byte[] getNonce() + { + return Arrays.clone(nonce); + } + + public int getIcvLen() + { + return icvLen; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new DEROctetString(nonce)); + + if (icvLen != 12) + { + v.add(new ASN1Integer(icvLen)); + } + + return new DERSequence(v); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java index ad0dbb1..d46cbfb 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java @@ -13,12 +13,37 @@ import org.bouncycastle.asn1.x509.Certificate; import org.bouncycastle.asn1.x509.X509CertificateStructure; import org.bouncycastle.asn1.x509.X509Name; +/** + * <a href="http://tools.ietf.org/html/rfc5652#section-10.2.4">RFC 5652</a>: IssuerAndSerialNumber object. + * <p> + * <pre> + * IssuerAndSerialNumber ::= SEQUENCE { + * issuer Name, + * serialNumber CertificateSerialNumber + * } + * + * CertificateSerialNumber ::= INTEGER -- See RFC 5280 + * </pre> + */ public class IssuerAndSerialNumber extends ASN1Object { private X500Name name; private ASN1Integer serialNumber; + /** + * Return an IssuerAndSerialNumber object from the given object. + * <p> + * Accepted inputs: + * <ul> + * <li> null → null + * <li> {@link IssuerAndSerialNumber} object + * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with IssuerAndSerialNumber structure inside + * </ul> + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ public static IssuerAndSerialNumber getInstance( Object obj) { @@ -36,7 +61,6 @@ public class IssuerAndSerialNumber /** * @deprecated use getInstance() method. - * @param seq */ public IssuerAndSerialNumber( ASN1Sequence seq) @@ -52,6 +76,9 @@ public class IssuerAndSerialNumber this.serialNumber = certificate.getSerialNumber(); } + /** + * @deprecated use constructor taking Certificate + */ public IssuerAndSerialNumber( X509CertificateStructure certificate) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java index fd2718a..8c7fcc2 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java @@ -16,7 +16,45 @@ import org.bouncycastle.asn1.BERTaggedObject; import org.bouncycastle.asn1.DERTaggedObject; /** - * a signed data object. + * <a href="http://tools.ietf.org/html/rfc5652#section-5.1">RFC 5652</a>: + * <p> + * A signed data object containing multitude of {@link SignerInfo}s. + * <pre> + * SignedData ::= SEQUENCE { + * version CMSVersion, + * digestAlgorithms DigestAlgorithmIdentifiers, + * encapContentInfo EncapsulatedContentInfo, + * certificates [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos + * } + * + * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier + * + * SignerInfos ::= SET OF SignerInfo + * </pre> + * <p> + * The version calculation uses following ruleset from RFC 3852 section 5.1: + * <pre> + * IF ((certificates is present) AND + * (any certificates with a type of other are present)) OR + * ((crls is present) AND + * (any crls with a type of other are present)) + * THEN version MUST be 5 + * ELSE + * IF (certificates is present) AND + * (any version 2 attribute certificates are present) + * THEN version MUST be 4 + * ELSE + * IF ((certificates is present) AND + * (any version 1 attribute certificates are present)) OR + * (any SignerInfo structures are version 3) OR + * (encapContentInfo eContentType is other than id-data) + * THEN version MUST be 3 + * ELSE version MUST be 1 + * </pre> + * <p> + * @todo Check possible update for this to RFC 5652 level */ public class SignedData extends ASN1Object @@ -35,6 +73,19 @@ public class SignedData private boolean certsBer; private boolean crlsBer; + /** + * Return a SignedData object from the given object. + * <p> + * Accepted inputs: + * <ul> + * <li> null → null + * <li> {@link SignedData} object + * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignedData structure inside + * </ul> + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ public static SignedData getInstance( Object o) { @@ -68,24 +119,6 @@ public class SignedData } - // RFC3852, section 5.1: - // IF ((certificates is present) AND - // (any certificates with a type of other are present)) OR - // ((crls is present) AND - // (any crls with a type of other are present)) - // THEN version MUST be 5 - // ELSE - // IF (certificates is present) AND - // (any version 2 attribute certificates are present) - // THEN version MUST be 4 - // ELSE - // IF ((certificates is present) AND - // (any version 1 attribute certificates are present)) OR - // (any SignerInfo structures are version 3) OR - // (encapContentInfo eContentType is other than id-data) - // THEN version MUST be 3 - // ELSE version MUST be 1 - // private ASN1Integer calculateVersion( ASN1ObjectIdentifier contentOid, ASN1Set certs, @@ -257,16 +290,6 @@ public class SignedData /** * Produce an object suitable for an ASN1OutputStream. - * <pre> - * SignedData ::= SEQUENCE { - * version CMSVersion, - * digestAlgorithms DigestAlgorithmIdentifiers, - * encapContentInfo EncapsulatedContentInfo, - * certificates [0] IMPLICIT CertificateSet OPTIONAL, - * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, - * signerInfos SignerInfos - * } - * </pre> */ public ASN1Primitive toASN1Primitive() { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java index 37b6b31..2543eb1 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java @@ -8,6 +8,21 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERTaggedObject; +/** + * <a href="http://tools.ietf.org/html/rfc5652#section-5.3">RFC 5652</a>: + * Identify who signed the containing {@link SignerInfo} object. + * <p> + * The certificates referred to by this are at containing {@link SignedData} structure. + * <p> + * <pre> + * SignerIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier + * } + * + * SubjectKeyIdentifier ::= OCTET STRING + * </pre> + */ public class SignerIdentifier extends ASN1Object implements ASN1Choice @@ -33,7 +48,16 @@ public class SignerIdentifier } /** - * return a SignerIdentifier object from the given object. + * Return a SignerIdentifier object from the given object. + * <p> + * Accepted inputs: + * <ul> + * <li> null → null + * <li> {@link SignerIdentifier} object + * <li> {@link IssuerAndSerialNumber} object + * <li> {@link org.bouncycastle.asn1.ASN1OctetString#getInstance(java.lang.Object) ASN1OctetString} input formats with SignerIdentifier structure inside + * <li> {@link org.bouncycastle.asn1.ASN1Primitive ASN1Primitive} for SignerIdentifier constructor. + * </ul> * * @param o the object we want converted. * @exception IllegalArgumentException if the object cannot be converted. @@ -82,14 +106,6 @@ public class SignerIdentifier /** * Produce an object suitable for an ASN1OutputStream. - * <pre> - * SignerIdentifier ::= CHOICE { - * issuerAndSerialNumber IssuerAndSerialNumber, - * subjectKeyIdentifier [0] SubjectKeyIdentifier - * } - * - * SubjectKeyIdentifier ::= OCTET STRING - * </pre> */ public ASN1Primitive toASN1Primitive() { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java index 8aafd67..4209045 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java @@ -15,6 +15,63 @@ import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +/** + * <a href="http://tools.ietf.org/html/rfc5652#section-5.3">RFC 5652</a>: + * Signature container per Signer, see {@link SignerIdentifier}. + * <pre> + * PKCS#7: + * + * SignerInfo ::= SEQUENCE { + * version Version, + * sid SignerIdentifier, + * digestAlgorithm DigestAlgorithmIdentifier, + * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + * encryptedDigest EncryptedDigest, + * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL + * } + * + * EncryptedDigest ::= OCTET STRING + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * ----------------------------------------- + * + * RFC 5256: + * + * SignerInfo ::= SEQUENCE { + * version CMSVersion, + * sid SignerIdentifier, + * digestAlgorithm DigestAlgorithmIdentifier, + * signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, + * signatureAlgorithm SignatureAlgorithmIdentifier, + * signature SignatureValue, + * unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL + * } + * + * -- {@link SignerIdentifier} referenced certificates are at containing + * -- {@link SignedData} certificates element. + * + * SignerIdentifier ::= CHOICE { + * issuerAndSerialNumber {@link IssuerAndSerialNumber}, + * subjectKeyIdentifier [0] SubjectKeyIdentifier } + * + * -- See {@link Attributes} for generalized SET OF {@link Attribute} + * + * SignedAttributes ::= SET SIZE (1..MAX) OF Attribute + * UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * {@link Attribute} ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue } + * + * AttributeValue ::= ANY + * + * SignatureValue ::= OCTET STRING + * </pre> + */ public class SignerInfo extends ASN1Object { @@ -26,22 +83,44 @@ public class SignerInfo private ASN1OctetString encryptedDigest; private ASN1Set unauthenticatedAttributes; + /** + * Return a SignerInfo object from the given input + * <p> + * Accepted inputs: + * <ul> + * <li> null → null + * <li> {@link SignerInfo} object + * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignerInfo structure inside + * </ul> + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ public static SignerInfo getInstance( Object o) throws IllegalArgumentException { - if (o == null || o instanceof SignerInfo) + if (o instanceof SignerInfo) { return (SignerInfo)o; } - else if (o instanceof ASN1Sequence) + else if (o != null) { - return new SignerInfo((ASN1Sequence)o); + return new SignerInfo(ASN1Sequence.getInstance(o)); } - throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + return null; } + /** + * + * @param sid + * @param digAlgorithm CMS knows as 'digestAlgorithm' + * @param authenticatedAttributes CMS knows as 'signedAttrs' + * @param digEncryptionAlgorithm CMS knows as 'signatureAlgorithm' + * @param encryptedDigest CMS knows as 'signature' + * @param unauthenticatedAttributes CMS knows as 'unsignedAttrs' + */ public SignerInfo( SignerIdentifier sid, AlgorithmIdentifier digAlgorithm, @@ -67,6 +146,15 @@ public class SignerInfo this.unauthenticatedAttributes = unauthenticatedAttributes; } + /** + * + * @param sid + * @param digAlgorithm CMS knows as 'digestAlgorithm' + * @param authenticatedAttributes CMS knows as 'signedAttrs' + * @param digEncryptionAlgorithm CMS knows as 'signatureAlgorithm' + * @param encryptedDigest CMS knows as 'signature' + * @param unauthenticatedAttributes CMS knows as 'unsignedAttrs' + */ public SignerInfo( SignerIdentifier sid, AlgorithmIdentifier digAlgorithm, @@ -167,23 +255,6 @@ public class SignerInfo /** * Produce an object suitable for an ASN1OutputStream. - * <pre> - * SignerInfo ::= SEQUENCE { - * version Version, - * SignerIdentifier sid, - * digestAlgorithm DigestAlgorithmIdentifier, - * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, - * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, - * encryptedDigest EncryptedDigest, - * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL - * } - * - * EncryptedDigest ::= OCTET STRING - * - * DigestAlgorithmIdentifier ::= AlgorithmIdentifier - * - * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier - * </pre> */ public ASN1Primitive toASN1Primitive() { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java index 2087248..977fce6 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java @@ -12,6 +12,22 @@ import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERGeneralizedTime; import org.bouncycastle.asn1.DERUTCTime; +/** + * <a href="http://tools.ietf.org/html/rfc5652#section-11.3">RFC 5652</a>: + * Dual-mode timestamp format producing either UTCTIme or GeneralizedTime. + * <p> + * <pre> + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + * </pre> + * <p> + * This has a constructor using java.util.Date for input which generates + * a {@link org.bouncycastle.asn1.DERUTCTime DERUTCTime} object if the + * supplied datetime is in range 1950-01-01-00:00:00 UTC until 2049-12-31-23:59:60 UTC. + * If the datetime value is outside that range, the generated object will be + * {@link org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime}. + */ public class Time extends ASN1Object implements ASN1Choice @@ -25,6 +41,9 @@ public class Time return getInstance(obj.getObject()); } + /** + * @deprecated use getInstance() + */ public Time( ASN1Primitive time) { @@ -38,7 +57,7 @@ public class Time } /** - * creates a time object from a given date - if the date is between 1950 + * Create a time object from a given date - if the year is in between 1950 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime * is used. */ @@ -63,6 +82,20 @@ public class Time } } + /** + * Return a Time object from the given object. + * <p> + * Accepted inputs: + * <ul> + * <li> null → null + * <li> {@link Time} object + * <li> {@link org.bouncycastle.asn1.DERUTCTime DERUTCTime} object + * <li> {@link org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime} object + * </ul> + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ public static Time getInstance( Object obj) { @@ -82,6 +115,9 @@ public class Time throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); } + /** + * Get the date+tine as a String in full form century format. + */ public String getTime() { if (time instanceof DERUTCTime) @@ -94,6 +130,9 @@ public class Time } } + /** + * Get java.util.Date version of date+time. + */ public Date getDate() { try @@ -115,11 +154,6 @@ public class Time /** * Produce an object suitable for an ASN1OutputStream. - * <pre> - * Time ::= CHOICE { - * utcTime UTCTime, - * generalTime GeneralizedTime } - * </pre> */ public ASN1Primitive toASN1Primitive() { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java index bef8620..77416dc 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java @@ -2,54 +2,109 @@ package org.bouncycastle.asn1.eac; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +/** + * German Federal Office for Information Security + * (Bundesamt für Sicherheit in der Informationstechnik) + * <a href="http://www.bsi.bund.de/">http://www.bsi.bund.de/</a> + * <p> + * <a href="https://www.bsi.bund.de/EN/Publications/TechnicalGuidelines/TR03110/BSITR03110.html">BSI TR-03110</a> + * Technical Guideline Advanced Security Mechanisms for Machine Readable Travel Documents + * <p> + * <a href="https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03110/TR-03110_v2.1_P3pdf.pdf?__blob=publicationFile">Technical Guideline TR-03110-3</a> + * Advanced Security Mechanisms for Machine Readable Travel Documents; + * Part 3: Common Specifications. + */ + public interface EACObjectIdentifiers { - // bsi-de OBJECT IDENTIFIER ::= { - // itu-t(0) identified-organization(4) etsi(0) - // reserved(127) etsi-identified-organization(0) 7 - // } + /** + * <pre> + * bsi-de OBJECT IDENTIFIER ::= { + * itu-t(0) identified-organization(4) etsi(0) + * reserved(127) etsi-identified-organization(0) 7 + * } + * </pre> + * OID: 0.4.0.127.0.7 + */ static final ASN1ObjectIdentifier bsi_de = new ASN1ObjectIdentifier("0.4.0.127.0.7"); - // id-PK OBJECT IDENTIFIER ::= { - // bsi-de protocols(2) smartcard(2) 1 - // } - static final ASN1ObjectIdentifier id_PK = bsi_de.branch("2.2.1"); + /** + * <pre> + * id-PK OBJECT IDENTIFIER ::= { + * bsi-de protocols(2) smartcard(2) 1 + * } + * </pre> + * OID: 0.4.0.127.0.7.2.2.1 + */ + static final ASN1ObjectIdentifier id_PK = bsi_de.branch("2.2.1"); - static final ASN1ObjectIdentifier id_PK_DH = id_PK.branch("1"); + /** OID: 0.4.0.127.0.7.2.2.1.1 */ + static final ASN1ObjectIdentifier id_PK_DH = id_PK.branch("1"); + /** OID: 0.4.0.127.0.7.2.2.1.2 */ static final ASN1ObjectIdentifier id_PK_ECDH = id_PK.branch("2"); - // id-CA OBJECT IDENTIFIER ::= { - // bsi-de protocols(2) smartcard(2) 3 - // } - static final ASN1ObjectIdentifier id_CA = bsi_de.branch("2.2.3"); - static final ASN1ObjectIdentifier id_CA_DH = id_CA.branch("1"); - static final ASN1ObjectIdentifier id_CA_DH_3DES_CBC_CBC = id_CA_DH.branch("1"); - static final ASN1ObjectIdentifier id_CA_ECDH = id_CA.branch("2"); + /** + * <pre> + * id-CA OBJECT IDENTIFIER ::= { + * bsi-de protocols(2) smartcard(2) 3 + * } + * </pre> + * OID: 0.4.0.127.0.7.2.2.3 + */ + static final ASN1ObjectIdentifier id_CA = bsi_de.branch("2.2.3"); + /** OID: 0.4.0.127.0.7.2.2.3.1 */ + static final ASN1ObjectIdentifier id_CA_DH = id_CA.branch("1"); + /** OID: 0.4.0.127.0.7.2.2.3.1.1 */ + static final ASN1ObjectIdentifier id_CA_DH_3DES_CBC_CBC = id_CA_DH.branch("1"); + /** OID: 0.4.0.127.0.7.2.2.3.2 */ + static final ASN1ObjectIdentifier id_CA_ECDH = id_CA.branch("2"); + /** OID: 0.4.0.127.0.7.2.2.3.2.1 */ static final ASN1ObjectIdentifier id_CA_ECDH_3DES_CBC_CBC = id_CA_ECDH.branch("1"); - // - // id-TA OBJECT IDENTIFIER ::= { - // bsi-de protocols(2) smartcard(2) 2 - // } + /** + * <pre> + * id-TA OBJECT IDENTIFIER ::= { + * bsi-de protocols(2) smartcard(2) 2 + * } + * </pre> + * OID: 0.4.0.127.0.7.2.2.2 + */ static final ASN1ObjectIdentifier id_TA = bsi_de.branch("2.2.2"); - static final ASN1ObjectIdentifier id_TA_RSA = id_TA.branch("1"); - static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_1 = id_TA_RSA .branch("1"); + /** OID: 0.4.0.127.0.7.2.2.2.1 */ + static final ASN1ObjectIdentifier id_TA_RSA = id_TA.branch("1"); + /** OID: 0.4.0.127.0.7.2.2.2.1.1 */ + static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_1 = id_TA_RSA.branch("1"); + /** OID: 0.4.0.127.0.7.2.2.2.1.2 */ static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_256 = id_TA_RSA.branch("2"); - static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_1 = id_TA_RSA.branch("3"); - static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_256 = id_TA_RSA.branch("4"); + /** OID: 0.4.0.127.0.7.2.2.2.1.3 */ + static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_1 = id_TA_RSA.branch("3"); + /** OID: 0.4.0.127.0.7.2.2.2.1.4 */ + static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_256 = id_TA_RSA.branch("4"); + /** OID: 0.4.0.127.0.7.2.2.2.1.5 */ static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_512 = id_TA_RSA.branch("5"); - static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_512 = id_TA_RSA.branch("6"); - static final ASN1ObjectIdentifier id_TA_ECDSA = id_TA.branch("2"); - static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_1 = id_TA_ECDSA.branch("1"); - static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_224 = id_TA_ECDSA.branch("2"); - static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_256 = id_TA_ECDSA.branch("3"); - static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_384 = id_TA_ECDSA.branch("4"); - static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_512 = id_TA_ECDSA.branch("5"); + /** OID: 0.4.0.127.0.7.2.2.2.1.6 */ + static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_512 = id_TA_RSA.branch("6"); + /** OID: 0.4.0.127.0.7.2.2.2.2 */ + static final ASN1ObjectIdentifier id_TA_ECDSA = id_TA.branch("2"); + /** OID: 0.4.0.127.0.7.2.2.2.2.1 */ + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_1 = id_TA_ECDSA.branch("1"); + /** OID: 0.4.0.127.0.7.2.2.2.2.2 */ + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_224 = id_TA_ECDSA.branch("2"); + /** OID: 0.4.0.127.0.7.2.2.2.2.3 */ + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_256 = id_TA_ECDSA.branch("3"); + /** OID: 0.4.0.127.0.7.2.2.2.2.4 */ + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_384 = id_TA_ECDSA.branch("4"); + /** OID: 0.4.0.127.0.7.2.2.2.2.5 */ + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_512 = id_TA_ECDSA.branch("5"); /** + * <pre> * id-EAC-ePassport OBJECT IDENTIFIER ::= { - * bsi-de applications(3) mrtd(1) roles(2) 1} + * bsi-de applications(3) mrtd(1) roles(2) 1 + * } + * </pre> + * OID: 0.4.0.127.0.7.3.1.2.1 */ static final ASN1ObjectIdentifier id_EAC_ePassport = bsi_de.branch("3.1.2.1"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java index e9ab8d6..5bfdbab 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java @@ -2,19 +2,59 @@ package org.bouncycastle.asn1.iana; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +/** + * IANA: + * { iso(1) identifier-organization(3) dod(6) internet(1) } == IETF defined things + */ public interface IANAObjectIdentifiers { + + /** { iso(1) identifier-organization(3) dod(6) internet(1) } == IETF defined things */ + static final ASN1ObjectIdentifier internet = new ASN1ObjectIdentifier("1.3.6.1"); + /** 1.3.6.1.1: Internet directory: X.500 */ + static final ASN1ObjectIdentifier directory = internet.branch("1"); + /** 1.3.6.1.2: Internet management */ + static final ASN1ObjectIdentifier mgmt = internet.branch("2"); + /** 1.3.6.1.3: */ + static final ASN1ObjectIdentifier experimental = internet.branch("3"); + /** 1.3.6.1.4: */ + static final ASN1ObjectIdentifier _private = internet.branch("4"); + /** 1.3.6.1.5: Security services */ + static final ASN1ObjectIdentifier security = internet.branch("5"); + /** 1.3.6.1.6: SNMPv2 -- never really used */ + static final ASN1ObjectIdentifier SNMPv2 = internet.branch("6"); + /** 1.3.6.1.7: mail -- never really used */ + static final ASN1ObjectIdentifier mail = internet.branch("7"); + + // id-SHA1 OBJECT IDENTIFIER ::= // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)} // - static final ASN1ObjectIdentifier isakmpOakley = new ASN1ObjectIdentifier("1.3.6.1.5.5.8.1"); - static final ASN1ObjectIdentifier hmacMD5 = new ASN1ObjectIdentifier(isakmpOakley + ".1"); - static final ASN1ObjectIdentifier hmacSHA1 = new ASN1ObjectIdentifier(isakmpOakley + ".2"); + /** IANA security mechanisms; 1.3.6.1.5.5 */ + static final ASN1ObjectIdentifier security_mechanisms = security.branch("5"); + /** IANA security nametypes; 1.3.6.1.5.6 */ + static final ASN1ObjectIdentifier security_nametypes = security.branch("6"); + + /** PKIX base OID: 1.3.6.1.5.6.6 */ + static final ASN1ObjectIdentifier pkix = security_mechanisms.branch("6"); + + + /** IPSEC base OID: 1.3.6.1.5.5.8 */ + static final ASN1ObjectIdentifier ipsec = security_mechanisms.branch("8"); + /** IPSEC ISAKMP-Oakley OID: 1.3.6.1.5.5.8.1 */ + static final ASN1ObjectIdentifier isakmpOakley = ipsec.branch("1"); + + /** IPSEC ISAKMP-Oakley hmacMD5 OID: 1.3.6.1.5.5.8.1.1 */ + static final ASN1ObjectIdentifier hmacMD5 = isakmpOakley.branch("1"); + /** IPSEC ISAKMP-Oakley hmacSHA1 OID: 1.3.6.1.5.5.8.1.2 */ + static final ASN1ObjectIdentifier hmacSHA1 = isakmpOakley.branch("2"); - static final ASN1ObjectIdentifier hmacTIGER = new ASN1ObjectIdentifier(isakmpOakley + ".3"); + /** IPSEC ISAKMP-Oakley hmacTIGER OID: 1.3.6.1.5.5.8.1.3 */ + static final ASN1ObjectIdentifier hmacTIGER = isakmpOakley.branch("3"); - static final ASN1ObjectIdentifier hmacRIPEMD160 = new ASN1ObjectIdentifier(isakmpOakley + ".4"); + /** IPSEC ISAKMP-Oakley hmacRIPEMD160 OID: 1.3.6.1.5.5.8.1.4 */ + static final ASN1ObjectIdentifier hmacRIPEMD160 = isakmpOakley.branch("4"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java index bc2ac8d..6b75fde 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java @@ -2,11 +2,16 @@ package org.bouncycastle.asn1.isismtt; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +/** + * ISISMT -- Industrial Signature Interoperability Specification + */ public interface ISISMTTObjectIdentifiers { + /** 1.3.36.8 */ static final ASN1ObjectIdentifier id_isismtt = new ASN1ObjectIdentifier("1.3.36.8"); + /** 1.3.36.8.1 */ static final ASN1ObjectIdentifier id_isismtt_cp = id_isismtt.branch("1"); /** @@ -15,29 +20,37 @@ public interface ISISMTTObjectIdentifiers * Parliament and of the Council of 13 December 1999 on a Community * Framework for Electronic Signatures, which additionally conforms the * special requirements of the SigG and has been issued by an accredited CA. + * <p> + * 1.3.36.8.1.1 */ + static final ASN1ObjectIdentifier id_isismtt_cp_accredited = id_isismtt_cp.branch("1"); + /** 1.3.36.8.3 */ static final ASN1ObjectIdentifier id_isismtt_at = id_isismtt.branch("3"); /** * Certificate extensionDate of certificate generation - * * <pre> - * DateOfCertGenSyntax ::= GeneralizedTime + * DateOfCertGenSyntax ::= GeneralizedTime * </pre> + * OID: 1.3.36.8.3.1 */ static final ASN1ObjectIdentifier id_isismtt_at_dateOfCertGen = id_isismtt_at.branch("1"); /** * Attribute to indicate that the certificate holder may sign in the name of * a third person. May also be used as extension in a certificate. + * <p> + * OID: 1.3.36.8.3.2 */ static final ASN1ObjectIdentifier id_isismtt_at_procuration = id_isismtt_at.branch("2"); /** * Attribute to indicate admissions to certain professions. May be used as * attribute in attribute certificate or as extension in a certificate + * <p> + * OID: 1.3.36.8.3.3 */ static final ASN1ObjectIdentifier id_isismtt_at_admission = id_isismtt_at.branch("3"); @@ -47,33 +60,37 @@ public interface ISISMTTObjectIdentifiers * MonetaryLimit since January 1, 2004. For the sake of backward * compatibility with certificates already in use, SigG conforming * components MUST support MonetaryLimit (as well as QcEuLimitValue). + * <p> + * OID: 1.3.36.8.3.4 */ static final ASN1ObjectIdentifier id_isismtt_at_monetaryLimit = id_isismtt_at.branch("4"); /** * A declaration of majority. May be used as attribute in attribute * certificate or as extension in a certificate + * <p> + * OID: 1.3.36.8.3.5 */ static final ASN1ObjectIdentifier id_isismtt_at_declarationOfMajority = id_isismtt_at.branch("5"); /** - * * Serial number of the smart card containing the corresponding private key - * * <pre> - * ICCSNSyntax ::= OCTET STRING (SIZE(8..20)) + * ICCSNSyntax ::= OCTET STRING (SIZE(8..20)) * </pre> + * <p> + * OID: 1.3.36.8.3.6 */ static final ASN1ObjectIdentifier id_isismtt_at_iCCSN = id_isismtt_at.branch("6"); /** - * * Reference for a file of a smartcard that stores the public key of this - * certificate and that is used as �security anchor�. - * + * certificate and that is used as "security anchor". * <pre> - * PKReferenceSyntax ::= OCTET STRING (SIZE(20)) + * PKReferenceSyntax ::= OCTET STRING (SIZE(20)) * </pre> + * <p> + * OID: 1.3.36.8.3.7 */ static final ASN1ObjectIdentifier id_isismtt_at_PKReference = id_isismtt_at.branch("7"); @@ -81,28 +98,28 @@ public interface ISISMTTObjectIdentifiers * Some other restriction regarding the usage of this certificate. May be * used as attribute in attribute certificate or as extension in a * certificate. - * * <pre> - * RestrictionSyntax ::= DirectoryString (SIZE(1..1024)) + * RestrictionSyntax ::= DirectoryString (SIZE(1..1024)) * </pre> + * <p> + * OID: 1.3.36.8.3.8 * * @see org.bouncycastle.asn1.isismtt.x509.Restriction */ static final ASN1ObjectIdentifier id_isismtt_at_restriction = id_isismtt_at.branch("8"); /** - * * (Single)Request extension: Clients may include this extension in a * (single) Request to request the responder to send the certificate in the * response message along with the status information. Besides the LDAP * service, this extension provides another mechanism for the distribution * of certificates, which MAY optionally be provided by certificate * repositories. - * * <pre> - * RetrieveIfAllowed ::= BOOLEAN - * + * RetrieveIfAllowed ::= BOOLEAN * </pre> + * <p> + * OID: 1.3.36.8.3.9 */ static final ASN1ObjectIdentifier id_isismtt_at_retrieveIfAllowed = id_isismtt_at.branch("9"); @@ -110,6 +127,8 @@ public interface ISISMTTObjectIdentifiers * SingleOCSPResponse extension: The certificate requested by the client by * inserting the RetrieveIfAllowed extension in the request, will be * returned in this extension. + * <p> + * OID: 1.3.36.8.3.10 * * @see org.bouncycastle.asn1.isismtt.ocsp.RequestedCertificate */ @@ -117,6 +136,8 @@ public interface ISISMTTObjectIdentifiers /** * Base ObjectIdentifier for naming authorities + * <p> + * OID: 1.3.36.8.3.11 */ static final ASN1ObjectIdentifier id_isismtt_at_namingAuthorities = id_isismtt_at.branch("11"); @@ -127,13 +148,17 @@ public interface ISISMTTObjectIdentifiers * this extension in the responses. * * <pre> - * CertInDirSince ::= GeneralizedTime + * CertInDirSince ::= GeneralizedTime * </pre> + * <p> + * OID: 1.3.36.8.3.12 */ static final ASN1ObjectIdentifier id_isismtt_at_certInDirSince = id_isismtt_at.branch("12"); /** * Hash of a certificate in OCSP. + * <p> + * OID: 1.3.36.8.3.13 * * @see org.bouncycastle.asn1.isismtt.ocsp.CertHash */ @@ -141,11 +166,13 @@ public interface ISISMTTObjectIdentifiers /** * <pre> - * NameAtBirth ::= DirectoryString(SIZE(1..64) + * NameAtBirth ::= DirectoryString(SIZE(1..64) * </pre> * * Used in * {@link org.bouncycastle.asn1.x509.SubjectDirectoryAttributes SubjectDirectoryAttributes} + * <p> + * OID: 1.3.36.8.3.14 */ static final ASN1ObjectIdentifier id_isismtt_at_nameAtBirth = id_isismtt_at.branch("14"); @@ -155,8 +182,10 @@ public interface ISISMTTObjectIdentifiers * extension in a certificate. * * <pre> - * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048)) + * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048)) * </pre> + * <p> + * OID: 1.3.36.8.3.15 * * @see org.bouncycastle.asn1.isismtt.x509.AdditionalInformationSyntax */ @@ -171,10 +200,11 @@ public interface ISISMTTObjectIdentifiers * PKC as base certificate) contains some attribute that restricts the * usability of the PKC too. Attribute certificates with restricting content * MUST always be included in the signed document. - * * <pre> - * LiabilityLimitationFlagSyntax ::= BOOLEAN + * LiabilityLimitationFlagSyntax ::= BOOLEAN * </pre> + * <p> + * OID: 0.2.262.1.10.12.0 */ static final ASN1ObjectIdentifier id_isismtt_at_liabilityLimitationFlag = new ASN1ObjectIdentifier("0.2.262.1.10.12.0"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java index 73e0c58..73575f1 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java @@ -2,8 +2,30 @@ package org.bouncycastle.asn1.kisa; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +/** + * Korea Information Security Agency (KISA) + * ({iso(1) member-body(2) kr(410) kisa(200004)}) + * <p> + * See <a href="http://tools.ietf.org/html/rfc4010">RFC 4010</a> + * Use of the SEED Encryption Algorithm + * in Cryptographic Message Syntax (CMS), + * and <a href="http://tools.ietf.org/html/rfc4269">RFC 4269</a> + * The SEED Encryption Algorithm + */ public interface KISAObjectIdentifiers { - public static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier("1.2.410.200004.1.4"); - public static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1"); + /** RFC 4010, 4269: id-seedCBC; OID 1.2.410.200004.1.4 */ + static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier("1.2.410.200004.1.4"); + + /** RFC 4269: id-seedMAC; OID 1.2.410.200004.1.7 */ + static final ASN1ObjectIdentifier id_seedMAC = new ASN1ObjectIdentifier("1.2.410.200004.1.7"); + + /** RFC 4269: pbeWithSHA1AndSEED-CBC; OID 1.2.410.200004.1.15 */ + static final ASN1ObjectIdentifier pbeWithSHA1AndSEED_CBC = new ASN1ObjectIdentifier("1.2.410.200004.1.15"); + + /** RFC 4010: id-npki-app-cmsSeed-wrap; OID 1.2.410.200004.7.1.1.1 */ + static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1"); + + /** RFC 4010: SeedEncryptionAlgorithmInCMS; OID 1.2.840.113549.1.9.16.0.24 */ + static final ASN1ObjectIdentifier id_mod_cms_seed = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.0.24"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java index debf268..6aff988 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java @@ -8,40 +8,52 @@ 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"); // // 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"); - // - // CZAG - country, zip, age, and gender - // + /** Verisign CZAG (Country,Zip,Age,Gender) Extension OID: 2.16.840.1.113733.1.6.3 */ static final ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3"); - // D&B D-U-N-S number + /** 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"); // // 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"); // // 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"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java index afa93c4..e3613c6 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java @@ -2,59 +2,95 @@ package org.bouncycastle.asn1.nist; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +/** + * + * NIST: + * iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3) + */ public interface NISTObjectIdentifiers { // - // NIST - // iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3) - - // // nistalgorithms(4) // + /** 2.16.840.1.101.3.4 -- algorithms */ static final ASN1ObjectIdentifier nistAlgorithm = new ASN1ObjectIdentifier("2.16.840.1.101.3.4"); + /** 2.16.840.1.101.3.4.2 */ static final ASN1ObjectIdentifier hashAlgs = nistAlgorithm.branch("2"); + /** 2.16.840.1.101.3.4.2.1 */ static final ASN1ObjectIdentifier id_sha256 = hashAlgs.branch("1"); + /** 2.16.840.1.101.3.4.2.2 */ static final ASN1ObjectIdentifier id_sha384 = hashAlgs.branch("2"); + /** 2.16.840.1.101.3.4.2.3 */ static final ASN1ObjectIdentifier id_sha512 = hashAlgs.branch("3"); + /** 2.16.840.1.101.3.4.2.4 */ static final ASN1ObjectIdentifier id_sha224 = hashAlgs.branch("4"); + /** 2.16.840.1.101.3.4.2.5 */ static final ASN1ObjectIdentifier id_sha512_224 = hashAlgs.branch("5"); + /** 2.16.840.1.101.3.4.2.6 */ static final ASN1ObjectIdentifier id_sha512_256 = hashAlgs.branch("6"); - static final ASN1ObjectIdentifier aes = nistAlgorithm.branch("1"); + /** 2.16.840.1.101.3.4.1 */ + static final ASN1ObjectIdentifier aes = nistAlgorithm.branch("1"); + /** 2.16.840.1.101.3.4.1.1 */ static final ASN1ObjectIdentifier id_aes128_ECB = aes.branch("1"); + /** 2.16.840.1.101.3.4.1.2 */ static final ASN1ObjectIdentifier id_aes128_CBC = aes.branch("2"); + /** 2.16.840.1.101.3.4.1.3 */ static final ASN1ObjectIdentifier id_aes128_OFB = aes.branch("3"); + /** 2.16.840.1.101.3.4.1.4 */ static final ASN1ObjectIdentifier id_aes128_CFB = aes.branch("4"); + /** 2.16.840.1.101.3.4.1.5 */ static final ASN1ObjectIdentifier id_aes128_wrap = aes.branch("5"); + /** 2.16.840.1.101.3.4.1.6 */ static final ASN1ObjectIdentifier id_aes128_GCM = aes.branch("6"); + /** 2.16.840.1.101.3.4.1.7 */ static final ASN1ObjectIdentifier id_aes128_CCM = aes.branch("7"); + /** 2.16.840.1.101.3.4.1.21 */ static final ASN1ObjectIdentifier id_aes192_ECB = aes.branch("21"); + /** 2.16.840.1.101.3.4.1.22 */ static final ASN1ObjectIdentifier id_aes192_CBC = aes.branch("22"); + /** 2.16.840.1.101.3.4.1.23 */ static final ASN1ObjectIdentifier id_aes192_OFB = aes.branch("23"); + /** 2.16.840.1.101.3.4.1.24 */ static final ASN1ObjectIdentifier id_aes192_CFB = aes.branch("24"); + /** 2.16.840.1.101.3.4.1.25 */ static final ASN1ObjectIdentifier id_aes192_wrap = aes.branch("25"); + /** 2.16.840.1.101.3.4.1.26 */ static final ASN1ObjectIdentifier id_aes192_GCM = aes.branch("26"); + /** 2.16.840.1.101.3.4.1.27 */ static final ASN1ObjectIdentifier id_aes192_CCM = aes.branch("27"); + /** 2.16.840.1.101.3.4.1.41 */ static final ASN1ObjectIdentifier id_aes256_ECB = aes.branch("41"); + /** 2.16.840.1.101.3.4.1.42 */ static final ASN1ObjectIdentifier id_aes256_CBC = aes.branch("42"); + /** 2.16.840.1.101.3.4.1.43 */ static final ASN1ObjectIdentifier id_aes256_OFB = aes.branch("43"); + /** 2.16.840.1.101.3.4.1.44 */ static final ASN1ObjectIdentifier id_aes256_CFB = aes.branch("44"); + /** 2.16.840.1.101.3.4.1.45 */ static final ASN1ObjectIdentifier id_aes256_wrap = aes.branch("45"); + /** 2.16.840.1.101.3.4.1.46 */ static final ASN1ObjectIdentifier id_aes256_GCM = aes.branch("46"); + /** 2.16.840.1.101.3.4.1.47 */ static final ASN1ObjectIdentifier id_aes256_CCM = aes.branch("47"); // // signatures // + /** 2.16.840.1.101.3.4.3 */ static final ASN1ObjectIdentifier id_dsa_with_sha2 = nistAlgorithm.branch("3"); + /** 2.16.840.1.101.3.4.3.1 */ static final ASN1ObjectIdentifier dsa_with_sha224 = id_dsa_with_sha2.branch("1"); + /** 2.16.840.1.101.3.4.3.2 */ static final ASN1ObjectIdentifier dsa_with_sha256 = id_dsa_with_sha2.branch("2"); + /** 2.16.840.1.101.3.4.3.3 */ static final ASN1ObjectIdentifier dsa_with_sha384 = id_dsa_with_sha2.branch("3"); + /** 2.16.840.1.101.3.4.3.4 */ static final ASN1ObjectIdentifier dsa_with_sha512 = id_dsa_with_sha2.branch("4"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java index 2e4132a..fa32068 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java @@ -3,15 +3,23 @@ package org.bouncycastle.asn1.ntt; import org.bouncycastle.asn1.ASN1ObjectIdentifier; /** - * From RFC 3657 + * From <a href="http://tools.ietf.org/html/rfc3657">RFC 3657</a> + * Use of the Camellia Encryption Algorithm + * in Cryptographic Message Syntax (CMS) */ public interface NTTObjectIdentifiers { - public static final ASN1ObjectIdentifier id_camellia128_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.2"); - public static final ASN1ObjectIdentifier id_camellia192_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.3"); - public static final ASN1ObjectIdentifier id_camellia256_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.4"); + /** id-camellia128-cbc; OID 1.2.392.200011.61.1.1.1.2 */ + static final ASN1ObjectIdentifier id_camellia128_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.2"); + /** id-camellia192-cbc; OID 1.2.392.200011.61.1.1.1.3 */ + static final ASN1ObjectIdentifier id_camellia192_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.3"); + /** id-camellia256-cbc; OID 1.2.392.200011.61.1.1.1.4 */ + static final ASN1ObjectIdentifier id_camellia256_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.4"); - public static final ASN1ObjectIdentifier id_camellia128_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.2"); - public static final ASN1ObjectIdentifier id_camellia192_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.3"); - public static final ASN1ObjectIdentifier id_camellia256_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.4"); + /** id-camellia128-wrap; OID 1.2.392.200011.61.1.1.3.2 */ + static final ASN1ObjectIdentifier id_camellia128_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.2"); + /** id-camellia192-wrap; OID 1.2.392.200011.61.1.1.3.3 */ + static final ASN1ObjectIdentifier id_camellia192_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.3"); + /** id-camellia256-wrap; OID 1.2.392.200011.61.1.1.3.4 */ + static final ASN1ObjectIdentifier id_camellia256_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.4"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java index c8ce26b..c169c16 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java @@ -2,30 +2,49 @@ package org.bouncycastle.asn1.oiw; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +/** + * OIW organization's OIDs: + * <p> + * id-SHA1 OBJECT IDENTIFIER ::= + * {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } + */ public interface OIWObjectIdentifiers { - // id-SHA1 OBJECT IDENTIFIER ::= - // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // + /** OID: 1.3.14.3.2.2 */ static final ASN1ObjectIdentifier md4WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.2"); + /** OID: 1.3.14.3.2.3 */ static final ASN1ObjectIdentifier md5WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.3"); + /** OID: 1.3.14.3.2.4 */ static final ASN1ObjectIdentifier md4WithRSAEncryption = new ASN1ObjectIdentifier("1.3.14.3.2.4"); + /** OID: 1.3.14.3.2.6 */ static final ASN1ObjectIdentifier desECB = new ASN1ObjectIdentifier("1.3.14.3.2.6"); + /** OID: 1.3.14.3.2.7 */ static final ASN1ObjectIdentifier desCBC = new ASN1ObjectIdentifier("1.3.14.3.2.7"); + /** OID: 1.3.14.3.2.8 */ static final ASN1ObjectIdentifier desOFB = new ASN1ObjectIdentifier("1.3.14.3.2.8"); + /** OID: 1.3.14.3.2.9 */ static final ASN1ObjectIdentifier desCFB = new ASN1ObjectIdentifier("1.3.14.3.2.9"); + /** OID: 1.3.14.3.2.17 */ static final ASN1ObjectIdentifier desEDE = new ASN1ObjectIdentifier("1.3.14.3.2.17"); + /** OID: 1.3.14.3.2.26 */ static final ASN1ObjectIdentifier idSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26"); + /** OID: 1.3.14.3.2.27 */ static final ASN1ObjectIdentifier dsaWithSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.27"); + /** OID: 1.3.14.3.2.29 */ static final ASN1ObjectIdentifier sha1WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.29"); - // ElGamal Algorithm OBJECT IDENTIFIER ::= - // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 } - // + /** + * <pre> + * ElGamal Algorithm OBJECT IDENTIFIER ::= + * {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 } + * </pre> + * OID: 1.3.14.7.2.1.1 + */ static final ASN1ObjectIdentifier elGamalAlgorithm = new ASN1ObjectIdentifier("1.3.14.7.2.1.1"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java index 65c0fa8..92c4e8f 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java @@ -9,16 +9,39 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; - +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * <pre> + * PBKDF2-params ::= SEQUENCE { + * salt CHOICE { + * specified OCTET STRING, + * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} + * }, + * iterationCount INTEGER (1..MAX), + * keyLength INTEGER (1..MAX) OPTIONAL, + * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 } + * </pre> + */ public class PBKDF2Params extends ASN1Object { + private static final AlgorithmIdentifier algid_hmacWithSHA1 = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE); + private ASN1OctetString octStr; private ASN1Integer iterationCount; private ASN1Integer keyLength; - + private AlgorithmIdentifier prf; + + /** + * Create PBKDF2Params from the passed in object, + * + * @param obj either PBKDF2Params or an ASN2Sequence. + * @return a PBKDF2Params instance. + */ public static PBKDF2Params getInstance( Object obj) { @@ -34,7 +57,13 @@ public class PBKDF2Params return null; } - + + /** + * Create a PBKDF2Params with the specified salt, iteration count, and algid-hmacWithSHA1 for the prf. + * + * @param salt input salt. + * @param iterationCount input iteration count. + */ public PBKDF2Params( byte[] salt, int iterationCount) @@ -43,6 +72,13 @@ public class PBKDF2Params this.iterationCount = new ASN1Integer(iterationCount); } + /** + * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and algid-hmacWithSHA1 for the prf. + * + * @param salt input salt. + * @param iterationCount input iteration count. + * @param keyLength intended key length to be produced. + */ public PBKDF2Params( byte[] salt, int iterationCount, @@ -53,6 +89,42 @@ public class PBKDF2Params this.keyLength = new ASN1Integer(keyLength); } + /** + * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and a defined prf. + * + * @param salt input salt. + * @param iterationCount input iteration count. + * @param keyLength intended key length to be produced. + * @param prf the pseudo-random function to use. + */ + public PBKDF2Params( + byte[] salt, + int iterationCount, + int keyLength, + AlgorithmIdentifier prf) + { + this(salt, iterationCount); + + this.keyLength = new ASN1Integer(keyLength); + this.prf = prf; + } + + /** + * Create a PBKDF2Params with the specified salt, iteration count, and a defined prf. + * + * @param salt input salt. + * @param iterationCount input iteration count. + * @param prf the pseudo-random function to use. + */ + public PBKDF2Params( + byte[] salt, + int iterationCount, + AlgorithmIdentifier prf) + { + this(salt, iterationCount); + this.prf = prf; + } + private PBKDF2Params( ASN1Sequence seq) { @@ -63,24 +135,57 @@ public class PBKDF2Params if (e.hasMoreElements()) { - keyLength = (ASN1Integer)e.nextElement(); - } - else - { - keyLength = null; + Object o = e.nextElement(); + + if (o instanceof ASN1Integer) + { + keyLength = ASN1Integer.getInstance(o); + if (e.hasMoreElements()) + { + o = e.nextElement(); + } + else + { + o = null; + } + } + else + { + keyLength = null; + } + + if (o != null) + { + prf = AlgorithmIdentifier.getInstance(o); + } } } + /** + * Return the salt to use. + * + * @return the input salt. + */ public byte[] getSalt() { return octStr.getOctets(); } + /** + * Return the iteration count to use. + * + * @return the input iteration count. + */ public BigInteger getIterationCount() { return iterationCount.getValue(); } + /** + * Return the intended length in octets of the derived key. + * + * @return length in octets for derived key, if specified. + */ public BigInteger getKeyLength() { if (keyLength != null) @@ -91,6 +196,36 @@ public class PBKDF2Params return null; } + /** + * Return true if the PRF is the default (hmacWithSHA1) + * + * @return true if PRF is default, false otherwise. + */ + public boolean isDefaultPrf() + { + return prf == null || prf.equals(algid_hmacWithSHA1); + } + + /** + * Return the algId of the underlying pseudo random function to use. + * + * @return the prf algorithm identifier. + */ + public AlgorithmIdentifier getPrf() + { + if (prf != null) + { + return prf; + } + + return algid_hmacWithSHA1; + } + + /** + * Return an ASN.1 structure suitable for encoding. + * + * @return the object as an ASN.1 encodable structure. + */ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(); @@ -103,6 +238,11 @@ public class PBKDF2Params v.add(keyLength); } + if (prf != null && !prf.equals(algid_hmacWithSHA1)) + { + v.add(prf); + } + return new DERSequence(v); } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java index 37f94fe..82f1f94 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java @@ -2,73 +2,104 @@ package org.bouncycastle.asn1.pkcs; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +/** + * pkcs-1 OBJECT IDENTIFIER ::=<p> + * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } + * + */ public interface PKCSObjectIdentifiers { - // - // pkcs-1 OBJECT IDENTIFIER ::= { - // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } - // + /** PKCS#1: 1.2.840.113549.1.1 */ static final 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"); // BEGIN android-removed + // /** PKCS#1: 1.2.840.113549.1.1.2 */ // static final ASN1ObjectIdentifier md2WithRSAEncryption = pkcs_1.branch("2"); + // /** PKCS#1: 1.2.840.113549.1.1.3 */ // static final ASN1ObjectIdentifier md4WithRSAEncryption = pkcs_1.branch("3"); // END android-removed + /** PKCS#1: 1.2.840.113549.1.1.4 */ static final ASN1ObjectIdentifier md5WithRSAEncryption = pkcs_1.branch("4"); + /** PKCS#1: 1.2.840.113549.1.1.5 */ static final ASN1ObjectIdentifier sha1WithRSAEncryption = pkcs_1.branch("5"); + /** PKCS#1: 1.2.840.113549.1.1.6 */ static final 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"); + /** PKCS#1: 1.2.840.113549.1.1.8 */ static final 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"); + /** PKCS#1: 1.2.840.113549.1.1.10 */ static final 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"); + /** PKCS#1: 1.2.840.113549.1.1.12 */ static final ASN1ObjectIdentifier sha384WithRSAEncryption = pkcs_1.branch("12"); + /** PKCS#1: 1.2.840.113549.1.1.13 */ static final ASN1ObjectIdentifier sha512WithRSAEncryption = pkcs_1.branch("13"); + /** PKCS#1: 1.2.840.113549.1.1.14 */ static final ASN1ObjectIdentifier sha224WithRSAEncryption = pkcs_1.branch("14"); // // 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"); + /** PKCS#3: 1.2.840.113549.1.3.1 */ static final 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"); + /** PKCS#5: 1.2.840.113549.1.5.1 */ static final 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"); + /** PKCS#5: 1.2.840.113549.1.5.3 */ static final 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"); + /** PKCS#5: 1.2.840.113549.1.5.10 */ static final 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"); - + /** PKCS#5: 1.2.840.113549.1.5.13 */ static final 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"); // // 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"); + /** 1.2.840.113549.3.7 */ static final ASN1ObjectIdentifier des_EDE3_CBC = encryptionAlgorithm.branch("7"); + /** 1.2.840.113549.3.2 */ static final ASN1ObjectIdentifier RC2_CBC = encryptionAlgorithm.branch("2"); + /** 1.2.840.113549.3.4 */ static final 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"); // // md2 OBJECT IDENTIFIER ::= // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2} // // BEGIN android-removed + // /** 1.2.840.113549.2.2 */ // static final ASN1ObjectIdentifier md2 = digestAlgorithm.branch("2"); // END android-removed @@ -77,188 +108,289 @@ public interface PKCSObjectIdentifiers // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4} // // BEGIN android-removed - // static final ASN1ObjectIdentifier md4 = digestAlgorithm.branch("4"); + // /** 1.2.840.113549.2.4 */ + // static final ASN1ObjectIdentifier md4 = digestAlgorithm.branch("4"); // END android-removed // // md5 OBJECT IDENTIFIER ::= // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5} // - static final ASN1ObjectIdentifier md5 = digestAlgorithm.branch("5"); + /** 1.2.840.113549.2.5 */ + static final ASN1ObjectIdentifier md5 = digestAlgorithm.branch("5"); - static final ASN1ObjectIdentifier id_hmacWithSHA1 = digestAlgorithm.branch("7"); - static final ASN1ObjectIdentifier id_hmacWithSHA224 = digestAlgorithm.branch("8"); - static final ASN1ObjectIdentifier id_hmacWithSHA256 = digestAlgorithm.branch("9"); - static final ASN1ObjectIdentifier id_hmacWithSHA384 = digestAlgorithm.branch("10"); - static final ASN1ObjectIdentifier id_hmacWithSHA512 = digestAlgorithm.branch("11"); + /** 1.2.840.113549.2.7 */ + static final ASN1ObjectIdentifier id_hmacWithSHA1 = digestAlgorithm.branch("7"); + /** 1.2.840.113549.2.8 */ + static final ASN1ObjectIdentifier id_hmacWithSHA224 = digestAlgorithm.branch("8"); + /** 1.2.840.113549.2.9 */ + static final ASN1ObjectIdentifier id_hmacWithSHA256 = digestAlgorithm.branch("9"); + /** 1.2.840.113549.2.10 */ + static final ASN1ObjectIdentifier id_hmacWithSHA384 = digestAlgorithm.branch("10"); + /** 1.2.840.113549.2.11 */ + static final ASN1ObjectIdentifier id_hmacWithSHA512 = digestAlgorithm.branch("11"); // // pkcs-7 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 } // - static final String pkcs_7 = "1.2.840.113549.1.7"; - static final ASN1ObjectIdentifier data = new ASN1ObjectIdentifier(pkcs_7 + ".1"); - static final ASN1ObjectIdentifier signedData = new ASN1ObjectIdentifier(pkcs_7 + ".2"); - static final ASN1ObjectIdentifier envelopedData = new ASN1ObjectIdentifier(pkcs_7 + ".3"); - static final ASN1ObjectIdentifier signedAndEnvelopedData = new ASN1ObjectIdentifier(pkcs_7 + ".4"); - static final ASN1ObjectIdentifier digestedData = new ASN1ObjectIdentifier(pkcs_7 + ".5"); - static final ASN1ObjectIdentifier encryptedData = new ASN1ObjectIdentifier(pkcs_7 + ".6"); + /** pkcs#7: 1.2.840.113549.1.7 */ + static final ASN1ObjectIdentifier pkcs_7 = new ASN1ObjectIdentifier("1.2.840.113549.1.7"); + /** PKCS#7: 1.2.840.113549.1.7.1 */ + static final ASN1ObjectIdentifier data = new ASN1ObjectIdentifier("1.2.840.113549.1.7.1"); + /** PKCS#7: 1.2.840.113549.1.7.2 */ + static final ASN1ObjectIdentifier signedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.2"); + /** PKCS#7: 1.2.840.113549.1.7.3 */ + static final ASN1ObjectIdentifier envelopedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.3"); + /** PKCS#7: 1.2.840.113549.1.7.4 */ + static final ASN1ObjectIdentifier signedAndEnvelopedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.4"); + /** PKCS#7: 1.2.840.113549.1.7.5 */ + static final ASN1ObjectIdentifier digestedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.5"); + /** PKCS#7: 1.2.840.113549.1.7.76 */ + static final ASN1ObjectIdentifier encryptedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.6"); // // 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"); - static final ASN1ObjectIdentifier pkcs_9_at_emailAddress = pkcs_9.branch("1"); - static final ASN1ObjectIdentifier pkcs_9_at_unstructuredName = pkcs_9.branch("2"); - static final ASN1ObjectIdentifier pkcs_9_at_contentType = pkcs_9.branch("3"); - static final ASN1ObjectIdentifier pkcs_9_at_messageDigest = pkcs_9.branch("4"); - static final ASN1ObjectIdentifier pkcs_9_at_signingTime = pkcs_9.branch("5"); - static final ASN1ObjectIdentifier pkcs_9_at_counterSignature = pkcs_9.branch("6"); - static final ASN1ObjectIdentifier pkcs_9_at_challengePassword = pkcs_9.branch("7"); + /** PKCS#9: 1.2.840.113549.1.9.1 */ + static final ASN1ObjectIdentifier pkcs_9_at_emailAddress = pkcs_9.branch("1"); + /** PKCS#9: 1.2.840.113549.1.9.2 */ + static final ASN1ObjectIdentifier pkcs_9_at_unstructuredName = pkcs_9.branch("2"); + /** PKCS#9: 1.2.840.113549.1.9.3 */ + static final ASN1ObjectIdentifier pkcs_9_at_contentType = pkcs_9.branch("3"); + /** PKCS#9: 1.2.840.113549.1.9.4 */ + static final ASN1ObjectIdentifier pkcs_9_at_messageDigest = pkcs_9.branch("4"); + /** PKCS#9: 1.2.840.113549.1.9.5 */ + static final ASN1ObjectIdentifier pkcs_9_at_signingTime = pkcs_9.branch("5"); + /** PKCS#9: 1.2.840.113549.1.9.6 */ + static final ASN1ObjectIdentifier pkcs_9_at_counterSignature = pkcs_9.branch("6"); + /** PKCS#9: 1.2.840.113549.1.9.7 */ + static final ASN1ObjectIdentifier pkcs_9_at_challengePassword = pkcs_9.branch("7"); + /** PKCS#9: 1.2.840.113549.1.9.8 */ static final ASN1ObjectIdentifier pkcs_9_at_unstructuredAddress = pkcs_9.branch("8"); + /** PKCS#9: 1.2.840.113549.1.9.9 */ static final ASN1ObjectIdentifier pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9"); + /** PKCS#9: 1.2.840.113549.1.9.13 */ static final ASN1ObjectIdentifier pkcs_9_at_signingDescription = pkcs_9.branch("13"); - static final ASN1ObjectIdentifier pkcs_9_at_extensionRequest = pkcs_9.branch("14"); - static final ASN1ObjectIdentifier pkcs_9_at_smimeCapabilities = pkcs_9.branch("15"); - + /** PKCS#9: 1.2.840.113549.1.9.14 */ + static final ASN1ObjectIdentifier pkcs_9_at_extensionRequest = pkcs_9.branch("14"); + /** PKCS#9: 1.2.840.113549.1.9.15 */ + static final ASN1ObjectIdentifier pkcs_9_at_smimeCapabilities = pkcs_9.branch("15"); + /** PKCS#9: 1.2.840.113549.1.9.16 */ + static final ASN1ObjectIdentifier id_smime = pkcs_9.branch("16"); + + /** PKCS#9: 1.2.840.113549.1.9.20 */ static final ASN1ObjectIdentifier pkcs_9_at_friendlyName = pkcs_9.branch("20"); + /** PKCS#9: 1.2.840.113549.1.9.21 */ static final ASN1ObjectIdentifier pkcs_9_at_localKeyId = pkcs_9.branch("21"); - /** @deprecated use x509Certificate instead */ + /** PKCS#9: 1.2.840.113549.1.9.22.1 + * @deprecated use x509Certificate instead */ static final ASN1ObjectIdentifier x509certType = pkcs_9.branch("22.1"); + /** PKCS#9: 1.2.840.113549.1.9.22 */ static final ASN1ObjectIdentifier certTypes = pkcs_9.branch("22"); + /** PKCS#9: 1.2.840.113549.1.9.22.1 */ static final ASN1ObjectIdentifier x509Certificate = certTypes.branch("1"); + /** PKCS#9: 1.2.840.113549.1.9.22.2 */ static final ASN1ObjectIdentifier sdsiCertificate = certTypes.branch("2"); + /** PKCS#9: 1.2.840.113549.1.9.23 */ static final ASN1ObjectIdentifier crlTypes = pkcs_9.branch("23"); + /** PKCS#9: 1.2.840.113549.1.9.23.1 */ static final ASN1ObjectIdentifier x509Crl = crlTypes.branch("1"); - static final ASN1ObjectIdentifier id_alg_PWRI_KEK = pkcs_9.branch("16.3.9"); - // // 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"); + /** PKCS#9: 1.2.840.113549.1.9.15.2 -- smime capability */ static final 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"); // // 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"); + /** PKCS#9: 1.2.840.113549.1.9.16.1.2 -- smime ct authData */ static final 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"); + /** PKCS#9: 1.2.840.113549.1.9.16.1.9 -- smime ct compressedData */ static final 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"); + /** PKCS#9: 1.2.840.113549.1.9.16.1.31 -- smime ct timestampedData*/ static final 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"); + /** PKCS#9: 1.2.840.113549.1.9.16.3.9 */ + static final ASN1ObjectIdentifier id_alg_PWRI_KEK = id_alg.branch("9"); + // // 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"); - static final ASN1ObjectIdentifier id_cti_ets_proofOfOrigin = id_cti.branch("1"); - static final ASN1ObjectIdentifier id_cti_ets_proofOfReceipt = id_cti.branch("2"); + /** 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"); + /** 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"); + /** 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"); - static final ASN1ObjectIdentifier id_cti_ets_proofOfSender = id_cti.branch("4"); + /** 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"); + /** 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"); + /** 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"); // // 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.6.2.1 -- smime attribute receiptRequest */ static final ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1"); - static final ASN1ObjectIdentifier id_aa_contentHint = id_aa.branch("4"); // See RFC 2634 - static final ASN1ObjectIdentifier id_aa_msgSigDigest = id_aa.branch("5"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */ + 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"); /* * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11} * */ - static final ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch("11"); - static final ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch("12"); + /** 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.6.2.7 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */ static final 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 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_signatureTimeStampToken = id_aa.branch("14"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.15 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch("15"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.16 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch("16"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.17 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch("17"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.18 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_signerAttr = id_aa.branch("18"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.19 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch("19"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.20 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch("20"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.21 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch("21"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.22 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch("22"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.23 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch("23"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.24 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch("24"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.25 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch("25"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.26 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch("26"); + /** PKCS#9: 1.2.840.113549.1.9.16.6.2.27 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ static final ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch("27"); /** @deprecated use id_aa_ets_sigPolicyId instead */ - static final ASN1ObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId; + static final 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; /** @deprecated use id_aa_ets_signerLocation instead */ static final 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; + static final ASN1ObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert; - // - // id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) - // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)} - // + /** + * id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + * rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)}; <p> + * 1.2.840.113549.1.9.16.5 + */ final String id_spq = "1.2.840.113549.1.9.16.5"; - static final ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + ".1"); + /** SMIME SPQ URI: 1.2.840.113549.1.9.16.5.1 */ + static final 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"); // // 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"); + /** PKCS#12: 1.2.840.113549.1.12.10.1 */ static final 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"); + /** PKCS#12: 1.2.840.113549.1.12.10.1.2 */ static final ASN1ObjectIdentifier pkcs8ShroudedKeyBag = bagtypes.branch("2"); + /** PKCS#12: 1.2.840.113549.1.12.10.1.3 */ static final ASN1ObjectIdentifier certBag = bagtypes.branch("3"); + /** PKCS#12: 1.2.840.113549.1.12.10.1.4 */ static final ASN1ObjectIdentifier crlBag = bagtypes.branch("4"); + /** PKCS#12: 1.2.840.113549.1.12.10.1.5 */ static final ASN1ObjectIdentifier secretBag = bagtypes.branch("5"); + /** PKCS#12: 1.2.840.113549.1.12.10.1.6 */ static final ASN1ObjectIdentifier safeContentsBag = bagtypes.branch("6"); - static final ASN1ObjectIdentifier pkcs_12PbeIds = pkcs_12.branch("1"); + /** PKCS#12: 1.2.840.113549.1.12.1 */ + static final ASN1ObjectIdentifier pkcs_12PbeIds = pkcs_12.branch("1"); - static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1"); - static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC4 = pkcs_12PbeIds.branch("2"); + /** PKCS#12: 1.2.840.113549.1.12.1.1 */ + static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1"); + /** PKCS#12: 1.2.840.113549.1.12.1.2 */ + static final 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"); + /** PKCS#12: 1.2.840.113549.1.12.1.4 */ static final ASN1ObjectIdentifier pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4"); - static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch("5"); - static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); + /** PKCS#12: 1.2.840.113549.1.12.1.5 */ + static final 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"); /** + * PKCS#12: 1.2.840.113549.1.12.1.6 * @deprecated use pbeWithSHAAnd40BitRC2_CBC */ static final 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"); - static final 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.7 */ + static final ASN1ObjectIdentifier id_alg_CMSRC2wrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java index 515b515..e707fd1 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java @@ -57,7 +57,11 @@ public class RSAESOAEPparams this.maskGenAlgorithm = maskGenAlgorithm; this.pSourceAlgorithm = pSourceAlgorithm; } - + + /** + * @deprecated use getInstance() + * @param seq + */ public RSAESOAEPparams( ASN1Sequence seq) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java index 4bf6b2b..df2238a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java @@ -62,7 +62,7 @@ public class ECPrivateKey public ECPrivateKey( BigInteger key, - ASN1Object parameters) + ASN1Encodable parameters) { this(key, null, parameters); } @@ -70,7 +70,7 @@ public class ECPrivateKey public ECPrivateKey( BigInteger key, DERBitString publicKey, - ASN1Object parameters) + ASN1Encodable parameters) { byte[] bytes = BigIntegers.asUnsignedByteArray(key); diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java index 44c811b..50a7a63 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java @@ -15,6 +15,21 @@ import org.bouncycastle.util.encoders.Hex; public class SECNamedCurves { + private static ECCurve configureCurve(ECCurve curve) + { +// int coord = ECCurve.COORD_JACOBIAN_MODIFIED; +// +// if (curve.getCoordinateSystem() != coord && curve.supportsCoordinateSystem(coord)) +// { +// return curve.configure() +// .setCoordinateSystem(coord) +//// .setMultiplier(new WNafL2RMultiplier()) +// .create(); +// } + + return curve; + } + private static BigInteger fromHex( String hex) { @@ -36,7 +51,7 @@ public class SECNamedCurves BigInteger n = fromHex("DB7C2ABF62E35E7628DFAC6561C5"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "09487239995A5EE76B55F9C2F098")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -62,7 +77,7 @@ public class SECNamedCurves BigInteger n = fromHex("36DF0AAFD8B8D7597CA10520D04B"); BigInteger h = BigInteger.valueOf(4); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "4BA30AB5E892B4E1649DD0928643")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -88,7 +103,7 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFE0000000075A30D1B9038A115"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "161FF7528B899B2D0C28607CA52C5B86")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -114,7 +129,7 @@ public class SECNamedCurves BigInteger n = fromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3"); BigInteger h = BigInteger.valueOf(4); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "7B6AA5D85E572983E6FB32A7CDEBC140")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -140,7 +155,7 @@ public class SECNamedCurves BigInteger n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); // ECPoint G = curve.decodePoint(Hex.decode("02" // + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -166,7 +181,7 @@ public class SECNamedCurves BigInteger n = fromHex("0100000000000000000001F4C8F927AED3CA752257"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "4A96B5688EF573284664698968C38BB913CBFC82")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -192,7 +207,7 @@ public class SECNamedCurves BigInteger n = fromHex("0100000000000000000000351EE786A818F3A1A16B"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -218,7 +233,7 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -244,7 +259,7 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -270,7 +285,7 @@ public class SECNamedCurves BigInteger n = fromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -296,7 +311,7 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -322,7 +337,7 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -348,7 +363,7 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -374,7 +389,7 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -400,7 +415,8 @@ public class SECNamedCurves BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = new ECCurve.Fp(p, a, b); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -410,7 +426,7 @@ public class SECNamedCurves return new X9ECParameters(curve, G, n, h, S); } }; - + /* * sect113r1 */ @@ -427,7 +443,7 @@ public class SECNamedCurves BigInteger n = fromHex("0100000000000000D9CCEC8A39E56F"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "009D73616F35F4AB1407D73562C10F")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -454,7 +470,7 @@ public class SECNamedCurves BigInteger n = fromHex("010000000000000108789B2496AF93"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "01A57A6A7B26CA5EF52FCDB8164797")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -483,7 +499,7 @@ public class SECNamedCurves BigInteger n = fromHex("0400000000000000023123953A9464B54D"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "0081BAF91FDF9833C40F9C181343638399")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -512,7 +528,7 @@ public class SECNamedCurves BigInteger n = fromHex("0400000000000000016954A233049BA98F"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "0356DCD8F2F95031AD652D23951BB366A8")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -541,7 +557,7 @@ public class SECNamedCurves BigInteger n = fromHex("04000000000000000000020108A2E0CC0D99F8A5EF"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -570,7 +586,7 @@ public class SECNamedCurves BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "0369979697AB43897789566789567F787A7876A654")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -599,7 +615,7 @@ public class SECNamedCurves BigInteger n = fromHex("040000000000000000000292FE77E70C12A4234C33"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -626,7 +642,7 @@ public class SECNamedCurves BigInteger n = fromHex("01000000000000000000000000C7F34A778F443ACC920EBA49"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -653,7 +669,7 @@ public class SECNamedCurves BigInteger n = fromHex("010000000000000000000000015AAB561B005413CCD4EE99D5"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -680,7 +696,7 @@ public class SECNamedCurves BigInteger n = fromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF"); BigInteger h = BigInteger.valueOf(4); - ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -707,7 +723,7 @@ public class SECNamedCurves BigInteger n = fromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -734,7 +750,7 @@ public class SECNamedCurves BigInteger n = fromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5"); BigInteger h = BigInteger.valueOf(4); - ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -763,7 +779,7 @@ public class SECNamedCurves BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61"); BigInteger h = BigInteger.valueOf(4); - ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -792,7 +808,7 @@ public class SECNamedCurves BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -819,7 +835,7 @@ public class SECNamedCurves BigInteger n = fromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF"); BigInteger h = BigInteger.valueOf(4); - ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -846,7 +862,7 @@ public class SECNamedCurves BigInteger n = fromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -875,7 +891,7 @@ public class SECNamedCurves BigInteger n = fromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001"); BigInteger h = BigInteger.valueOf(4); - ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -904,7 +920,7 @@ public class SECNamedCurves BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47"); BigInteger h = BigInteger.valueOf(2); - ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19")); ECPoint G = curve.decodePoint(Hex.decode("04" diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java index 8b19cd6..fb60aca 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java @@ -3,48 +3,85 @@ package org.bouncycastle.asn1.sec; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +/** + * Certicom object identifiers + * <pre> + * ellipticCurve OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) + * } + * </pre> + */ public interface SECObjectIdentifiers { - /** - * ellipticCurve OBJECT IDENTIFIER ::= { - * iso(1) identified-organization(3) certicom(132) curve(0) - * } - */ + /** Base OID: 1.3.132.0 */ static final ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.132.0"); + /** sect163k1 OID: 1.3.132.0.1 */ static final ASN1ObjectIdentifier sect163k1 = ellipticCurve.branch("1"); + /** sect163r1 OID: 1.3.132.0.2 */ static final ASN1ObjectIdentifier sect163r1 = ellipticCurve.branch("2"); + /** sect239k1 OID: 1.3.132.0.3 */ static final ASN1ObjectIdentifier sect239k1 = ellipticCurve.branch("3"); + /** sect113r1 OID: 1.3.132.0.4 */ static final ASN1ObjectIdentifier sect113r1 = ellipticCurve.branch("4"); + /** sect113r2 OID: 1.3.132.0.5 */ static final ASN1ObjectIdentifier sect113r2 = ellipticCurve.branch("5"); + /** secp112r1 OID: 1.3.132.0.6 */ static final ASN1ObjectIdentifier secp112r1 = ellipticCurve.branch("6"); + /** secp112r2 OID: 1.3.132.0.7 */ static final ASN1ObjectIdentifier secp112r2 = ellipticCurve.branch("7"); + /** secp160r1 OID: 1.3.132.0.8 */ static final ASN1ObjectIdentifier secp160r1 = ellipticCurve.branch("8"); + /** secp160k1 OID: 1.3.132.0.9 */ static final ASN1ObjectIdentifier secp160k1 = ellipticCurve.branch("9"); + /** secp256k1 OID: 1.3.132.0.10 */ static final ASN1ObjectIdentifier secp256k1 = ellipticCurve.branch("10"); + /** sect163r2 OID: 1.3.132.0.15 */ static final ASN1ObjectIdentifier sect163r2 = ellipticCurve.branch("15"); + /** sect283k1 OID: 1.3.132.0.16 */ static final ASN1ObjectIdentifier sect283k1 = ellipticCurve.branch("16"); + /** sect283r1 OID: 1.3.132.0.17 */ static final ASN1ObjectIdentifier sect283r1 = ellipticCurve.branch("17"); + /** sect131r1 OID: 1.3.132.0.22 */ static final ASN1ObjectIdentifier sect131r1 = ellipticCurve.branch("22"); + /** sect131r2 OID: 1.3.132.0.23 */ static final ASN1ObjectIdentifier sect131r2 = ellipticCurve.branch("23"); + /** sect193r1 OID: 1.3.132.0.24 */ static final ASN1ObjectIdentifier sect193r1 = ellipticCurve.branch("24"); + /** sect193r2 OID: 1.3.132.0.25 */ static final ASN1ObjectIdentifier sect193r2 = ellipticCurve.branch("25"); + /** sect233k1 OID: 1.3.132.0.26 */ static final ASN1ObjectIdentifier sect233k1 = ellipticCurve.branch("26"); + /** sect233r1 OID: 1.3.132.0.27 */ static final ASN1ObjectIdentifier sect233r1 = ellipticCurve.branch("27"); + /** secp128r1 OID: 1.3.132.0.28 */ static final ASN1ObjectIdentifier secp128r1 = ellipticCurve.branch("28"); + /** secp128r2 OID: 1.3.132.0.29 */ static final ASN1ObjectIdentifier secp128r2 = ellipticCurve.branch("29"); + /** secp160r2 OID: 1.3.132.0.30 */ static final ASN1ObjectIdentifier secp160r2 = ellipticCurve.branch("30"); + /** secp192k1 OID: 1.3.132.0.31 */ static final ASN1ObjectIdentifier secp192k1 = ellipticCurve.branch("31"); + /** secp224k1 OID: 1.3.132.0.32 */ static final ASN1ObjectIdentifier secp224k1 = ellipticCurve.branch("32"); + /** secp224r1 OID: 1.3.132.0.33 */ static final ASN1ObjectIdentifier secp224r1 = ellipticCurve.branch("33"); + /** secp384r1 OID: 1.3.132.0.34 */ static final ASN1ObjectIdentifier secp384r1 = ellipticCurve.branch("34"); + /** secp521r1 OID: 1.3.132.0.35 */ static final ASN1ObjectIdentifier secp521r1 = ellipticCurve.branch("35"); + /** sect409k1 OID: 1.3.132.0.36 */ static final ASN1ObjectIdentifier sect409k1 = ellipticCurve.branch("36"); + /** sect409r1 OID: 1.3.132.0.37 */ static final ASN1ObjectIdentifier sect409r1 = ellipticCurve.branch("37"); + /** sect571k1 OID: 1.3.132.0.38 */ static final ASN1ObjectIdentifier sect571k1 = ellipticCurve.branch("38"); + /** sect571r1 OID: 1.3.132.0.39 */ static final ASN1ObjectIdentifier sect571r1 = ellipticCurve.branch("39"); + /** secp192r1 OID: 1.3.132.0.prime192v1 */ static final ASN1ObjectIdentifier secp192r1 = X9ObjectIdentifiers.prime192v1; + /** secp256r1 OID: 1.3.132.0.prime256v1 */ static final ASN1ObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1; } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java index df9a0ff..895f5e8 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java @@ -2,41 +2,74 @@ package org.bouncycastle.asn1.teletrust; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +/** + * TeleTrusT: + * { iso(1) identifier-organization(3) teleTrust(36) algorithm(3) + * + */ public interface TeleTrusTObjectIdentifiers { + /** 1.3.36.3 */ static final ASN1ObjectIdentifier teleTrusTAlgorithm = new ASN1ObjectIdentifier("1.3.36.3"); + /** 1.3.36.3.2.1 */ static final ASN1ObjectIdentifier ripemd160 = teleTrusTAlgorithm.branch("2.1"); + /** 1.3.36.3.2.2 */ static final ASN1ObjectIdentifier ripemd128 = teleTrusTAlgorithm.branch("2.2"); + /** 1.3.36.3.2.3 */ static final ASN1ObjectIdentifier ripemd256 = teleTrusTAlgorithm.branch("2.3"); + /** 1.3.36.3.3.1 */ static final ASN1ObjectIdentifier teleTrusTRSAsignatureAlgorithm = teleTrusTAlgorithm.branch("3.1"); - static final ASN1ObjectIdentifier rsaSignatureWithripemd160 = teleTrusTRSAsignatureAlgorithm.branch("2"); - static final ASN1ObjectIdentifier rsaSignatureWithripemd128 = teleTrusTRSAsignatureAlgorithm.branch("3"); - static final ASN1ObjectIdentifier rsaSignatureWithripemd256 = teleTrusTRSAsignatureAlgorithm.branch("4"); + /** 1.3.36.3.3.1.2 */ + static final ASN1ObjectIdentifier rsaSignatureWithripemd160 = teleTrusTRSAsignatureAlgorithm.branch("2"); + /** 1.3.36.3.3.1.3 */ + static final ASN1ObjectIdentifier rsaSignatureWithripemd128 = teleTrusTRSAsignatureAlgorithm.branch("3"); + /** 1.3.36.3.3.1.4 */ + static final ASN1ObjectIdentifier rsaSignatureWithripemd256 = teleTrusTRSAsignatureAlgorithm.branch("4"); - static final ASN1ObjectIdentifier ecSign = teleTrusTAlgorithm.branch("3.2"); + /** 1.3.36.3.3.2 */ + static final ASN1ObjectIdentifier ecSign = teleTrusTAlgorithm.branch("3.2"); - static final ASN1ObjectIdentifier ecSignWithSha1 = ecSign.branch("1"); + /** 1.3.36.3.3.2,1 */ + static final ASN1ObjectIdentifier ecSignWithSha1 = ecSign.branch("1"); + /** 1.3.36.3.3.2.2 */ static final ASN1ObjectIdentifier ecSignWithRipemd160 = ecSign.branch("2"); + /** 1.3.36.3.3.2.8 */ static final ASN1ObjectIdentifier ecc_brainpool = teleTrusTAlgorithm.branch("3.2.8"); + /** 1.3.36.3.3.2.8.1 */ static final ASN1ObjectIdentifier ellipticCurve = ecc_brainpool.branch("1"); + /** 1.3.36.3.3.2.8.1 */ static final ASN1ObjectIdentifier versionOne = ellipticCurve.branch("1"); + /** 1.3.36.3.3.2.8.1.1 */ static final ASN1ObjectIdentifier brainpoolP160r1 = versionOne.branch("1"); + /** 1.3.36.3.3.2.8.1.2 */ static final ASN1ObjectIdentifier brainpoolP160t1 = versionOne.branch("2"); + /** 1.3.36.3.3.2.8.1.3 */ static final ASN1ObjectIdentifier brainpoolP192r1 = versionOne.branch("3"); + /** 1.3.36.3.3.2.8.1.4 */ static final ASN1ObjectIdentifier brainpoolP192t1 = versionOne.branch("4"); + /** 1.3.36.3.3.2.8.1.5 */ static final ASN1ObjectIdentifier brainpoolP224r1 = versionOne.branch("5"); + /** 1.3.36.3.3.2.8.1.6 */ static final ASN1ObjectIdentifier brainpoolP224t1 = versionOne.branch("6"); + /** 1.3.36.3.3.2.8.1.7 */ static final ASN1ObjectIdentifier brainpoolP256r1 = versionOne.branch("7"); + /** 1.3.36.3.3.2.8.1.8 */ static final ASN1ObjectIdentifier brainpoolP256t1 = versionOne.branch("8"); + /** 1.3.36.3.3.2.8.1.9 */ static final ASN1ObjectIdentifier brainpoolP320r1 = versionOne.branch("9"); + /** 1.3.36.3.3.2.8.1.10 */ static final ASN1ObjectIdentifier brainpoolP320t1 = versionOne.branch("10"); + /** 1.3.36.3.3.2.8.1.11 */ static final ASN1ObjectIdentifier brainpoolP384r1 = versionOne.branch("11"); + /** 1.3.36.3.3.2.8.1.12 */ static final ASN1ObjectIdentifier brainpoolP384t1 = versionOne.branch("12"); + /** 1.3.36.3.3.2.8.1.13 */ static final ASN1ObjectIdentifier brainpoolP512r1 = versionOne.branch("13"); + /** 1.3.36.3.3.2.8.1.14 */ static final ASN1ObjectIdentifier brainpoolP512t1 = versionOne.branch("14"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java index 714a32c..6842182 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java @@ -1,6 +1,7 @@ package org.bouncycastle.asn1.x500.style; import java.io.IOException; +import java.util.Enumeration; import java.util.Hashtable; import org.bouncycastle.asn1.ASN1Encodable; @@ -19,8 +20,6 @@ import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; public class BCStyle implements X500NameStyle { - public static final X500NameStyle INSTANCE = new BCStyle(); - /** * country code - StringType(SIZE(2)) */ @@ -273,9 +272,18 @@ public class BCStyle DefaultLookUp.put("name", NAME); } + /** + * Singleton instance. + */ + public static final X500NameStyle INSTANCE = new BCStyle(); + + protected final Hashtable defaultLookUp; + protected final Hashtable defaultSymbols; + protected BCStyle() { - + defaultSymbols = copyHashTable(DefaultSymbols); + defaultLookUp = copyHashTable(DefaultLookUp); } public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) @@ -322,12 +330,12 @@ public class BCStyle public String[] oidToAttrNames(ASN1ObjectIdentifier oid) { - return IETFUtils.findAttrNamesForOID(oid, DefaultLookUp); + return IETFUtils.findAttrNamesForOID(oid, defaultLookUp); } public ASN1ObjectIdentifier attrNameToOID(String attrName) { - return IETFUtils.decodeAttrName(attrName, DefaultLookUp); + return IETFUtils.decodeAttrName(attrName, defaultLookUp); } public boolean areEqual(X500Name name1, X500Name name2) @@ -451,9 +459,23 @@ public class BCStyle buf.append(','); } - IETFUtils.appendRDN(buf, rdns[i], DefaultSymbols); + IETFUtils.appendRDN(buf, rdns[i], defaultSymbols); } return buf.toString(); } + + private static Hashtable copyHashTable(Hashtable paramsMap) + { + Hashtable newTable = new Hashtable(); + + Enumeration keys = paramsMap.keys(); + while (keys.hasMoreElements()) + { + Object key = keys.nextElement(); + newTable.put(key, paramsMap.get(key)); + } + + return newTable; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java index c73107e..b4f1794 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java @@ -405,7 +405,7 @@ public class IETFUtils int start = 0; if (vBuf.length() > 0) { - while (vBuf.charAt(start) == ' ') + while (vBuf.length() > start && vBuf.charAt(start) == ' ') { vBuf.insert(start, "\\"); start += 2; diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java index 8486989..8c92257 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java @@ -1,6 +1,7 @@ package org.bouncycastle.asn1.x500.style; import java.io.IOException; +import java.util.Enumeration; import java.util.Hashtable; import org.bouncycastle.asn1.ASN1Encodable; @@ -16,8 +17,6 @@ import org.bouncycastle.asn1.x500.X500NameStyle; public class RFC4519Style implements X500NameStyle { - public static final X500NameStyle INSTANCE = new RFC4519Style(); - public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15"); public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6"); public static final ASN1ObjectIdentifier cn = new ASN1ObjectIdentifier("2.5.4.3"); @@ -166,9 +165,18 @@ public class RFC4519Style // TODO: need to add correct matching for equality comparisons. } + /** + * Singleton instance. + */ + public static final X500NameStyle INSTANCE = new RFC4519Style(); + + protected final Hashtable defaultLookUp; + protected final Hashtable defaultSymbols; + protected RFC4519Style() { - + defaultSymbols = copyHashTable(DefaultSymbols); + defaultLookUp = copyHashTable(DefaultLookUp); } public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) @@ -211,12 +219,12 @@ public class RFC4519Style public String[] oidToAttrNames(ASN1ObjectIdentifier oid) { - return IETFUtils.findAttrNamesForOID(oid, DefaultLookUp); + return IETFUtils.findAttrNamesForOID(oid, defaultLookUp); } public ASN1ObjectIdentifier attrNameToOID(String attrName) { - return IETFUtils.decodeAttrName(attrName, DefaultLookUp); + return IETFUtils.decodeAttrName(attrName, defaultLookUp); } public boolean areEqual(X500Name name1, X500Name name2) @@ -350,9 +358,23 @@ public class RFC4519Style buf.append(','); } - IETFUtils.appendRDN(buf, rdns[i], DefaultSymbols); + IETFUtils.appendRDN(buf, rdns[i], defaultSymbols); } return buf.toString(); } + + private static Hashtable copyHashTable(Hashtable paramsMap) + { + Hashtable newTable = new Hashtable(); + + Enumeration keys = paramsMap.keys(); + while (keys.hasMoreElements()) + { + Object key = keys.nextElement(); + newTable.put(key, paramsMap.get(key)); + } + + return newTable; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java index 92aa0f7..73fe7b4 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java @@ -41,7 +41,10 @@ public class AttributeCertificate this.signatureAlgorithm = signatureAlgorithm; this.signatureValue = signatureValue; } - + + /** + * @deprecated use getInstance() method. + */ public AttributeCertificate( ASN1Sequence seq) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java index 7b9d450..ae539f4 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java @@ -13,7 +13,7 @@ import org.bouncycastle.asn1.DERSequence; public class AttributeCertificateInfo extends ASN1Object { - private ASN1Integer version; + private ASN1Integer version; private Holder holder; private AttCertIssuer issuer; private AlgorithmIdentifier signature; @@ -48,22 +48,33 @@ public class AttributeCertificateInfo private AttributeCertificateInfo( ASN1Sequence seq) { - if (seq.size() < 7 || seq.size() > 9) + if (seq.size() < 6 || seq.size() > 9) { throw new IllegalArgumentException("Bad sequence size: " + seq.size()); } - this.version = ASN1Integer.getInstance(seq.getObjectAt(0)); - this.holder = Holder.getInstance(seq.getObjectAt(1)); - this.issuer = AttCertIssuer.getInstance(seq.getObjectAt(2)); - this.signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(3)); - this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(4)); - this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(5)); - this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(6)); + int start; + if (seq.getObjectAt(0) instanceof ASN1Integer) // in version 1 certs version is DEFAULT v1(0) + { + this.version = ASN1Integer.getInstance(seq.getObjectAt(0)); + start = 1; + } + else + { + this.version = new ASN1Integer(0); + start = 0; + } + + this.holder = Holder.getInstance(seq.getObjectAt(start)); + this.issuer = AttCertIssuer.getInstance(seq.getObjectAt(start + 1)); + this.signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(start + 2)); + this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(start + 3)); + this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(start + 4)); + this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(start + 5)); - for (int i = 7; i < seq.size(); i++) + for (int i = start + 6; i < seq.size(); i++) { - ASN1Encodable obj = (ASN1Encodable)seq.getObjectAt(i); + ASN1Encodable obj = seq.getObjectAt(i); if (obj instanceof DERBitString) { @@ -143,7 +154,10 @@ public class AttributeCertificateInfo { ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(version); + if (version.getValue().intValue() != 0) + { + v.add(version); + } v.add(holder); v.add(issuer); v.add(signature); diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java index 91a37ad..61d7d4a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java @@ -31,6 +31,8 @@ public class CertificateList TBSCertList tbsCertList; AlgorithmIdentifier sigAlgId; DERBitString sig; + boolean isHashCodeSet = false; + int hashCodeValue; public static CertificateList getInstance( ASN1TaggedObject obj, @@ -54,6 +56,10 @@ public class CertificateList return null; } + /** + * @deprecated use getInstance() method. + * @param seq + */ public CertificateList( ASN1Sequence seq) { @@ -124,4 +130,15 @@ public class CertificateList return new DERSequence(v); } + + public int hashCode() + { + if (!isHashCodeSet) + { + hashCodeValue = super.hashCode(); + isHashCodeSet = true; + } + + return hashCodeValue; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java index dcc1b1f..84d21ca 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java @@ -25,6 +25,13 @@ public class ExtendedKeyUsage Hashtable usageTable = new Hashtable(); ASN1Sequence seq; + /** + * Return an ExtendedKeyUsage from the passed in tagged object. + * + * @param obj the tagged object containing the ExtendedKeyUsage + * @param explicit true if the tagged object should be interpreted as explicitly tagged, false if implicit. + * @return the ExtendedKeyUsage contained. + */ public static ExtendedKeyUsage getInstance( ASN1TaggedObject obj, boolean explicit) @@ -32,6 +39,12 @@ public class ExtendedKeyUsage return getInstance(ASN1Sequence.getInstance(obj, explicit)); } + /** + * Return an ExtendedKeyUsage from the passed in object. + * + * @param obj an ExtendedKeyUsage, some form or encoding of one, or null. + * @return an ExtendedKeyUsage object, or null if null is passed in. + */ public static ExtendedKeyUsage getInstance( Object obj) { @@ -47,11 +60,22 @@ public class ExtendedKeyUsage return null; } + /** + * Retrieve an ExtendedKeyUsage for a passed in Extensions object, if present. + * + * @param extensions the extensions object to be examined. + * @return the ExtendedKeyUsage, null if the extension is not present. + */ public static ExtendedKeyUsage fromExtensions(Extensions extensions) { return ExtendedKeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.extendedKeyUsage)); } + /** + * Base constructor, from a single KeyPurposeId. + * + * @param usage the keyPurposeId to be included. + */ public ExtendedKeyUsage( KeyPurposeId usage) { @@ -78,6 +102,11 @@ public class ExtendedKeyUsage } } + /** + * Base constructor, from multiple KeyPurposeIds. + * + * @param usages an array of KeyPurposeIds. + */ public ExtendedKeyUsage( KeyPurposeId[] usages) { @@ -103,7 +132,7 @@ public class ExtendedKeyUsage while (e.hasMoreElements()) { - ASN1Primitive o = (ASN1Primitive)e.nextElement(); + KeyPurposeId o = KeyPurposeId.getInstance(e.nextElement()); v.add(o); this.usageTable.put(o, o); @@ -112,6 +141,12 @@ public class ExtendedKeyUsage this.seq = new DERSequence(v); } + /** + * Return true if this ExtendedKeyUsage object contains the passed in keyPurposeId. + * + * @param keyPurposeId the KeyPurposeId of interest. + * @return true if the keyPurposeId is present, false otherwise. + */ public boolean hasKeyPurposeId( KeyPurposeId keyPurposeId) { @@ -120,7 +155,7 @@ public class ExtendedKeyUsage /** * Returns all extended key usages. - * The returned vector contains DERObjectIdentifiers. + * * @return An array with all key purposes. */ public KeyPurposeId[] getUsages() @@ -135,11 +170,21 @@ public class ExtendedKeyUsage return temp; } + /** + * Return the number of KeyPurposeIds present in this ExtendedKeyUsage. + * + * @return the number of KeyPurposeIds + */ public int size() { return usageTable.size(); } - + + /** + * Return the ASN.1 primitive form of this object. + * + * @return an ASN1Sequence. + */ public ASN1Primitive toASN1Primitive() { return seq; diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java index 6ae6e35..e854681 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java @@ -31,9 +31,9 @@ import org.bouncycastle.asn1.DERTaggedObject; * * <pre> * subject CHOICE { - * baseCertificateID [0] IssuerSerial, + * baseCertificateID [0] EXPLICIT IssuerSerial, * -- associated with a Public Key Certificate - * subjectName [1] GeneralNames }, + * subjectName [1] EXPLICIT GeneralNames }, * -- associated with a name * </pre> */ @@ -79,10 +79,10 @@ public class Holder switch (tagObj.getTagNo()) { case 0: - baseCertificateID = IssuerSerial.getInstance(tagObj, false); + baseCertificateID = IssuerSerial.getInstance(tagObj, true); break; case 1: - entityName = GeneralNames.getInstance(tagObj, false); + entityName = GeneralNames.getInstance(tagObj, true); break; default: throw new IllegalArgumentException("unknown tag in Holder"); @@ -234,11 +234,11 @@ public class Holder { if (entityName != null) { - return new DERTaggedObject(false, 1, entityName); + return new DERTaggedObject(true, 1, entityName); } else { - return new DERTaggedObject(false, 0, baseCertificateID); + return new DERTaggedObject(true, 0, baseCertificateID); } } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java index 8d3036b..fefc939 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java @@ -10,6 +10,7 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x500.X500Name; public class IssuerSerial extends ASN1Object @@ -59,6 +60,13 @@ public class IssuerSerial } public IssuerSerial( + X500Name issuer, + BigInteger serial) + { + this(new GeneralNames(new GeneralName(issuer)), new ASN1Integer(serial)); + } + + public IssuerSerial( GeneralNames issuer, BigInteger serial) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java index 2943c0b..d4456b7 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java @@ -74,6 +74,17 @@ public class KeyUsage this.bitString = bitString; } + /** + * Return true if a given usage bit is set, false otherwise. + * + * @param usages combination of usage flags. + * @return true if all bits are set, false otherwise. + */ + public boolean hasUsages(int usages) + { + return (bitString.intValue() & usages) == usages; + } + public byte[] getBytes() { return bitString.getBytes(); diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyConstraints.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyConstraints.java new file mode 100644 index 0000000..aeb53f0 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyConstraints.java @@ -0,0 +1,106 @@ +package org.bouncycastle.asn1.x509; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * PKIX RFC 5280 + * <pre> + * id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } + * + * PolicyConstraints ::= SEQUENCE { + * requireExplicitPolicy [0] SkipCerts OPTIONAL, + * inhibitPolicyMapping [1] SkipCerts OPTIONAL } + * + * SkipCerts ::= INTEGER (0..MAX) + * </pre> + */ +public class PolicyConstraints + extends ASN1Object +{ + private BigInteger requireExplicitPolicyMapping; + private BigInteger inhibitPolicyMapping; + + public PolicyConstraints(BigInteger requireExplicitPolicyMapping, BigInteger inhibitPolicyMapping) + { + this.requireExplicitPolicyMapping = requireExplicitPolicyMapping; + this.inhibitPolicyMapping = inhibitPolicyMapping; + } + + private PolicyConstraints(ASN1Sequence seq) + { + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject to = ASN1TaggedObject.getInstance(seq.getObjectAt(i)); + + if (to.getTagNo() == 0) + { + requireExplicitPolicyMapping = ASN1Integer.getInstance(to, false).getValue(); + } + else if (to.getTagNo() == 1) + { + inhibitPolicyMapping = ASN1Integer.getInstance(to, false).getValue(); + } + else + { + throw new IllegalArgumentException("Unknown tag encountered."); + } + } + } + + public static PolicyConstraints getInstance( + Object obj) + { + if (obj instanceof PolicyConstraints) + { + return (PolicyConstraints)obj; + } + + if (obj != null) + { + return new PolicyConstraints(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static PolicyConstraints fromExtensions(Extensions extensions) + { + return PolicyConstraints.getInstance(extensions.getExtensionParsedValue(Extension.policyConstraints)); + } + + public BigInteger getRequireExplicitPolicyMapping() + { + return requireExplicitPolicyMapping; + } + + public BigInteger getInhibitPolicyMapping() + { + return inhibitPolicyMapping; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (requireExplicitPolicyMapping != null) + { + v.add(new DERTaggedObject(0, new ASN1Integer(requireExplicitPolicyMapping))); + } + + if (inhibitPolicyMapping != null) + { + v.add(new DERTaggedObject(1, new ASN1Integer(inhibitPolicyMapping))); + } + + return new DERSequence(v); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java index f020bcb..f29284d 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java @@ -10,6 +10,7 @@ import org.bouncycastle.asn1.DERBoolean; /** * an object for the elements in the X.509 V3 extension block. + * @deprecated use Extension */ public class X509Extension { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java index 9aed4e1..0c372f7 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java @@ -1242,49 +1242,47 @@ public class X509Name buf.append('='); - int index = buf.length(); - int start = index; - + int start = buf.length(); buf.append(value); - - int end = buf.length(); + int end = buf.length(); if (value.length() >= 2 && value.charAt(0) == '\\' && value.charAt(1) == '#') { - index += 2; - } - - while (index != end) - { - if ((buf.charAt(index) == ',') - || (buf.charAt(index) == '"') - || (buf.charAt(index) == '\\') - || (buf.charAt(index) == '+') - || (buf.charAt(index) == '=') - || (buf.charAt(index) == '<') - || (buf.charAt(index) == '>') - || (buf.charAt(index) == ';')) - { - buf.insert(index, "\\"); - index++; - end++; - } - - index++; + start += 2; } - while (buf.charAt(start) == ' ') + while (start < end && buf.charAt(start) == ' ') { buf.insert(start, "\\"); start += 2; + ++end; } - int endBuf = buf.length() - 1; + while (--end > start && buf.charAt(end) == ' ') + { + buf.insert(end, '\\'); + } - while (endBuf >= 0 && buf.charAt(endBuf) == ' ') + while (start <= end) { - buf.insert(endBuf, '\\'); - endBuf--; + switch (buf.charAt(start)) + { + case ',': + case '"': + case '\\': + case '+': + case '=': + case '<': + case '>': + case ';': + buf.insert(start, "\\"); + start += 2; + ++end; + break; + default: + ++start; + break; + } } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java index ed4dd32..e1c7a54 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java @@ -4,64 +4,78 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; public interface X509ObjectIdentifiers { - // - // base id - // - static final String id = "2.5.4"; - - static final ASN1ObjectIdentifier commonName = new ASN1ObjectIdentifier(id + ".3"); - static final ASN1ObjectIdentifier countryName = new ASN1ObjectIdentifier(id + ".6"); - static final ASN1ObjectIdentifier localityName = new ASN1ObjectIdentifier(id + ".7"); - static final ASN1ObjectIdentifier stateOrProvinceName = new ASN1ObjectIdentifier(id + ".8"); - static final ASN1ObjectIdentifier organization = new ASN1ObjectIdentifier(id + ".10"); - static final ASN1ObjectIdentifier organizationalUnitName = new ASN1ObjectIdentifier(id + ".11"); + + /** Subject RDN components: commonName = 2.5.4.3 */ + static final ASN1ObjectIdentifier commonName = new ASN1ObjectIdentifier("2.5.4.3"); + /** Subject RDN components: countryName = 2.5.4.6 */ + static final ASN1ObjectIdentifier countryName = new ASN1ObjectIdentifier("2.5.4.6"); + /** Subject RDN components: localityName = 2.5.4.7 */ + static final ASN1ObjectIdentifier localityName = new ASN1ObjectIdentifier("2.5.4.7"); + /** Subject RDN components: stateOrProvinceName = 2.5.4.8 */ + static final ASN1ObjectIdentifier stateOrProvinceName = new ASN1ObjectIdentifier("2.5.4.8"); + /** Subject RDN components: organization = 2.5.4.10 */ + static final ASN1ObjectIdentifier organization = new ASN1ObjectIdentifier("2.5.4.10"); + /** Subject RDN components: organizationalUnitName = 2.5.4.11 */ + static final ASN1ObjectIdentifier organizationalUnitName = new ASN1ObjectIdentifier("2.5.4.11"); + /** Subject RDN components: telephone_number = 2.5.4.20 */ static final ASN1ObjectIdentifier id_at_telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20"); - static final ASN1ObjectIdentifier id_at_name = new ASN1ObjectIdentifier(id + ".41"); + /** Subject RDN components: name = 2.5.4.41 */ + static final ASN1ObjectIdentifier id_at_name = new ASN1ObjectIdentifier("2.5.4.41"); - // id-SHA1 OBJECT IDENTIFIER ::= - // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // + /** + * id-SHA1 OBJECT IDENTIFIER ::= + * {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } + * <p> + * OID: 1.3.14.3.2.27 + */ static final ASN1ObjectIdentifier id_SHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26"); - // - // ripemd160 OBJECT IDENTIFIER ::= - // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)} - // + /** + * ripemd160 OBJECT IDENTIFIER ::= + * {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)} + * <p> + * OID: 1.3.36.3.2.1 + */ static final ASN1ObjectIdentifier ripemd160 = new ASN1ObjectIdentifier("1.3.36.3.2.1"); - // - // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::= - // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) } - // + /** + * ripemd160WithRSAEncryption OBJECT IDENTIFIER ::= + * {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) } + * <p> + * OID: 1.3.36.3.3.1.2 + */ static final ASN1ObjectIdentifier ripemd160WithRSAEncryption = new ASN1ObjectIdentifier("1.3.36.3.3.1.2"); + /** OID: 2.5.8.1.1 */ static final ASN1ObjectIdentifier id_ea_rsa = new ASN1ObjectIdentifier("2.5.8.1.1"); - // id-pkix - static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7"); + /** id-pkix OID: 1.3.6.1.5.5.7 + */ + static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7"); - // - // private internet extensions - // - static final ASN1ObjectIdentifier id_pe = new ASN1ObjectIdentifier(id_pkix + ".1"); + /** + * private internet extensions; OID = 1.3.6.1.5.5.7.1 + */ + static final ASN1ObjectIdentifier id_pe = id_pkix.branch("1"); - // - // ISO ARC for standard certificate and CRL extensions - // + /** + * ISO ARC for standard certificate and CRL extensions + * <p> + * OID: 2.5.29 + */ static final ASN1ObjectIdentifier id_ce = new ASN1ObjectIdentifier("2.5.29"); - // - // authority information access - // - static final ASN1ObjectIdentifier id_ad = new ASN1ObjectIdentifier(id_pkix + ".48"); - static final ASN1ObjectIdentifier id_ad_caIssuers = new ASN1ObjectIdentifier(id_ad + ".2"); - static final ASN1ObjectIdentifier id_ad_ocsp = new ASN1ObjectIdentifier(id_ad + ".1"); + /** id-pkix OID: 1.3.6.1.5.5.7.48 */ + static final ASN1ObjectIdentifier id_ad = id_pkix.branch("48"); + /** id-ad-caIssuers OID: 1.3.6.1.5.5.7.48.2 */ + static final ASN1ObjectIdentifier id_ad_caIssuers = id_ad.branch("2"); + /** id-ad-ocsp OID: 1.3.6.1.5.5.7.48.1 */ + static final ASN1ObjectIdentifier id_ad_ocsp = id_ad.branch("1"); - // - // OID for ocsp and crl uri in AuthorityInformationAccess extension - // + /** OID for ocsp uri in AuthorityInformationAccess extension */ static final ASN1ObjectIdentifier ocspAccessMethod = id_ad_ocsp; - static final ASN1ObjectIdentifier crlAccessMethod = id_ad_caIssuers; + /** OID for crl uri in AuthorityInformationAccess extension */ + static final ASN1ObjectIdentifier crlAccessMethod = id_ad_caIssuers; } - diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java new file mode 100644 index 0000000..fef664f --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java @@ -0,0 +1,107 @@ +package org.bouncycastle.asn1.x9; + +import java.util.Enumeration; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.nist.NISTNamedCurves; +import org.bouncycastle.asn1.sec.SECNamedCurves; +// BEGIN android-removed +// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; +// END android-removed + +/** + * A general class that reads all X9.62 style EC curve tables. + */ +public class ECNamedCurveTable +{ + /** + * return a X9ECParameters object representing the passed in named + * curve. The routine returns null if the curve is not present. + * + * @param name the name of the curve requested + * @return an X9ECParameters object or null if the curve is not available. + */ + public static X9ECParameters getByName( + String name) + { + X9ECParameters ecP = X962NamedCurves.getByName(name); + + if (ecP == null) + { + ecP = SECNamedCurves.getByName(name); + } + + // BEGIN android-removed + // if (ecP == null) + // { + // ecP = TeleTrusTNamedCurves.getByName(name); + // } + // END android-removed + + if (ecP == null) + { + ecP = NISTNamedCurves.getByName(name); + } + + return ecP; + } + + /** + * return a X9ECParameters object representing the passed in named + * curve. + * + * @param oid the object id of the curve requested + * @return an X9ECParameters object or null if the curve is not available. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + X9ECParameters ecP = X962NamedCurves.getByOID(oid); + + if (ecP == null) + { + ecP = SECNamedCurves.getByOID(oid); + } + + // BEGIN android-removed + // if (ecP == null) + // { + // ecP = TeleTrusTNamedCurves.getByOID(oid); + // } + // END android-removed + + // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup + + return ecP; + } + + /** + * return an enumeration of the names of the available curves. + * + * @return an enumeration of the names of the available curves. + */ + public static Enumeration getNames() + { + Vector v = new Vector(); + + addEnumeration(v, X962NamedCurves.getNames()); + addEnumeration(v, SECNamedCurves.getNames()); + addEnumeration(v, NISTNamedCurves.getNames()); + // BEGIN android-removed + // addEnumeration(v, TeleTrusTNamedCurves.getNames()); + // END android-removed + + return v.elements(); + } + + private static void addEnumeration( + Vector v, + Enumeration e) + { + while (e.hasMoreElements()) + { + v.addElement(e.nextElement()); + } + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java index e059089..60f9008 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java @@ -39,11 +39,21 @@ public class X9ECParameters } X9Curve x9c = new X9Curve( - new X9FieldID((ASN1Sequence)seq.getObjectAt(1)), - (ASN1Sequence)seq.getObjectAt(2)); + X9FieldID.getInstance(seq.getObjectAt(1)), + ASN1Sequence.getInstance(seq.getObjectAt(2))); this.curve = x9c.getCurve(); - this.g = new X9ECPoint(curve, (ASN1OctetString)seq.getObjectAt(3)).getPoint(); + Object p = seq.getObjectAt(3); + + if (p instanceof X9ECPoint) + { + this.g = ((X9ECPoint)p).getPoint(); + } + else + { + this.g = new X9ECPoint(curve, (ASN1OctetString)p).getPoint(); + } + this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue(); this.seed = x9c.getSeed(); @@ -93,7 +103,7 @@ public class X9ECParameters byte[] seed) { this.curve = curve; - this.g = g; + this.g = g.normalize(); this.n = n; this.h = h; this.seed = seed; diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java index a4acb6e..cbb9116 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java @@ -18,7 +18,7 @@ public class X9ECPoint public X9ECPoint( ECPoint p) { - this.p = p; + this.p = p.normalize(); } public X9ECPoint( diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java index 30598e2..a210352 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java @@ -71,11 +71,26 @@ public class X9FieldID this.parameters = new DERSequence(fieldIdParams); } - public X9FieldID( + private X9FieldID( ASN1Sequence seq) { - this.id = (ASN1ObjectIdentifier)seq.getObjectAt(0); - this.parameters = (ASN1Primitive)seq.getObjectAt(1); + this.id = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + this.parameters = seq.getObjectAt(1).toASN1Primitive(); + } + + public static X9FieldID getInstance(Object obj) + { + if (obj instanceof X9FieldID) + { + return (X9FieldID)obj; + } + + if (obj != null) + { + return new X9FieldID(ASN1Sequence.getInstance(obj)); + } + + return null; } public ASN1ObjectIdentifier getIdentifier() diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java index f005cfa..eabf90e 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java @@ -2,109 +2,172 @@ package org.bouncycastle.asn1.x9; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +/** + * + * X9.62 + * <pre> + * ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + * us(840) ansi-x962(10045) } + * </pre> + */ public interface X9ObjectIdentifiers { - // - // X9.62 - // - // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2) - // us(840) ansi-x962(10045) } - // + /** Base OID: 1.2.840.10045 */ static final 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"); + /** OID: 1.2.840.10045.1.1 */ static final ASN1ObjectIdentifier prime_field = id_fieldType.branch("1"); + /** OID: 1.2.840.10045.1.2 */ static final 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"); + /** OID: 1.2.840.10045.1.2.3.2 */ static final 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"); + /** OID: 1.2.840.10045.4 */ static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4"); - static final ASN1ObjectIdentifier ecdsa_with_SHA1 = new ASN1ObjectIdentifier(id_ecSigType + ".1"); + /** OID: 1.2.840.10045.4.1 */ + static final ASN1ObjectIdentifier ecdsa_with_SHA1 = id_ecSigType.branch("1"); + /** OID: 1.2.840.10045.2 */ static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2"); + /** OID: 1.2.840.10045.2.1 */ static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1"); + /** OID: 1.2.840.10045.4.3 */ static final 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"); + /** OID: 1.2.840.10045.4.3.2 */ static final 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"); + /** OID: 1.2.840.10045.4.3.4 */ static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4"); - // - // named curves - // + /** + * Named curves base + * <p> + * OID: 1.2.840.10045.1 + */ static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3"); - // - // Two Curves - // + /** + * Two Curves + * <p> + * OID: 1.2.840.10045.1.0 + */ static final ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0"); + /** Two Curve c2pnb163v1, OID: 1.2.840.10045.1.0.1 */ static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1"); + /** Two Curve c2pnb163v2, OID: 1.2.840.10045.1.0.2 */ static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2"); + /** Two Curve c2pnb163v3, OID: 1.2.840.10045.1.0.3 */ static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3"); + /** Two Curve c2pnb176w1, OID: 1.2.840.10045.1.0.4 */ static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4"); + /** Two Curve c2tnb191v1, OID: 1.2.840.10045.1.0.5 */ static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5"); + /** Two Curve c2tnb191v2, OID: 1.2.840.10045.1.0.6 */ static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6"); + /** Two Curve c2tnb191v3, OID: 1.2.840.10045.1.0.7 */ static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7"); + /** Two Curve c2onb191v4, OID: 1.2.840.10045.1.0.8 */ static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8"); + /** Two Curve c2onb191v5, OID: 1.2.840.10045.1.0.9 */ static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9"); + /** Two Curve c2pnb208w1, OID: 1.2.840.10045.1.0.10 */ static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10"); + /** Two Curve c2tnb239v1, OID: 1.2.840.10045.1.0.11 */ static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11"); + /** Two Curve c2tnb239v2, OID: 1.2.840.10045.1.0.12 */ static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12"); + /** Two Curve c2tnb239v3, OID: 1.2.840.10045.1.0.13 */ static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13"); + /** Two Curve c2onb239v4, OID: 1.2.840.10045.1.0.14 */ static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14"); + /** Two Curve c2onb239v5, OID: 1.2.840.10045.1.0.15 */ static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15"); + /** Two Curve c2pnb272w1, OID: 1.2.840.10045.1.0.16 */ static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16"); + /** Two Curve c2pnb304w1, OID: 1.2.840.10045.1.0.17 */ static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17"); + /** Two Curve c2tnb359v1, OID: 1.2.840.10045.1.0.18 */ static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18"); + /** Two Curve c2pnb368w1, OID: 1.2.840.10045.1.0.19 */ static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19"); + /** Two Curve c2tnb431r1, OID: 1.2.840.10045.1.0.20 */ static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20"); - // - // Prime - // + /** + * Prime Curves + * <p> + * OID: 1.2.840.10045.1.1 + */ static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1"); + /** Prime Curve prime192v1, OID: 1.2.840.10045.1.1.1 */ static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1"); + /** Prime Curve prime192v2, OID: 1.2.840.10045.1.1.2 */ static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2"); + /** Prime Curve prime192v3, OID: 1.2.840.10045.1.1.3 */ static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3"); + /** Prime Curve prime239v1, OID: 1.2.840.10045.1.1.4 */ static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4"); + /** Prime Curve prime239v2, OID: 1.2.840.10045.1.1.5 */ static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5"); + /** Prime Curve prime239v3, OID: 1.2.840.10045.1.1.6 */ static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6"); + /** Prime Curve prime256v1, OID: 1.2.840.10045.1.1.7 */ static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7"); - // - // DSA - // - // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) - // us(840) ansi-x957(10040) number-type(4) 1 } + /** + * DSA + * <pre> + * dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) + * us(840) ansi-x957(10040) number-type(4) 1 } + * </pre> + * Base OID: 1.2.840.10040.4.1 + */ static final ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1"); /** - * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57 - * (10040) x9cm(4) 3 } + * <pre> + * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } + * </pre> + * OID: 1.2.840.10040.4.3 */ - public static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3"); + static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3"); /** - * X9.63 + * X9.63 - Signature Specification + * <p> + * Base OID: 1.3.133.16.840.63.0 */ - public static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0"); - public static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2"); - public static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3"); - public static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16"); + static final 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"); + /** OID: 1.3.133.16.840.63.0.3 */ + static final 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"); /** * X9.42 @@ -112,21 +175,33 @@ public interface X9ObjectIdentifiers static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046"); - // - // Diffie-Hellman - // - // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) - // us(840) ansi-x942(10046) number-type(2) 1 } - // - public static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1"); - - public static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3"); - public static final ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1"); - public static final ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2"); - public static final ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3"); - public static final ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4"); - public static final ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5"); - public static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6"); - public static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7"); - public static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8"); + /** + * Diffie-Hellman + * <pre> + * dhpublicnumber OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-x942(10046) number-type(2) 1 + * } + * </pre> + * OID: 1.2.840.10046.2.1 + */ + static final 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"); + /** X9.42 dhStatic OID: 1.2.840.10046.3.1 */ + static final 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"); + /** X9.42 dhOneFlow OID: 1.2.840.10046.3.3 */ + static final 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"); + /** X9.42 dhHybrid2 OID: 1.2.840.10046.3.5 */ + static final 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"); + /** X9.42 MQV2 OID: 1.2.840.10046.3.7 */ + static final 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"); } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java index bdb694d..dd056ac 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java @@ -54,7 +54,7 @@ public class BufferedBlockCipher } else { - partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx))); + partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("GCFB", idx) ||name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx))); } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java b/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java index ef6e29e..0e2b4b0 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java @@ -7,11 +7,6 @@ public interface DerivationFunction { public void init(DerivationParameters param); - /** - * return the message digest used as the basis for the function - */ - public Digest getDigest(); - public int generateBytes(byte[] out, int outOff, int len) throws DataLengthException, IllegalArgumentException; } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java index 59944e0..a491b9d 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java @@ -42,10 +42,13 @@ public class ECDHBasicAgreement CipherParameters pubKey) { ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey; - ECPoint P = pub.getQ().multiply(key.getD()); + ECPoint P = pub.getQ().multiply(key.getD()).normalize(); - // if (p.isInfinity()) throw new RuntimeException("d*Q == infinity"); + if (P.isInfinity()) + { + throw new IllegalStateException("Infinity is not a valid agreement value for ECDH"); + } - return P.getX().toBigInteger(); + return P.getAffineXCoord().toBigInteger(); } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java index 540bd25..cfd86fb 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java @@ -85,7 +85,7 @@ public class RFC3394WrapEngine byte[] buf = new byte[8 + iv.length]; System.arraycopy(iv, 0, block, 0, iv.length); - System.arraycopy(in, 0, block, iv.length, inLen); + System.arraycopy(in, inOff, block, iv.length, inLen); engine.init(true, param); @@ -137,8 +137,8 @@ public class RFC3394WrapEngine byte[] a = new byte[iv.length]; byte[] buf = new byte[8 + iv.length]; - System.arraycopy(in, 0, a, 0, iv.length); - System.arraycopy(in, iv.length, block, 0, inLen - iv.length); + System.arraycopy(in, inOff, a, 0, iv.length); + System.arraycopy(in, inOff + iv.length, block, 0, inLen - iv.length); engine.init(false, param); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java index e7fb943..c9765bf 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java @@ -1,5 +1,8 @@ package org.bouncycastle.crypto.engines; +import java.math.BigInteger; +import java.security.SecureRandom; + import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; @@ -8,16 +11,13 @@ import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import org.bouncycastle.util.BigIntegers; -import java.math.BigInteger; -import java.security.SecureRandom; - /** * this does your basic RSA algorithm with blinding */ public class RSABlindedEngine implements AsymmetricBlockCipher { - private static BigInteger ONE = BigInteger.valueOf(1); + private static final BigInteger ONE = BigInteger.valueOf(1); private RSACoreEngine core = new RSACoreEngine(); private RSAKeyParameters key; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java index 50baa4d..d70ee8f 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java @@ -232,10 +232,10 @@ public class DSAParametersGenerator int seedlen = N; byte[] seed = new byte[seedlen / 8]; -// 3. n = ceiling(L ⁄ outlen) – 1. +// 3. n = ceiling(L / outlen) - 1. int n = (L - 1) / outlen; -// 4. b = L – 1 – (n ∗ outlen). +// 4. b = L - 1 - (n * outlen). int b = (L - 1) % outlen; byte[] output = new byte[d.getDigestSize()]; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java index d77bd74..d5f5fc8 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java @@ -26,6 +26,11 @@ public class ECKeyPairGenerator this.random = ecP.getRandom(); this.params = ecP.getDomainParameters(); + + if (this.random == null) + { + this.random = new SecureRandom(); + } } /** diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java index 316de64..082a1c8 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java @@ -62,7 +62,7 @@ public class PKCS5S2ParametersGenerator hMac.doFinal(state, 0); System.arraycopy(state, 0, out, outOff, state.length); - + for (int count = 1; count < c; count++) { hMac.update(state, 0, state.length); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java deleted file mode 100644 index bb09a76..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java +++ /dev/null @@ -1,244 +0,0 @@ -package org.bouncycastle.crypto.io; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.StreamCipher; - -/** - * A CipherInputStream is composed of an InputStream and a BufferedBlockCipher so - * that read() methods return data that are read in from the - * underlying InputStream but have been additionally processed by the - * Cipher. The Cipher must be fully initialized before being used by - * a CipherInputStream. - * <p> - * For example, if the Cipher is initialized for decryption, the - * CipherInputStream will attempt to read in data and decrypt them, - * before returning the decrypted data. - */ -public class CipherInputStream - extends FilterInputStream -{ - private BufferedBlockCipher bufferedBlockCipher; - private StreamCipher streamCipher; - - private byte[] buf; - private byte[] inBuf; - - private int bufOff; - private int maxBuf; - private boolean finalized; - - private static final int INPUT_BUF_SIZE = 2048; - - /** - * Constructs a CipherInputStream from an InputStream and a - * BufferedBlockCipher. - */ - public CipherInputStream( - InputStream is, - BufferedBlockCipher cipher) - { - super(is); - - this.bufferedBlockCipher = cipher; - - buf = new byte[cipher.getOutputSize(INPUT_BUF_SIZE)]; - inBuf = new byte[INPUT_BUF_SIZE]; - } - - public CipherInputStream( - InputStream is, - StreamCipher cipher) - { - super(is); - - this.streamCipher = cipher; - - buf = new byte[INPUT_BUF_SIZE]; - inBuf = new byte[INPUT_BUF_SIZE]; - } - - /** - * grab the next chunk of input from the underlying input stream - */ - private int nextChunk() - throws IOException - { - int available = super.available(); - - // must always try to read 1 byte! - // some buggy InputStreams return < 0! - if (available <= 0) - { - available = 1; - } - - if (available > inBuf.length) - { - available = super.read(inBuf, 0, inBuf.length); - } - else - { - available = super.read(inBuf, 0, available); - } - - if (available < 0) - { - if (finalized) - { - return -1; - } - - try - { - if (bufferedBlockCipher != null) - { - maxBuf = bufferedBlockCipher.doFinal(buf, 0); - } - else - { - maxBuf = 0; // a stream cipher - } - } - catch (Exception e) - { - throw new IOException("error processing stream: " + e.toString()); - } - - bufOff = 0; - - finalized = true; - - if (bufOff == maxBuf) - { - return -1; - } - } - else - { - bufOff = 0; - - try - { - if (bufferedBlockCipher != null) - { - maxBuf = bufferedBlockCipher.processBytes(inBuf, 0, available, buf, 0); - } - else - { - streamCipher.processBytes(inBuf, 0, available, buf, 0); - maxBuf = available; - } - } - catch (Exception e) - { - throw new IOException("error processing stream: " + e.toString()); - } - - if (maxBuf == 0) // not enough bytes read for first block... - { - return nextChunk(); - } - } - - return maxBuf; - } - - public int read() - throws IOException - { - if (bufOff == maxBuf) - { - if (nextChunk() < 0) - { - return -1; - } - } - - return buf[bufOff++] & 0xff; - } - - public int read( - byte[] b) - throws IOException - { - return read(b, 0, b.length); - } - - public int read( - byte[] b, - int off, - int len) - throws IOException - { - if (bufOff == maxBuf) - { - if (nextChunk() < 0) - { - return -1; - } - } - - int available = maxBuf - bufOff; - - if (len > available) - { - System.arraycopy(buf, bufOff, b, off, available); - bufOff = maxBuf; - - return available; - } - else - { - System.arraycopy(buf, bufOff, b, off, len); - bufOff += len; - - return len; - } - } - - public long skip( - long n) - throws IOException - { - if (n <= 0) - { - return 0; - } - - int available = maxBuf - bufOff; - - if (n > available) - { - bufOff = maxBuf; - - return available; - } - else - { - bufOff += (int)n; - - return (int)n; - } - } - - public int available() - throws IOException - { - return maxBuf - bufOff; - } - - public void close() - throws IOException - { - super.close(); - } - - public boolean markSupported() - { - return false; - } -} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java deleted file mode 100644 index 17a7b6d..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java +++ /dev/null @@ -1,188 +0,0 @@ -package org.bouncycastle.crypto.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.StreamCipher; - -public class CipherOutputStream - extends FilterOutputStream -{ - private BufferedBlockCipher bufferedBlockCipher; - private StreamCipher streamCipher; - - private byte[] oneByte = new byte[1]; - private byte[] buf; - - /** - * Constructs a CipherOutputStream from an OutputStream and a - * BufferedBlockCipher. - */ - public CipherOutputStream( - OutputStream os, - BufferedBlockCipher cipher) - { - super(os); - this.bufferedBlockCipher = cipher; - this.buf = new byte[cipher.getBlockSize()]; - } - - /** - * Constructs a CipherOutputStream from an OutputStream and a - * BufferedBlockCipher. - */ - public CipherOutputStream( - OutputStream os, - StreamCipher cipher) - { - super(os); - this.streamCipher = cipher; - } - - /** - * Writes the specified byte to this output stream. - * - * @param b the <code>byte</code>. - * @exception java.io.IOException if an I/O error occurs. - */ - public void write( - int b) - throws IOException - { - oneByte[0] = (byte)b; - - if (bufferedBlockCipher != null) - { - int len = bufferedBlockCipher.processBytes(oneByte, 0, 1, buf, 0); - - if (len != 0) - { - out.write(buf, 0, len); - } - } - else - { - out.write(streamCipher.returnByte((byte)b)); - } - } - - /** - * Writes <code>b.length</code> bytes from the specified byte array - * to this output stream. - * <p> - * The <code>write</code> method of - * <code>CipherOutputStream</code> calls the <code>write</code> - * method of three arguments with the three arguments - * <code>b</code>, <code>0</code>, and <code>b.length</code>. - * - * @param b the data. - * @exception java.io.IOException if an I/O error occurs. - * @see #write(byte[], int, int) - */ - public void write( - byte[] b) - throws IOException - { - write(b, 0, b.length); - } - - /** - * Writes <code>len</code> bytes from the specified byte array - * starting at offset <code>off</code> to this output stream. - * - * @param b the data. - * @param off the start offset in the data. - * @param len the number of bytes to write. - * @exception java.io.IOException if an I/O error occurs. - */ - public void write( - byte[] b, - int off, - int len) - throws IOException - { - if (bufferedBlockCipher != null) - { - byte[] buf = new byte[bufferedBlockCipher.getOutputSize(len)]; - - int outLen = bufferedBlockCipher.processBytes(b, off, len, buf, 0); - - if (outLen != 0) - { - out.write(buf, 0, outLen); - } - } - else - { - byte[] buf = new byte[len]; - - streamCipher.processBytes(b, off, len, buf, 0); - - out.write(buf, 0, len); - } - } - - /** - * Flushes this output stream by forcing any buffered output bytes - * that have already been processed by the encapsulated cipher object - * to be written out. - * - * <p> - * Any bytes buffered by the encapsulated cipher - * and waiting to be processed by it will not be written out. For example, - * if the encapsulated cipher is a block cipher, and the total number of - * bytes written using one of the <code>write</code> methods is less than - * the cipher's block size, no bytes will be written out. - * - * @exception java.io.IOException if an I/O error occurs. - */ - public void flush() - throws IOException - { - super.flush(); - } - - /** - * Closes this output stream and releases any system resources - * associated with this stream. - * <p> - * This method invokes the <code>doFinal</code> method of the encapsulated - * cipher object, which causes any bytes buffered by the encapsulated - * cipher to be processed. The result is written out by calling the - * <code>flush</code> method of this output stream. - * <p> - * This method resets the encapsulated cipher object to its initial state - * and calls the <code>close</code> method of the underlying output - * stream. - * - * @exception java.io.IOException if an I/O error occurs. - */ - public void close() - throws IOException - { - try - { - if (bufferedBlockCipher != null) - { - byte[] buf = new byte[bufferedBlockCipher.getOutputSize(0)]; - - int outLen = bufferedBlockCipher.doFinal(buf, 0); - - if (outLen != 0) - { - out.write(buf, 0, outLen); - } - } - } - catch (Exception e) - { - throw new IOException("Error closing stream: " + e.toString()); - } - - flush(); - - super.close(); - } -} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java index 9a6e2e0..fef51fd 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java @@ -29,8 +29,8 @@ public class CCMBlockCipher private int macSize; private CipherParameters keyParam; private byte[] macBlock; - private ByteArrayOutputStream associatedText = new ByteArrayOutputStream(); - private ByteArrayOutputStream data = new ByteArrayOutputStream(); + private ExposedByteArrayOutputStream associatedText = new ExposedByteArrayOutputStream(); + private ExposedByteArrayOutputStream data = new ExposedByteArrayOutputStream(); /** * Basic constructor. @@ -65,6 +65,7 @@ public class CCMBlockCipher { this.forEncryption = forEncryption; + CipherParameters cipherParameters; if (params instanceof AEADParameters) { AEADParameters param = (AEADParameters)params; @@ -72,7 +73,7 @@ public class CCMBlockCipher nonce = param.getNonce(); initialAssociatedText = param.getAssociatedText(); macSize = param.getMacSize() / 8; - keyParam = param.getKey(); + cipherParameters = param.getKey(); } else if (params instanceof ParametersWithIV) { @@ -81,17 +82,25 @@ public class CCMBlockCipher nonce = param.getIV(); initialAssociatedText = null; macSize = macBlock.length / 2; - keyParam = param.getParameters(); + cipherParameters = param.getParameters(); } else { throw new IllegalArgumentException("invalid parameters passed to CCM"); } + // NOTE: Very basic support for key re-use, but no performance gain from it + if (cipherParameters != null) + { + keyParam = cipherParameters; + } + if (nonce == null || nonce.length < 7 || nonce.length > 13) { throw new IllegalArgumentException("nonce must have length from 7 to 13 octets"); } + + reset(); } public String getAlgorithmName() @@ -129,14 +138,11 @@ public class CCMBlockCipher public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException { - byte[] text = data.toByteArray(); - byte[] enc = processPacket(text, 0, text.length); - - System.arraycopy(enc, 0, out, outOff, enc.length); + int len = processPacket(data.getBuffer(), 0, data.size(), out, outOff); reset(); - return enc.length; + return len; } public void reset() @@ -178,9 +184,55 @@ public class CCMBlockCipher return totalData < macSize ? 0 : totalData - macSize; } + /** + * Process a packet of data for either CCM decryption or encryption. + * + * @param in data for processing. + * @param inOff offset at which data starts in the input array. + * @param inLen length of the data in the input array. + * @return a byte array containing the processed input.. + * @throws IllegalStateException if the cipher is not appropriately set up. + * @throws InvalidCipherTextException if the input data is truncated or the mac check fails. + */ public byte[] processPacket(byte[] in, int inOff, int inLen) throws IllegalStateException, InvalidCipherTextException { + byte[] output; + + if (forEncryption) + { + output = new byte[inLen + macSize]; + } + else + { + if (inLen < macSize) + { + throw new InvalidCipherTextException("data too short"); + } + output = new byte[inLen - macSize]; + } + + processPacket(in, inOff, inLen, output, 0); + + return output; + } + + /** + * Process a packet of data for either CCM decryption or encryption. + * + * @param in data for processing. + * @param inOff offset at which data starts in the input array. + * @param inLen length of the data in the input array. + * @param output output array. + * @param outOff offset into output array to start putting processed bytes. + * @return the number of bytes added to output. + * @throws IllegalStateException if the cipher is not appropriately set up. + * @throws InvalidCipherTextException if the input data is truncated or the mac check fails. + * @throws DataLengthException if output buffer too short. + */ + public int processPacket(byte[] in, int inOff, int inLen, byte[] output, int outOff) + throws IllegalStateException, InvalidCipherTextException, DataLengthException + { // TODO: handle null keyParam (e.g. via RepeatedKeySpec) // Need to keep the CTR and CBC Mac parts around and reset if (keyParam == null) @@ -206,42 +258,52 @@ public class CCMBlockCipher BlockCipher ctrCipher = new SICBlockCipher(cipher); ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv)); - int index = inOff; - int outOff = 0; - byte[] output; + int outputLen; + int inIndex = inOff; + int outIndex = outOff; if (forEncryption) { - output = new byte[inLen + macSize]; + outputLen = inLen + macSize; + if (output.length < (outputLen + outOff)) + { + throw new DataLengthException("Output buffer too short."); + } calculateMac(in, inOff, inLen, macBlock); ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0 - while (index < inLen - blockSize) // S1... + while (inIndex < (inOff + inLen - blockSize)) // S1... { - ctrCipher.processBlock(in, index, output, outOff); - outOff += blockSize; - index += blockSize; + ctrCipher.processBlock(in, inIndex, output, outIndex); + outIndex += blockSize; + inIndex += blockSize; } byte[] block = new byte[blockSize]; - System.arraycopy(in, index, block, 0, inLen - index); + System.arraycopy(in, inIndex, block, 0, inLen + inOff - inIndex); ctrCipher.processBlock(block, 0, block, 0); - System.arraycopy(block, 0, output, outOff, inLen - index); + System.arraycopy(block, 0, output, outIndex, inLen + inOff - inIndex); - outOff += inLen - index; - - System.arraycopy(macBlock, 0, output, outOff, output.length - outOff); + System.arraycopy(macBlock, 0, output, outOff + inLen, macSize); } else { - output = new byte[inLen - macSize]; + if (inLen < macSize) + { + throw new InvalidCipherTextException("data too short"); + } + outputLen = inLen - macSize; + if (output.length < (outputLen + outOff)) + { + throw new DataLengthException("Output buffer too short."); + } - System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize); + System.arraycopy(in, inOff + outputLen, macBlock, 0, macSize); ctrCipher.processBlock(macBlock, 0, macBlock, 0); @@ -250,24 +312,24 @@ public class CCMBlockCipher macBlock[i] = 0; } - while (outOff < output.length - blockSize) + while (inIndex < (inOff + outputLen - blockSize)) { - ctrCipher.processBlock(in, index, output, outOff); - outOff += blockSize; - index += blockSize; + ctrCipher.processBlock(in, inIndex, output, outIndex); + outIndex += blockSize; + inIndex += blockSize; } byte[] block = new byte[blockSize]; - System.arraycopy(in, index, block, 0, output.length - outOff); + System.arraycopy(in, inIndex, block, 0, outputLen - (inIndex - inOff)); ctrCipher.processBlock(block, 0, block, 0); - System.arraycopy(block, 0, output, outOff, output.length - outOff); + System.arraycopy(block, 0, output, outIndex, outputLen - (inIndex - inOff)); byte[] calculatedMacBlock = new byte[blockSize]; - calculateMac(output, 0, output.length, calculatedMacBlock); + calculateMac(output, outOff, outputLen, calculatedMacBlock); if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock)) { @@ -275,7 +337,7 @@ public class CCMBlockCipher } } - return output; + return outputLen; } private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock) @@ -344,8 +406,7 @@ public class CCMBlockCipher } if (associatedText.size() > 0) { - byte[] tmp = associatedText.toByteArray(); - cMac.update(tmp, 0, tmp.length); + cMac.update(associatedText.getBuffer(), 0, associatedText.size()); } extra = (extra + textLength) % 16; @@ -375,4 +436,17 @@ public class CCMBlockCipher { return getAssociatedTextLength() > 0; } + + private class ExposedByteArrayOutputStream + extends ByteArrayOutputStream + { + public ExposedByteArrayOutputStream() + { + } + + public byte[] getBuffer() + { + return this.buf; + } + } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java index d0fb9bb..a885169 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java @@ -4,6 +4,7 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; /** * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher. @@ -246,6 +247,16 @@ public class CFBBlockCipher } /** + * Return the current state of the initialisation vector. + * + * @return current IV + */ + public byte[] getCurrentIV() + { + return Arrays.clone(cfbV); + } + + /** * reset the chaining vector back to the IV and reset the underlying * cipher. */ diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java index b8e5b61..5388b40 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java @@ -22,8 +22,9 @@ public class CTSBlockCipher public CTSBlockCipher( BlockCipher cipher) { - if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher)) + if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher) || (cipher instanceof SICBlockCipher)) { + // TODO: This is broken - need to introduce marker interface to differentiate block cipher primitive from mode? throw new IllegalArgumentException("CTSBlockCipher can only accept ECB, or CBC ciphers"); } @@ -72,7 +73,7 @@ public class CTSBlockCipher } /** - * process a single byte, producing an output block if neccessary. + * process a single byte, producing an output block if necessary. * * @param in the input byte. * @param out the space for any output that might be produced. @@ -200,60 +201,81 @@ public class CTSBlockCipher if (forEncryption) { - cipher.processBlock(buf, 0, block, 0); - if (bufOff < blockSize) { throw new DataLengthException("need at least one block of input for CTS"); } - for (int i = bufOff; i != buf.length; i++) - { - buf[i] = block[i - blockSize]; - } - - for (int i = blockSize; i != bufOff; i++) - { - buf[i] ^= block[i - blockSize]; - } + cipher.processBlock(buf, 0, block, 0); - if (cipher instanceof CBCBlockCipher) + if (bufOff > blockSize) { - BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); - - c.processBlock(buf, blockSize, out, outOff); + for (int i = bufOff; i != buf.length; i++) + { + buf[i] = block[i - blockSize]; + } + + for (int i = blockSize; i != bufOff; i++) + { + buf[i] ^= block[i - blockSize]; + } + + if (cipher instanceof CBCBlockCipher) + { + BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); + + c.processBlock(buf, blockSize, out, outOff); + } + else + { + cipher.processBlock(buf, blockSize, out, outOff); + } + + System.arraycopy(block, 0, out, outOff + blockSize, len); } else { - cipher.processBlock(buf, blockSize, out, outOff); + System.arraycopy(block, 0, out, outOff, blockSize); } - - System.arraycopy(block, 0, out, outOff + blockSize, len); } else { + if (bufOff < blockSize) + { + throw new DataLengthException("need at least one block of input for CTS"); + } + byte[] lastBlock = new byte[blockSize]; - if (cipher instanceof CBCBlockCipher) + if (bufOff > blockSize) { - BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); - - c.processBlock(buf, 0, block, 0); + if (cipher instanceof CBCBlockCipher) + { + BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher(); + + c.processBlock(buf, 0, block, 0); + } + else + { + cipher.processBlock(buf, 0, block, 0); + } + + for (int i = blockSize; i != bufOff; i++) + { + lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]); + } + + System.arraycopy(buf, blockSize, block, 0, len); + + cipher.processBlock(block, 0, out, outOff); + System.arraycopy(lastBlock, 0, out, outOff + blockSize, len); } else { cipher.processBlock(buf, 0, block, 0); - } - for (int i = blockSize; i != bufOff; i++) - { - lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]); + System.arraycopy(block, 0, out, outOff, blockSize); } - - System.arraycopy(buf, blockSize, block, 0, len); - - cipher.processBlock(block, 0, out, outOff); - System.arraycopy(lastBlock, 0, out, outOff + blockSize, len); } int offset = bufOff; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java index 4875301..3031a44 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java @@ -5,6 +5,32 @@ import org.bouncycastle.util.Arrays; abstract class GCMUtil { + private static final int E1 = 0xe1000000; + private static final byte E1B = (byte)0xe1; + private static final long E1L = (E1 & 0xFFFFFFFFL) << 24; + + private static int[] generateLookup() + { + int[] lookup = new int[256]; + + for (int c = 0; c < 256; ++c) + { + int v = 0; + for (int i = 7; i >= 0; --i) + { + if ((c & (1 << i)) != 0) + { + v ^= (E1 >>> (7 - i)); + } + } + lookup[c] = v; + } + + return lookup; + } + + private static final int[] LOOKUP = generateLookup(); + static byte[] oneAsBytes() { byte[] tmp = new byte[16]; @@ -15,78 +41,155 @@ abstract class GCMUtil static int[] oneAsInts() { int[] tmp = new int[4]; - tmp[0] = 0x80000000; + tmp[0] = 1 << 31; + return tmp; + } + + static long[] oneAsLongs() + { + long[] tmp = new long[2]; + tmp[0] = 1L << 63; return tmp; } - static byte[] asBytes(int[] ns) + static byte[] asBytes(int[] x) + { + byte[] z = new byte[16]; + Pack.intToBigEndian(x, z, 0); + return z; + } + + static void asBytes(int[] x, byte[] z) + { + Pack.intToBigEndian(x, z, 0); + } + + static byte[] asBytes(long[] x) + { + byte[] z = new byte[16]; + Pack.longToBigEndian(x, z, 0); + return z; + } + + static void asBytes(long[] x, byte[] z) + { + Pack.longToBigEndian(x, z, 0); + } + + static int[] asInts(byte[] x) + { + int[] z = new int[4]; + Pack.bigEndianToInt(x, 0, z); + return z; + } + + static void asInts(byte[] x, int[] z) { - byte[] output = new byte[16]; - Pack.intToBigEndian(ns, output, 0); - return output; + Pack.bigEndianToInt(x, 0, z); } - static int[] asInts(byte[] bs) + static long[] asLongs(byte[] x) { - int[] output = new int[4]; - Pack.bigEndianToInt(bs, 0, output); - return output; + long[] z = new long[2]; + Pack.bigEndianToLong(x, 0, z); + return z; } - static void asInts(byte[] bs, int[] output) + static void asLongs(byte[] x, long[] z) { - Pack.bigEndianToInt(bs, 0, output); + Pack.bigEndianToLong(x, 0, z); } - static void multiply(byte[] block, byte[] val) + static void multiply(byte[] x, byte[] y) { - byte[] tmp = Arrays.clone(block); - byte[] c = new byte[16]; + byte[] r0 = Arrays.clone(x); + byte[] r1 = new byte[16]; for (int i = 0; i < 16; ++i) { - byte bits = val[i]; + byte bits = y[i]; for (int j = 7; j >= 0; --j) { if ((bits & (1 << j)) != 0) { - xor(c, tmp); + xor(r1, r0); } - boolean lsb = (tmp[15] & 1) != 0; - shiftRight(tmp); - if (lsb) + if (shiftRight(r0) != 0) { - // R = new byte[]{ 0xe1, ... }; -// GCMUtil.xor(v, R); - tmp[0] ^= (byte)0xe1; + r0[0] ^= E1B; } } } - System.arraycopy(c, 0, block, 0, 16); + System.arraycopy(r1, 0, x, 0, 16); + } + + static void multiply(int[] x, int[] y) + { + int[] r0 = Arrays.clone(x); + int[] r1 = new int[4]; + + for (int i = 0; i < 4; ++i) + { + int bits = y[i]; + for (int j = 31; j >= 0; --j) + { + if ((bits & (1 << j)) != 0) + { + xor(r1, r0); + } + + if (shiftRight(r0) != 0) + { + r0[0] ^= E1; + } + } + } + + System.arraycopy(r1, 0, x, 0, 4); + } + + static void multiply(long[] x, long[] y) + { + long[] r0 = new long[]{ x[0], x[1] }; + long[] r1 = new long[2]; + + for (int i = 0; i < 2; ++i) + { + long bits = y[i]; + for (int j = 63; j >= 0; --j) + { + if ((bits & (1L << j)) != 0) + { + xor(r1, r0); + } + + if (shiftRight(r0) != 0) + { + r0[0] ^= E1L; + } + } + } + + x[0] = r1[0]; + x[1] = r1[1]; } // P is the value with only bit i=1 set static void multiplyP(int[] x) { - boolean lsb = (x[3] & 1) != 0; - shiftRight(x); - if (lsb) + if (shiftRight(x) != 0) { - // R = new int[]{ 0xe1000000, 0, 0, 0 }; -// xor(v, R); - x[0] ^= 0xe1000000; + x[0] ^= E1; } } - static void multiplyP(int[] x, int[] output) + static void multiplyP(int[] x, int[] y) { - boolean lsb = (x[3] & 1) != 0; - shiftRight(x, output); - if (lsb) + if (shiftRight(x, y) != 0) { - output[0] ^= 0xe1000000; + y[0] ^= E1; } } @@ -98,163 +201,257 @@ abstract class GCMUtil // multiplyP(x); // } - int lsw = x[3]; - shiftRightN(x, 8); - for (int i = 7; i >= 0; --i) - { - if ((lsw & (1 << i)) != 0) - { - x[0] ^= (0xe1000000 >>> (7 - i)); - } - } + int c = shiftRightN(x, 8); + x[0] ^= LOOKUP[c >>> 24]; } - static void multiplyP8(int[] x, int[] output) + static void multiplyP8(int[] x, int[] y) { - int lsw = x[3]; - shiftRightN(x, 8, output); - for (int i = 7; i >= 0; --i) - { - if ((lsw & (1 << i)) != 0) - { - output[0] ^= (0xe1000000 >>> (7 - i)); - } - } + int c = shiftRightN(x, 8, y); + y[0] ^= LOOKUP[c >>> 24]; } - static void shiftRight(byte[] block) + static byte shiftRight(byte[] x) { - int i = 0; - int bit = 0; - for (;;) +// int c = 0; +// for (int i = 0; i < 16; ++i) +// { +// int b = x[i] & 0xff; +// x[i] = (byte)((b >>> 1) | c); +// c = (b & 1) << 7; +// } +// return (byte)c; + + int i = 0, c = 0; + do { - int b = block[i] & 0xff; - block[i] = (byte) ((b >>> 1) | bit); - if (++i == 16) - { - break; - } - bit = (b & 1) << 7; + int b = x[i] & 0xff; + x[i++] = (byte)((b >>> 1) | c); + c = (b & 1) << 7; + b = x[i] & 0xff; + x[i++] = (byte)((b >>> 1) | c); + c = (b & 1) << 7; + b = x[i] & 0xff; + x[i++] = (byte)((b >>> 1) | c); + c = (b & 1) << 7; + b = x[i] & 0xff; + x[i++] = (byte)((b >>> 1) | c); + c = (b & 1) << 7; } + while (i < 16); + return (byte)c; } - static void shiftRight(byte[] block, byte[] output) + static byte shiftRight(byte[] x, byte[] z) { - int i = 0; - int bit = 0; - for (;;) +// int c = 0; +// for (int i = 0; i < 16; ++i) +// { +// int b = x[i] & 0xff; +// z[i] = (byte) ((b >>> 1) | c); +// c = (b & 1) << 7; +// } +// return (byte) c; + + int i = 0, c = 0; + do { - int b = block[i] & 0xff; - output[i] = (byte) ((b >>> 1) | bit); - if (++i == 16) - { - break; - } - bit = (b & 1) << 7; + int b = x[i] & 0xff; + z[i++] = (byte)((b >>> 1) | c); + c = (b & 1) << 7; + b = x[i] & 0xff; + z[i++] = (byte)((b >>> 1) | c); + c = (b & 1) << 7; + b = x[i] & 0xff; + z[i++] = (byte)((b >>> 1) | c); + c = (b & 1) << 7; + b = x[i] & 0xff; + z[i++] = (byte)((b >>> 1) | c); + c = (b & 1) << 7; } + while (i < 16); + return (byte)c; } - static void shiftRight(int[] block) + static int shiftRight(int[] x) { - int i = 0; - int bit = 0; - for (;;) - { - int b = block[i]; - block[i] = (b >>> 1) | bit; - if (++i == 4) - { - break; - } - bit = b << 31; - } +// int c = 0; +// for (int i = 0; i < 4; ++i) +// { +// int b = x[i]; +// x[i] = (b >>> 1) | c; +// c = b << 31; +// } +// return c; + + int b = x[0]; + x[0] = b >>> 1; + int c = b << 31; + b = x[1]; + x[1] = (b >>> 1) | c; + c = b << 31; + b = x[2]; + x[2] = (b >>> 1) | c; + c = b << 31; + b = x[3]; + x[3] = (b >>> 1) | c; + return b << 31; } - static void shiftRight(int[] block, int[] output) + static int shiftRight(int[] x, int[] z) { - int i = 0; - int bit = 0; - for (;;) - { - int b = block[i]; - output[i] = (b >>> 1) | bit; - if (++i == 4) - { - break; - } - bit = b << 31; - } +// int c = 0; +// for (int i = 0; i < 4; ++i) +// { +// int b = x[i]; +// z[i] = (b >>> 1) | c; +// c = b << 31; +// } +// return c; + + int b = x[0]; + z[0] = b >>> 1; + int c = b << 31; + b = x[1]; + z[1] = (b >>> 1) | c; + c = b << 31; + b = x[2]; + z[2] = (b >>> 1) | c; + c = b << 31; + b = x[3]; + z[3] = (b >>> 1) | c; + return b << 31; } - static void shiftRightN(int[] block, int n) + static long shiftRight(long[] x) { - int i = 0; - int bits = 0; - for (;;) - { - int b = block[i]; - block[i] = (b >>> n) | bits; - if (++i == 4) - { - break; - } - bits = b << (32 - n); - } + long b = x[0]; + x[0] = b >>> 1; + long c = b << 63; + b = x[1]; + x[1] = (b >>> 1) | c; + return b << 63; + } + + static long shiftRight(long[] x, long[] z) + { + long b = x[0]; + z[0] = b >>> 1; + long c = b << 63; + b = x[1]; + z[1] = (b >>> 1) | c; + return b << 63; + } + + static int shiftRightN(int[] x, int n) + { +// int c = 0, nInv = 32 - n; +// for (int i = 0; i < 4; ++i) +// { +// int b = x[i]; +// x[i] = (b >>> n) | c; +// c = b << nInv; +// } +// return c; + + int b = x[0], nInv = 32 - n; + x[0] = b >>> n; + int c = b << nInv; + b = x[1]; + x[1] = (b >>> n) | c; + c = b << nInv; + b = x[2]; + x[2] = (b >>> n) | c; + c = b << nInv; + b = x[3]; + x[3] = (b >>> n) | c; + return b << nInv; } - static void shiftRightN(int[] block, int n, int[] output) + static int shiftRightN(int[] x, int n, int[] z) + { +// int c = 0, nInv = 32 - n; +// for (int i = 0; i < 4; ++i) +// { +// int b = x[i]; +// z[i] = (b >>> n) | c; +// c = b << nInv; +// } +// return c; + + int b = x[0], nInv = 32 - n; + z[0] = b >>> n; + int c = b << nInv; + b = x[1]; + z[1] = (b >>> n) | c; + c = b << nInv; + b = x[2]; + z[2] = (b >>> n) | c; + c = b << nInv; + b = x[3]; + z[3] = (b >>> n) | c; + return b << nInv; + } + + static void xor(byte[] x, byte[] y) { int i = 0; - int bits = 0; - for (;;) + do { - int b = block[i]; - output[i] = (b >>> n) | bits; - if (++i == 4) - { - break; - } - bits = b << (32 - n); + x[i] ^= y[i]; ++i; + x[i] ^= y[i]; ++i; + x[i] ^= y[i]; ++i; + x[i] ^= y[i]; ++i; } + while (i < 16); } - static void xor(byte[] block, byte[] val) + static void xor(byte[] x, byte[] y, int yOff, int yLen) { - for (int i = 15; i >= 0; --i) + while (yLen-- > 0) { - block[i] ^= val[i]; + x[yLen] ^= y[yOff + yLen]; } } - static void xor(byte[] block, byte[] val, int off, int len) + static void xor(byte[] x, byte[] y, byte[] z) { - while (len-- > 0) + int i = 0; + do { - block[len] ^= val[off + len]; + z[i] = (byte)(x[i] ^ y[i]); ++i; + z[i] = (byte)(x[i] ^ y[i]); ++i; + z[i] = (byte)(x[i] ^ y[i]); ++i; + z[i] = (byte)(x[i] ^ y[i]); ++i; } + while (i < 16); } - static void xor(byte[] block, byte[] val, byte[] output) + static void xor(int[] x, int[] y) { - for (int i = 15; i >= 0; --i) - { - output[i] = (byte)(block[i] ^ val[i]); - } + x[0] ^= y[0]; + x[1] ^= y[1]; + x[2] ^= y[2]; + x[3] ^= y[3]; } - static void xor(int[] block, int[] val) + static void xor(int[] x, int[] y, int[] z) { - for (int i = 3; i >= 0; --i) - { - block[i] ^= val[i]; - } + z[0] = x[0] ^ y[0]; + z[1] = x[1] ^ y[1]; + z[2] = x[2] ^ y[2]; + z[3] = x[3] ^ y[3]; } - static void xor(int[] block, int[] val, int[] output) + static void xor(long[] x, long[] y) { - for (int i = 3; i >= 0; --i) - { - output[i] = block[i] ^ val[i]; - } + x[0] ^= y[0]; + x[1] ^= y[1]; + } + + static void xor(long[] x, long[] y, long[] z) + { + z[0] = x[0] ^ y[0]; + z[1] = x[1] ^ y[1]; } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java index a051208..6eff4e3 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables1kGCMExponentiator.java @@ -12,31 +12,32 @@ public class Tables1kGCMExponentiator implements GCMExponentiator public void init(byte[] x) { - if (lookupPowX2 != null && Arrays.areEqual(x, (byte[])lookupPowX2.elementAt(0))) + int[] y = GCMUtil.asInts(x); + if (lookupPowX2 != null && Arrays.areEqual(y, (int[])lookupPowX2.elementAt(0))) { return; } lookupPowX2 = new Vector(8); - lookupPowX2.addElement(Arrays.clone(x)); + lookupPowX2.addElement(y); } public void exponentiateX(long pow, byte[] output) { - byte[] y = GCMUtil.oneAsBytes(); + int[] y = GCMUtil.oneAsInts(); int bit = 0; while (pow > 0) { if ((pow & 1L) != 0) { ensureAvailable(bit); - GCMUtil.multiply(y, (byte[])lookupPowX2.elementAt(bit)); + GCMUtil.multiply(y, (int[])lookupPowX2.elementAt(bit)); } ++bit; pow >>>= 1; } - System.arraycopy(y, 0, output, 0, 16); + GCMUtil.asBytes(y, output); } private void ensureAvailable(int bit) @@ -44,7 +45,7 @@ public class Tables1kGCMExponentiator implements GCMExponentiator int count = lookupPowX2.size(); if (count <= bit) { - byte[] tmp = (byte[])lookupPowX2.elementAt(count - 1); + int[] tmp = (int[])lookupPowX2.elementAt(count - 1); do { tmp = Arrays.clone(tmp); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java index 05a1327..9cc6e72 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java @@ -41,7 +41,7 @@ public class ECDomainParameters byte[] seed) { this.curve = curve; - this.G = G; + this.G = G.normalize(); this.n = n; this.h = h; this.seed = seed; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java index 5fbea19..b6b3fb6 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java @@ -12,7 +12,7 @@ public class ECPublicKeyParameters ECDomainParameters params) { super(false, params); - this.Q = Q; + this.Q = Q.normalize(); } public ECPoint getQ() diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSAKCalculator.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSAKCalculator.java new file mode 100644 index 0000000..fced06e --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSAKCalculator.java @@ -0,0 +1,41 @@ +package org.bouncycastle.crypto.signers; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * Interface define calculators of K values for DSA/ECDSA. + */ +public interface DSAKCalculator +{ + /** + * Return true if this calculator is deterministic, false otherwise. + * + * @return true if deterministic, otherwise false. + */ + boolean isDeterministic(); + + /** + * Non-deterministic initialiser. + * + * @param n the order of the DSA group. + * @param random a source of randomness. + */ + void init(BigInteger n, SecureRandom random); + + /** + * Deterministic initialiser. + * + * @param n the order of the DSA group. + * @param d the DSA private value. + * @param message the message being signed. + */ + void init(BigInteger n, BigInteger d, byte[] message); + + /** + * Return the next valid value of K. + * + * @return a K value. + */ + BigInteger nextK(); +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java index a96cef0..292c408 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java @@ -1,5 +1,8 @@ package org.bouncycastle.crypto.signers; +import java.math.BigInteger; +import java.security.SecureRandom; + import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DSA; import org.bouncycastle.crypto.params.DSAKeyParameters; @@ -8,9 +11,6 @@ import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; -import java.math.BigInteger; -import java.security.SecureRandom; - /** * The Digital Signature Algorithm - as described in "Handbook of Applied * Cryptography", pages 452 - 453. @@ -18,9 +18,28 @@ import java.security.SecureRandom; public class DSASigner implements DSA { - DSAKeyParameters key; + private final DSAKCalculator kCalculator; - SecureRandom random; + private DSAKeyParameters key; + private SecureRandom random; + + /** + * Default configuration, random K values. + */ + public DSASigner() + { + this.kCalculator = new RandomDSAKCalculator(); + } + + /** + * Configuration with an alternate, possibly deterministic calculator of K. + * + * @param kCalculator a K value calculator. + */ + public DSASigner(DSAKCalculator kCalculator) + { + this.kCalculator = kCalculator; + } public void init( boolean forSigning, @@ -59,14 +78,17 @@ public class DSASigner { DSAParameters params = key.getParameters(); BigInteger m = calculateE(params.getQ(), message); - BigInteger k; - int qBitLength = params.getQ().bitLength(); - do + if (kCalculator.isDeterministic()) { - k = new BigInteger(qBitLength, random); + kCalculator.init(params.getQ(), ((DSAPrivateKeyParameters)key).getX(), message); } - while (k.compareTo(params.getQ()) >= 0); + else + { + kCalculator.init(params.getQ(), random); + } + + BigInteger k = kCalculator.nextK(); BigInteger r = params.getG().modPow(k, params.getP()).mod(params.getQ()); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java index a80c574..2a1f98e 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java @@ -19,9 +19,28 @@ import org.bouncycastle.math.ec.ECPoint; public class ECDSASigner implements ECConstants, DSA { - ECKeyParameters key; + private final DSAKCalculator kCalculator; - SecureRandom random; + private ECKeyParameters key; + private SecureRandom random; + + /** + * Default configuration, random K values. + */ + public ECDSASigner() + { + this.kCalculator = new RandomDSAKCalculator(); + } + + /** + * Configuration with an alternate, possibly deterministic calculator of K. + * + * @param kCalculator a K value calculator. + */ + public ECDSASigner(DSAKCalculator kCalculator) + { + this.kCalculator = kCalculator; + } public void init( boolean forSigning, @@ -64,24 +83,28 @@ public class ECDSASigner BigInteger r = null; BigInteger s = null; + if (kCalculator.isDeterministic()) + { + kCalculator.init(n, ((ECPrivateKeyParameters)key).getD(), message); + } + else + { + kCalculator.init(n, random); + } + // 5.3.2 do // generate s { BigInteger k = null; - int nBitLength = n.bitLength(); do // generate r { - do - { - k = new BigInteger(nBitLength, random); - } - while (k.equals(ZERO) || k.compareTo(n) >= 0); + k = kCalculator.nextK(); - ECPoint p = key.getParameters().getG().multiply(k); + ECPoint p = key.getParameters().getG().multiply(k).normalize(); // 5.3.3 - BigInteger x = p.getX().toBigInteger(); + BigInteger x = p.getAffineXCoord().toBigInteger(); r = x.mod(n); } @@ -135,7 +158,7 @@ public class ECDSASigner ECPoint G = key.getParameters().getG(); ECPoint Q = ((ECPublicKeyParameters)key).getQ(); - ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2); + ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2).normalize(); // components must be bogus. if (point.isInfinity()) @@ -143,7 +166,7 @@ public class ECDSASigner return false; } - BigInteger v = point.getX().toBigInteger().mod(n); + BigInteger v = point.getAffineXCoord().toBigInteger().mod(n); return v.equals(r); } @@ -153,17 +176,11 @@ public class ECDSASigner int log2n = n.bitLength(); int messageBitLength = message.length * 8; - if (log2n >= messageBitLength) + BigInteger e = new BigInteger(1, message); + if (log2n < messageBitLength) { - return new BigInteger(1, message); - } - else - { - BigInteger trunc = new BigInteger(1, message); - - trunc = trunc.shiftRight(messageBitLength - log2n); - - return trunc; + e = e.shiftRight(messageBitLength - log2n); } + return e; } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java index 7fba55a..18dd84e 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java @@ -61,9 +61,15 @@ public class RSADigestSigner public RSADigestSigner( Digest digest) { - this.digest = digest; + this(digest, (ASN1ObjectIdentifier)oidMap.get(digest.getAlgorithmName())); + } - algId = new AlgorithmIdentifier((ASN1ObjectIdentifier)oidMap.get(digest.getAlgorithmName()), DERNull.INSTANCE); + public RSADigestSigner( + Digest digest, + ASN1ObjectIdentifier digestOid) + { + this.digest = digest; + this.algId = new AlgorithmIdentifier(digestOid, DERNull.INSTANCE); } /** diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java new file mode 100644 index 0000000..bbd8cda --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java @@ -0,0 +1,43 @@ +package org.bouncycastle.crypto.signers; + +import java.math.BigInteger; +import java.security.SecureRandom; + +class RandomDSAKCalculator + implements DSAKCalculator +{ + private static final BigInteger ZERO = BigInteger.valueOf(0); + + private BigInteger q; + private SecureRandom random; + + public boolean isDeterministic() + { + return false; + } + + public void init(BigInteger n, SecureRandom random) + { + this.q = n; + this.random = random; + } + + public void init(BigInteger n, BigInteger d, byte[] message) + { + throw new IllegalStateException("Operation not supported"); + } + + public BigInteger nextK() + { + int qBitLength = q.bitLength(); + + BigInteger k; + do + { + k = new BigInteger(qBitLength, random); + } + while (k.equals(ZERO) || k.compareTo(q) >= 0); + + return k; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java index 394f2c2..d997db7 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java @@ -10,7 +10,6 @@ import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.nist.NISTNamedCurves; // BEGIN android-removed // import org.bouncycastle.asn1.oiw.ElGamalParameter; // END android-removed @@ -20,13 +19,9 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.pkcs.RSAPrivateKey; import org.bouncycastle.asn1.sec.ECPrivateKey; -import org.bouncycastle.asn1.sec.SECNamedCurves; -// BEGIN android-removed -// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; -// END android-removed import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DSAParameter; -import org.bouncycastle.asn1.x9.X962NamedCurves; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; @@ -138,24 +133,7 @@ public class PrivateKeyFactory if (params.isNamedCurve()) { ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); - x9 = X962NamedCurves.getByOID(oid); - - if (x9 == null) - { - x9 = SECNamedCurves.getByOID(oid); - - if (x9 == null) - { - x9 = NISTNamedCurves.getByOID(oid); - - // BEGIN android-removed - // if (x9 == null) - // { - // x9 = TeleTrusTNamedCurves.getByOID(oid); - // } - // END android-removed - } - } + x9 = ECNamedCurveTable.getByOID(oid); } else { diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java index 6a5c88e..7ade197 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java @@ -12,7 +12,6 @@ import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.nist.NISTNamedCurves; // BEGIN android-removed // import org.bouncycastle.asn1.oiw.ElGamalParameter; // END android-removed @@ -20,10 +19,6 @@ import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.DHParameter; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.RSAPublicKey; -import org.bouncycastle.asn1.sec.SECNamedCurves; -// BEGIN android-removed -// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; -// END android-removed import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DSAParameter; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; @@ -31,7 +26,7 @@ import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.asn1.x9.DHDomainParameters; import org.bouncycastle.asn1.x9.DHPublicKey; import org.bouncycastle.asn1.x9.DHValidationParms; -import org.bouncycastle.asn1.x9.X962NamedCurves; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ECPoint; @@ -168,31 +163,13 @@ public class PublicKeyFactory } else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey)) { - X962Parameters params = new X962Parameters( - (ASN1Primitive)algId.getParameters()); + X962Parameters params = X962Parameters.getInstance(algId.getParameters()); X9ECParameters x9; if (params.isNamedCurve()) { ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters(); - x9 = X962NamedCurves.getByOID(oid); - - if (x9 == null) - { - x9 = SECNamedCurves.getByOID(oid); - - if (x9 == null) - { - x9 = NISTNamedCurves.getByOID(oid); - - // BEGIN android-removed - // if (x9 == null) - // { - // x9 = TeleTrusTNamedCurves.getByOID(oid); - // } - // END android-removed - } - } + x9 = ECNamedCurveTable.getByOID(oid); } else { diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceUtils.java b/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceUtils.java new file mode 100644 index 0000000..d7677f3 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceUtils.java @@ -0,0 +1,53 @@ +package org.bouncycastle.jcajce; + +import java.io.IOException; +import java.security.AlgorithmParameters; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Primitive; + +public class JcaJceUtils +{ + private JcaJceUtils() + { + + } + + /** + * Extract an ASN.1 encodable from an AlgorithmParameters object. + * + * @param params the object to get the encoding used to create the return value. + * @return an ASN.1 object representing the primitives making up the params parameter. + * @throws IOException if an encoding cannot be extracted. + */ + public static ASN1Encodable extractParameters(AlgorithmParameters params) + throws IOException + { + // we try ASN.1 explicitly first just in case and then role back to the default. + ASN1Encodable asn1Params; + try + { + asn1Params = ASN1Primitive.fromByteArray(params.getEncoded("ASN.1")); + } + catch (Exception ex) + { + asn1Params = ASN1Primitive.fromByteArray(params.getEncoded()); + } + + return asn1Params; + } + + public static void loadParameters(AlgorithmParameters params, ASN1Encodable sParams) + throws IOException + { + // we try ASN.1 explicitly first just in case and then role back to the default. + try + { + params.init(sParams.toASN1Primitive().getEncoded(), "ASN.1"); + } + catch (Exception ex) + { + params.init(sParams.toASN1Primitive().getEncoded()); + } + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java b/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java deleted file mode 100644 index 235bfe5..0000000 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.bouncycastle.jcajce.io; - -import java.io.IOException; -import java.io.OutputStream; - -import javax.crypto.Mac; - -public class MacOutputStream - extends OutputStream -{ - protected Mac mac; - - public MacOutputStream( - Mac mac) - { - this.mac = mac; - } - - public void write(int b) - throws IOException - { - mac.update((byte)b); - } - - public void write( - byte[] b, - int off, - int len) - throws IOException - { - mac.update(b, off, len); - } - - public byte[] getMac() - { - return mac.doFinal(); - } -} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java index 1c7b679..ceb9292 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java @@ -34,18 +34,26 @@ public class DSA provider.addAlgorithm("Alg.Alias.Signature.RAWDSA", "NONEWITHDSA"); - addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224); - addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256); // BEGIN android-removed - // addSignatureAlgorithm(provider, "SHA384", "DSA", PREFIX + "DSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384); - // addSignatureAlgorithm(provider, "SHA512", "DSA", PREFIX + "DSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512); + // provider.addAlgorithm("Signature.DETDSA", PREFIX + "DSASigner$detDSA"); + // provider.addAlgorithm("Signature.SHA1WITHDETDSA", PREFIX + "DSASigner$detDSA"); + // provider.addAlgorithm("Signature.SHA224WITHDETDSA", PREFIX + "DSASigner$detDSA224"); + // provider.addAlgorithm("Signature.SHA256WITHDETDSA", PREFIX + "DSASigner$detDSA256"); + // provider.addAlgorithm("Signature.SHA384WITHDETDSA", PREFIX + "DSASigner$detDSA384"); + // provider.addAlgorithm("Signature.SHA512WITHDETDSA", PREFIX + "DSASigner$detDSA512"); // END android-removed + addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224); + addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256); + addSignatureAlgorithm(provider, "SHA384", "DSA", PREFIX + "DSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384); + addSignatureAlgorithm(provider, "SHA512", "DSA", PREFIX + "DSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512); + // BEGIN android-added provider.addAlgorithm("Alg.Alias.Signature.DSA", "SHA1withDSA"); // END android-added // BEGIN android-changed provider.addAlgorithm("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA"); + provider.addAlgorithm("Alg.Alias.Signature.SHA1withDSA", "SHA1withDSA"); provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDSA", "SHA1withDSA"); provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA"); provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA"); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java index 780a8ca..43e5861 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java @@ -79,6 +79,13 @@ public class EC provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA"); // BEGIN android-removed // provider.addAlgorithm("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA"); + // + // provider.addAlgorithm("Signature.DETECDSA", PREFIX + "SignatureSpi$ecDetDSA"); + // provider.addAlgorithm("Signature.SHA1WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA"); + // provider.addAlgorithm("Signature.SHA224WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA224"); + // provider.addAlgorithm("Signature.SHA256WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA256"); + // provider.addAlgorithm("Signature.SHA384WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA384"); + // provider.addAlgorithm("Signature.SHA512WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA512"); // END android-removed addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java index c9462a6..f2b5314 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java @@ -50,17 +50,34 @@ public class KeyAgreementSpi private byte[] bigIntToBytes( BigInteger r) { + // + // RFC 2631 (2.1.2) specifies that the secret should be padded with leading zeros if necessary + // must be the same length as p + // + int expectedLength = (p.bitLength() + 7) / 8; + byte[] tmp = r.toByteArray(); - - if (tmp[0] == 0) + + if (tmp.length == expectedLength) + { + return tmp; + } + + if (tmp[0] == 0 && tmp.length == expectedLength + 1) { - byte[] ntmp = new byte[tmp.length - 1]; + byte[] rv = new byte[tmp.length - 1]; - System.arraycopy(tmp, 1, ntmp, 0, ntmp.length); - return ntmp; + System.arraycopy(tmp, 1, rv, 0, rv.length); + return rv; } - - return tmp; + + // tmp must be shorter than expectedLength + // pad to the left with zeros. + byte[] rv = new byte[expectedLength]; + + System.arraycopy(tmp, 0, rv, rv.length - tmp.length, tmp.length); + + return rv; } protected Key engineDoPhase( diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java index a8c9d45..bdda6a2 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java @@ -34,6 +34,9 @@ import org.bouncycastle.crypto.digests.AndroidDigestFactory; // import org.bouncycastle.crypto.digests.SHA512Digest; // END android-removed import org.bouncycastle.crypto.params.ParametersWithRandom; +// BEGIN android-removed +// import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +// END android-removed public class DSASigner extends SignatureSpi @@ -227,6 +230,17 @@ public class DSASigner } } + // BEGIN android-removed + // static public class detDSA + // extends DSASigner + // { + // public detDSA() + // { + // super(new SHA1Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA1Digest()))); + // } + // } + // END android-removed + static public class dsa224 extends DSASigner { @@ -237,7 +251,18 @@ public class DSASigner // END android-changed } } - + + // BEGIN android-removed + // static public class detDSA224 + // extends DSASigner + // { + // public detDSA224() + // { + // super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA224Digest()))); + // } + // } + // END android-removed + static public class dsa256 extends DSASigner { @@ -248,8 +273,17 @@ public class DSASigner // END android-changed } } - + // BEGIN android-removed + // static public class detDSA256 + // extends DSASigner + // { + // public detDSA256() + // { + // super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA256Digest()))); + // } + // } + // // static public class dsa384 // extends DSASigner // { @@ -259,6 +293,15 @@ public class DSASigner // } // } // + // static public class detDSA384 + // extends DSASigner + // { + // public detDSA384() + // { + // super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA384Digest()))); + // } + // } + // // static public class dsa512 // extends DSASigner // { @@ -267,6 +310,15 @@ public class DSASigner // super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner()); // } // } + // + // static public class detDSA512 + // extends DSASigner + // { + // public detDSA512() + // { + // super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA512Digest()))); + // } + // } // END android-removed static public class noneDSA diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java index 3d64c83..45d5b08 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java @@ -13,16 +13,11 @@ import java.util.Enumeration; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERInteger; import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERObjectIdentifier; -// BEGIN android-removed -// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; -// END android-removed import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; @@ -140,8 +135,8 @@ public class BCECPrivateKey this.ecSpec = new ECParameterSpec( ellipticCurve, new ECPoint( - dp.getG().getX().toBigInteger(), - dp.getG().getY().toBigInteger()), + dp.getG().getAffineXCoord().toBigInteger(), + dp.getG().getAffineYCoord().toBigInteger()), dp.getN(), dp.getH().intValue()); } @@ -173,22 +168,16 @@ public class BCECPrivateKey this.ecSpec = new ECParameterSpec( ellipticCurve, new ECPoint( - dp.getG().getX().toBigInteger(), - dp.getG().getY().toBigInteger()), + dp.getG().getAffineXCoord().toBigInteger(), + dp.getG().getAffineYCoord().toBigInteger()), dp.getN(), dp.getH().intValue()); } else { EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed()); - - this.ecSpec = new ECParameterSpec( - ellipticCurve, - new ECPoint( - spec.getG().getX().toBigInteger(), - spec.getG().getY().toBigInteger()), - spec.getN(), - spec.getH().intValue()); + + this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec); } publicKey = getPublicKeyDetails(pubKey); @@ -225,36 +214,16 @@ public class BCECPrivateKey { ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid); - - // BEGIN android-removed - // if (ecP == null) // GOST Curve - // { - // ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid); - // EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed()); - // - // ecSpec = new ECNamedCurveSpec( - // ECGOST3410NamedCurves.getName(oid), - // ellipticCurve, - // new ECPoint( - // gParam.getG().getX().toBigInteger(), - // gParam.getG().getY().toBigInteger()), - // gParam.getN(), - // gParam.getH()); - // } - // else - // END android-removed - { - EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed()); - - ecSpec = new ECNamedCurveSpec( - ECUtil.getCurveName(oid), - ellipticCurve, - new ECPoint( - ecP.getG().getX().toBigInteger(), - ecP.getG().getY().toBigInteger()), - ecP.getN(), - ecP.getH()); - } + EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed()); + + ecSpec = new ECNamedCurveSpec( + ECUtil.getCurveName(oid), + ellipticCurve, + new ECPoint( + ecP.getG().getAffineXCoord().toBigInteger(), + ecP.getG().getAffineYCoord().toBigInteger()), + ecP.getN(), + ecP.getH()); } else if (params.isImplicitlyCA()) { @@ -268,16 +237,16 @@ public class BCECPrivateKey this.ecSpec = new ECParameterSpec( ellipticCurve, new ECPoint( - ecP.getG().getX().toBigInteger(), - ecP.getG().getY().toBigInteger()), + ecP.getG().getAffineXCoord().toBigInteger(), + ecP.getG().getAffineYCoord().toBigInteger()), ecP.getN(), ecP.getH().intValue()); } ASN1Encodable privKey = info.parsePrivateKey(); - if (privKey instanceof DERInteger) + if (privKey instanceof ASN1Integer) { - DERInteger derD = DERInteger.getInstance(privKey); + ASN1Integer derD = ASN1Integer.getInstance(privKey); this.d = derD.getValue(); } @@ -317,11 +286,12 @@ public class BCECPrivateKey if (ecSpec instanceof ECNamedCurveSpec) { - DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName()); + ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName()); if (curveOid == null) // guess it's the OID { - curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); + curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); } + params = new X962Parameters(curveOid); } else if (ecSpec == null) @@ -356,17 +326,7 @@ public class BCECPrivateKey try { - // BEGIN android-removed - // if (algorithm.equals("ECGOST3410")) - // { - // info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive()); - // } - // else - // END android-removed - { - - info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive()); - } + info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure); return info.getEncoded(ASN1Encoding.DER); } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java index 2b61727..0eaae1d 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java @@ -90,7 +90,7 @@ public class BCECPublicKey { org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa(); - q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false); + q = s.getCurve().createPoint(q.getXCoord().toBigInteger(), q.getYCoord().toBigInteger(), false); } this.ecSpec = null; } @@ -188,8 +188,8 @@ public class BCECPublicKey return new ECParameterSpec( ellipticCurve, new ECPoint( - dp.getG().getX().toBigInteger(), - dp.getG().getY().toBigInteger()), + dp.getG().getAffineXCoord().toBigInteger(), + dp.getG().getAffineYCoord().toBigInteger()), dp.getN(), dp.getH().intValue()); } @@ -212,8 +212,8 @@ public class BCECPublicKey ECUtil.getCurveName(oid), ellipticCurve, new ECPoint( - ecP.getG().getX().toBigInteger(), - ecP.getG().getY().toBigInteger()), + ecP.getG().getAffineXCoord().toBigInteger(), + ecP.getG().getAffineYCoord().toBigInteger()), ecP.getN(), ecP.getH()); } @@ -232,8 +232,8 @@ public class BCECPublicKey this.ecSpec = new ECParameterSpec( ellipticCurve, new ECPoint( - ecP.getG().getX().toBigInteger(), - ecP.getG().getY().toBigInteger()), + ecP.getG().getAffineXCoord().toBigInteger(), + ecP.getG().getAffineYCoord().toBigInteger()), ecP.getN(), ecP.getH().intValue()); } @@ -310,8 +310,19 @@ public class BCECPublicKey } ECCurve curve = this.engineGetQ().getCurve(); - ASN1OctetString p = (ASN1OctetString) - new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).toASN1Primitive(); + ASN1OctetString p; + + // stored curve is null if ImplicitlyCa + if (ecSpec == null) + { + p = (ASN1OctetString) + new X9ECPoint(curve.createPoint(this.getQ().getXCoord().toBigInteger(), this.getQ().getYCoord().toBigInteger(), withCompression)).toASN1Primitive(); + } + else + { + p = (ASN1OctetString) + new X9ECPoint(curve.createPoint(this.getQ().getAffineXCoord().toBigInteger(), this.getQ().getAffineYCoord().toBigInteger(), withCompression)).toASN1Primitive(); + } info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); @@ -351,7 +362,7 @@ public class BCECPublicKey public ECPoint getW() { - return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger()); + return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger()); } public org.bouncycastle.math.ec.ECPoint getQ() @@ -360,11 +371,11 @@ public class BCECPublicKey { if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp) { - return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY()); + return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getAffineXCoord(), q.getAffineYCoord()); } else { - return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY()); + return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getAffineXCoord(), q.getAffineYCoord()); } } @@ -392,8 +403,8 @@ public class BCECPublicKey String nl = System.getProperty("line.separator"); buf.append("EC Public Key").append(nl); - buf.append(" X: ").append(this.q.getX().toBigInteger().toString(16)).append(nl); - buf.append(" Y: ").append(this.q.getY().toBigInteger().toString(16)).append(nl); + buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl); + buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl); return buf.toString(); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java index 35a804c..ea36dfd 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java @@ -15,7 +15,7 @@ import javax.crypto.SecretKey; import javax.crypto.ShortBufferException; import javax.crypto.spec.SecretKeySpec; -import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x9.X9IntegerConverter; @@ -84,7 +84,7 @@ public class KeyAgreementSpi private byte[] bigIntToBytes( BigInteger r) { - return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getX())); + return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getAffineXCoord())); } protected KeyAgreementSpi( @@ -197,10 +197,10 @@ public class KeyAgreementSpi // { // throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm); // } - // + // // int keySize = ((Integer)algorithms.get(algorithm)).intValue(); // - // DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret); + // DHKDFParameters params = new DHKDFParameters(new ASN1ObjectIdentifier(algorithm), keySize, secret); // // byte[] keyBytes = new byte[keySize / 8]; // kdf.init(params); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java index c0c825c..42bb895 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java @@ -10,12 +10,7 @@ import java.security.spec.ECGenParameterSpec; import java.util.Hashtable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.nist.NISTNamedCurves; -import org.bouncycastle.asn1.sec.SECNamedCurves; -// BEGIN android-removed -// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; -// END android-removed -import org.bouncycastle.asn1.x9.X962NamedCurves; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; @@ -161,51 +156,23 @@ public abstract class KeyPairGeneratorSpi curveName = ((ECNamedCurveGenParameterSpec)params).getName(); } - X9ECParameters ecP = X962NamedCurves.getByName(curveName); + X9ECParameters ecP = ECNamedCurveTable.getByName(curveName); if (ecP == null) { - ecP = SECNamedCurves.getByName(curveName); - if (ecP == null) + // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug) + try { - ecP = NISTNamedCurves.getByName(curveName); - } - // BEGIN android-removed - // if (ecP == null) - // { - // ecP = TeleTrusTNamedCurves.getByName(curveName); - // } - // END android-removed - if (ecP == null) - { - // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug) - try - { - ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(curveName); - ecP = X962NamedCurves.getByOID(oid); - if (ecP == null) - { - ecP = SECNamedCurves.getByOID(oid); - } - if (ecP == null) - { - ecP = NISTNamedCurves.getByOID(oid); - } - // BEGIN android-removed - // if (ecP == null) - // { - // ecP = TeleTrusTNamedCurves.getByOID(oid); - // } - // END android-removed - if (ecP == null) - { - throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName); - } - } - catch (IllegalArgumentException ex) + ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(curveName); + ecP = ECNamedCurveTable.getByOID(oid); + if (ecP == null) { - throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName); + throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName); } } + catch (IllegalArgumentException ex) + { + throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName); + } } this.ecParams = new ECNamedCurveSpec( diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java index 09cba7c..3757229 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java @@ -31,6 +31,7 @@ import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.signers.ECDSASigner; // BEGIN android-removed // import org.bouncycastle.crypto.signers.ECNRSigner; +// import org.bouncycastle.crypto.signers.HMacDSAKCalculator; // END android-removed import org.bouncycastle.jcajce.provider.asymmetric.util.DSABase; import org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder; @@ -82,6 +83,17 @@ public class SignatureSpi } } + // BEGIN android-removed + // static public class ecDetDSA + // extends SignatureSpi + // { + // public ecDetDSA() + // { + // super(new SHA1Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA1Digest())), new StdDSAEncoder()); + // } + // } + // END android-removed + static public class ecDSAnone extends SignatureSpi { @@ -102,6 +114,17 @@ public class SignatureSpi } } + // BEGIN android-removed + // static public class ecDetDSA224 + // extends SignatureSpi + // { + // public ecDetDSA224() + // { + // super(new SHA224Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA224Digest())), new StdDSAEncoder()); + // } + // } + // END android-removed + static public class ecDSA256 extends SignatureSpi { @@ -113,6 +136,17 @@ public class SignatureSpi } } + // BEGIN android-removed + // static public class ecDetDSA256 + // extends SignatureSpi + // { + // public ecDetDSA256() + // { + // super(new SHA256Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest())), new StdDSAEncoder()); + // } + // } + // END android-removed + static public class ecDSA384 extends SignatureSpi { @@ -124,6 +158,17 @@ public class SignatureSpi } } + // BEGIN android-removed + // static public class ecDetDSA384 + // extends SignatureSpi + // { + // public ecDetDSA384() + // { + // super(new SHA384Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA384Digest())), new StdDSAEncoder()); + // } + // } + // END android-removed + static public class ecDSA512 extends SignatureSpi { @@ -136,6 +181,15 @@ public class SignatureSpi } // BEGIN android-removed + // static public class ecDetDSA512 + // extends SignatureSpi + // { + // public ecDetDSA512() + // { + // super(new SHA512Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA512Digest())), new StdDSAEncoder()); + // } + // } + // // static public class ecDSARipeMD160 // extends SignatureSpi // { diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java index ce0e603..a2114fa 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java @@ -1,6 +1,9 @@ package org.bouncycastle.jcajce.provider.asymmetric.rsa; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OptionalDataException; import java.math.BigInteger; import java.security.interfaces.RSAPublicKey; import java.security.spec.RSAPublicKeySpec; @@ -15,14 +18,18 @@ import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; public class BCRSAPublicKey implements RSAPublicKey { + private static final AlgorithmIdentifier DEFAULT_ALGORITHM_IDENTIFIER = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); + static final long serialVersionUID = 2675817738516720772L; - + private BigInteger modulus; private BigInteger publicExponent; + private transient AlgorithmIdentifier algorithmIdentifier; BCRSAPublicKey( RSAKeyParameters key) { + this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; this.modulus = key.getModulus(); this.publicExponent = key.getExponent(); } @@ -30,6 +37,7 @@ public class BCRSAPublicKey BCRSAPublicKey( RSAPublicKeySpec spec) { + this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; this.modulus = spec.getModulus(); this.publicExponent = spec.getPublicExponent(); } @@ -37,6 +45,7 @@ public class BCRSAPublicKey BCRSAPublicKey( RSAPublicKey key) { + this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; this.modulus = key.getModulus(); this.publicExponent = key.getPublicExponent(); } @@ -44,10 +53,16 @@ public class BCRSAPublicKey BCRSAPublicKey( SubjectPublicKeyInfo info) { + populateFromPublicKeyInfo(info); + } + + private void populateFromPublicKeyInfo(SubjectPublicKeyInfo info) + { try { org.bouncycastle.asn1.pkcs.RSAPublicKey pubKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(info.parsePublicKey()); + this.algorithmIdentifier = info.getAlgorithm(); this.modulus = pubKey.getModulus(); this.publicExponent = pubKey.getPublicExponent(); } @@ -89,7 +104,7 @@ public class BCRSAPublicKey public byte[] getEncoded() { - return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent())); + return KeyUtil.getEncodedSubjectPublicKeyInfo(algorithmIdentifier, new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent())); } public int hashCode() @@ -126,4 +141,32 @@ public class BCRSAPublicKey return buf.toString(); } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + try + { + algorithmIdentifier = AlgorithmIdentifier.getInstance(in.readObject()); + } + catch (OptionalDataException e) + { + algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; + } + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + if (!algorithmIdentifier.equals(DEFAULT_ALGORITHM_IDENTIFIER)) + { + out.writeObject(algorithmIdentifier.getEncoded()); + } + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java index d4065ac..5eea1b9 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java @@ -74,8 +74,8 @@ public class EC5Util ((ECNamedCurveParameterSpec)spec).getName(), ellipticCurve, new ECPoint( - spec.getG().getX().toBigInteger(), - spec.getG().getY().toBigInteger()), + spec.getG().getAffineXCoord().toBigInteger(), + spec.getG().getAffineYCoord().toBigInteger()), spec.getN(), spec.getH()); } @@ -84,8 +84,8 @@ public class EC5Util return new ECParameterSpec( ellipticCurve, new ECPoint( - spec.getG().getX().toBigInteger(), - spec.getG().getY().toBigInteger()), + spec.getG().getAffineXCoord().toBigInteger(), + spec.getG().getAffineYCoord().toBigInteger()), spec.getN(), spec.getH().intValue()); } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java index 1888328..32e595c 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java @@ -31,7 +31,7 @@ import org.bouncycastle.asn1.x509.X509Extension; * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer * (critical) */ -class X509CRLEntryObject extends X509CRLEntry +public class X509CRLEntryObject extends X509CRLEntry { private TBSCertList.CRLEntry c; @@ -39,7 +39,7 @@ class X509CRLEntryObject extends X509CRLEntry private int hashValue; private boolean isHashValueSet; - public X509CRLEntryObject(TBSCertList.CRLEntry c) + protected X509CRLEntryObject(TBSCertList.CRLEntry c) { this.c = c; this.certificateIssuer = null; @@ -62,7 +62,7 @@ class X509CRLEntryObject extends X509CRLEntry * @param previousCertificateIssuer * Certificate issuer of the previous CRLEntry. */ - public X509CRLEntryObject( + protected X509CRLEntryObject( TBSCertList.CRLEntry c, boolean isIndirect, X500Name previousCertificateIssuer) @@ -211,6 +211,23 @@ class X509CRLEntryObject extends X509CRLEntry return hashValue; } + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof X509CRLEntryObject) + { + X509CRLEntryObject other = (X509CRLEntryObject)o; + + return this.c.equals(other.c); + } + + return super.equals(this); + } + public byte[] getEncoded() throws CRLException { diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java index 2fc0826..c7d0402 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java @@ -54,13 +54,15 @@ import org.bouncycastle.util.encoders.Hex; * Delta CRL Indicator (critical) * Issuing Distribution Point (critical) */ -class X509CRLObject +public class X509CRLObject extends X509CRL { private CertificateList c; private String sigAlgName; private byte[] sigAlgParams; private boolean isIndirect; + private boolean isHashCodeSet = false; + private int hashCodeValue; static boolean isIndirectCRL(X509CRL crl) throws CRLException @@ -78,7 +80,7 @@ class X509CRLObject } } - public X509CRLObject( + protected X509CRLObject( CertificateList c) throws CRLException { @@ -522,19 +524,21 @@ class X509CRLObject throw new RuntimeException("X.509 CRL used with non X.509 Cert"); } - TBSCertList.CRLEntry[] certs = c.getRevokedCertificates(); + Enumeration certs = c.getRevokedCertificateEnumeration(); X500Name caName = c.getIssuer(); - if (certs != null) + if (certs.hasMoreElements()) { BigInteger serial = ((X509Certificate)cert).getSerialNumber(); - for (int i = 0; i < certs.length; i++) + while (certs.hasMoreElements()) { - if (isIndirect && certs[i].hasExtensions()) + TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement()); + + if (isIndirect && entry.hasExtensions()) { - Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer); + Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); if (currentCaName != null) { @@ -542,7 +546,7 @@ class X509CRLObject } } - if (certs[i].getUserCertificate().getValue().equals(serial)) + if (entry.getUserCertificate().getValue().equals(serial)) { X500Name issuer; @@ -574,5 +578,50 @@ class X509CRLObject return false; } + + public boolean equals(Object other) + { + if (this == other) + { + return true; + } + + if (!(other instanceof X509CRL)) + { + return false; + } + + if (other instanceof X509CRLObject) + { + X509CRLObject crlObject = (X509CRLObject)other; + + if (isHashCodeSet) + { + boolean otherIsHashCodeSet = crlObject.isHashCodeSet; + if (otherIsHashCodeSet) + { + if (crlObject.hashCodeValue != hashCodeValue) + { + return false; + } + } + } + + return this.c.equals(crlObject.c); + } + + return super.equals(other); + } + + public int hashCode() + { + if (!isHashCodeSet) + { + isHashCodeSet = true; + hashCodeValue = super.hashCode(); + } + + return hashCodeValue; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java index df5d41a..c7502c7 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java @@ -193,7 +193,6 @@ public class SHA1 provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACSHA1", PREFIX + "$PBEWithMacKeyFactory"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1", PREFIX + "$PBKDF2WithHmacSHA1UTF8"); - provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2WithHmacSHA1"); provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WithHmacSHA1AndUTF8", "PBKDF2WithHmacSHA1"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT"); } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java index 0d4f0ad..24dac19 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java @@ -6,6 +6,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyStore; import java.security.KeyStore.LoadStoreParameter; @@ -24,13 +26,18 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.util.Collections; import java.util.Date; import java.util.Enumeration; +import java.util.HashMap; import java.util.Hashtable; +import java.util.Map; import java.util.Vector; import javax.crypto.Cipher; import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; @@ -54,6 +61,12 @@ import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DEROutputStream; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERSet; +// BEGIN android-removed +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +// import org.bouncycastle.asn1.cryptopro.GOST28147Parameters; +// END android-removed +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; import org.bouncycastle.asn1.pkcs.AuthenticatedSafe; import org.bouncycastle.asn1.pkcs.CertBag; import org.bouncycastle.asn1.pkcs.ContentInfo; @@ -75,12 +88,16 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.jcajce.provider.config.PKCS12StoreParameter; import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey; -import org.bouncycastle.jcajce.provider.util.SecretKeyUtil; +// BEGIN android-removed +// import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; +// END android-removed +import org.bouncycastle.jcajce.spec.PBKDF2KeySpec; import org.bouncycastle.jce.interfaces.BCKeyStore; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.JDKPKCS12StoreParameter; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Integers; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; @@ -92,6 +109,7 @@ public class PKCS12KeyStoreSpi private static final int MIN_ITERATIONS = 1024; private static final Provider bcProvider = new BouncyCastleProvider(); + private static final DefaultSecretKeyProvider keySizeProvider = new DefaultSecretKeyProvider(); private IgnoresCaseHashtable keys = new IgnoresCaseHashtable(); private Hashtable localIds = new Hashtable(); @@ -593,16 +611,8 @@ public class PKCS12KeyStoreSpi } else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2)) { - PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters()); - PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters()); - SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg.getKeyDerivationFunc().getAlgorithm().getId(), bcProvider); - - SecretKey k = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), SecretKeyUtil.getKeySize(alg.getEncryptionScheme().getAlgorithm()))); - - Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId(), bcProvider); - - cipher.init(Cipher.UNWRAP_MODE, k, new IvParameterSpec(ASN1OctetString.getInstance(alg.getEncryptionScheme().getParameters()).getOctets())); + Cipher cipher = createCipher(Cipher.UNWRAP_MODE, password, algId); // we pass "" as the key algorithm type as it is unknown at this point return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY); @@ -656,31 +666,92 @@ public class PKCS12KeyStoreSpi byte[] data) throws IOException { - String algorithm = algId.getAlgorithm().getId(); - PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters()); - PBEKeySpec pbeSpec = new PBEKeySpec(password); + ASN1ObjectIdentifier algorithm = algId.getAlgorithm(); - try + if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds)) { - SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, bcProvider); - PBEParameterSpec defParams = new PBEParameterSpec( - pbeParams.getIV(), - pbeParams.getIterations().intValue()); - BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec); + PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters()); + PBEKeySpec pbeSpec = new PBEKeySpec(password); - key.setTryWrongPKCS12Zero(wrongPKCS12Zero); + try + { + SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm.getId(), bcProvider); + PBEParameterSpec defParams = new PBEParameterSpec( + pbeParams.getIV(), + pbeParams.getIterations().intValue()); + BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec); - Cipher cipher = Cipher.getInstance(algorithm, bcProvider); - int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; - cipher.init(mode, key, defParams); - return cipher.doFinal(data); + key.setTryWrongPKCS12Zero(wrongPKCS12Zero); + + Cipher cipher = Cipher.getInstance(algorithm.getId(), bcProvider); + int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; + cipher.init(mode, key, defParams); + return cipher.doFinal(data); + } + catch (Exception e) + { + throw new IOException("exception decrypting data - " + e.toString()); + } } - catch (Exception e) + else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2)) { - throw new IOException("exception decrypting data - " + e.toString()); + try + { + Cipher cipher = createCipher(Cipher.DECRYPT_MODE, password, algId); + + return cipher.doFinal(data); + } + catch (Exception e) + { + throw new IOException("exception decrypting data - " + e.toString()); + } + } + else + { + throw new IOException("unknown PBE algorithm: " + algorithm); } } + private Cipher createCipher(int mode, char[] password, AlgorithmIdentifier algId) + throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException + { + PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters()); + PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters()); + AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme()); + + SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg.getKeyDerivationFunc().getAlgorithm().getId(), bcProvider); + SecretKey key; + + if (func.isDefaultPrf()) + { + key = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme))); + } + else + { + key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme), func.getPrf())); + } + + Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId()); + + AlgorithmIdentifier encryptionAlg = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme()); + + ASN1Encodable encParams = alg.getEncryptionScheme().getParameters(); + if (encParams instanceof ASN1OctetString) + { + cipher.init(mode, key, new IvParameterSpec(ASN1OctetString.getInstance(encParams).getOctets())); + } + // BEGIN android-removed + // else + // { + // // TODO: at the moment it's just GOST, but... + // GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams); + // + // cipher.init(mode, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV())); + // } + // END android-removed + return cipher; + } + public void engineLoad( InputStream stream, char[] password) @@ -1673,4 +1744,45 @@ public class PKCS12KeyStoreSpi return orig.elements(); } } + + private static class DefaultSecretKeyProvider + { + private final Map KEY_SIZES; + + DefaultSecretKeyProvider() + { + Map keySizes = new HashMap(); + + keySizes.put(new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"), Integers.valueOf(128)); + + keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192)); + + keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128)); + keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192)); + keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256)); + + keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128)); + keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192)); + keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256)); + + // BEGIN android-removed + // keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256)); + // END android-removed + + KEY_SIZES = Collections.unmodifiableMap(keySizes); + } + + public int getKeySize(AlgorithmIdentifier algorithmIdentifier) + { + // TODO: not all ciphers/oid relationships are this simple. + Integer keySize = (Integer)KEY_SIZES.get(algorithmIdentifier.getAlgorithm()); + + if (keySize != null) + { + return keySize.intValue(); + } + + return -1; + } + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java index f561b8a..500bf2d 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java @@ -1,17 +1,22 @@ package org.bouncycastle.jcajce.provider.symmetric; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; // BEGIN android-removed // import java.security.AlgorithmParameters; // import java.security.InvalidAlgorithmParameterException; // END android-removed import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + // BEGIN android-removed -// import java.security.spec.AlgorithmParameterSpec; -// // import javax.crypto.spec.IvParameterSpec; // END android-removed import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +import org.bouncycastle.asn1.cms.GCMParameters; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; @@ -20,6 +25,7 @@ import org.bouncycastle.crypto.engines.AESFastEngine; import org.bouncycastle.crypto.engines.AESWrapEngine; // BEGIN android-removed // import org.bouncycastle.crypto.engines.RFC3211WrapEngine; +// import org.bouncycastle.crypto.generators.Poly1305KeyGenerator; // import org.bouncycastle.crypto.macs.CMac; // import org.bouncycastle.crypto.macs.GMac; // END android-removed @@ -31,6 +37,7 @@ import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; // BEGIN android-removed // import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator; // END android-removed +import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters; import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher; import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; // BEGIN android-removed @@ -43,9 +50,12 @@ import org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory; // BEGIN android-removed // import org.bouncycastle.jce.provider.BouncyCastleProvider; // END android-removed +import org.bouncycastle.util.Integers; public final class AES { + private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec"); + private AES() { } @@ -92,6 +102,15 @@ public final class AES } } + static public class GCM + extends BaseBlockCipher + { + public GCM() + { + super(new GCMBlockCipher(new AESFastEngine())); + } + } + // BEGIN android-removed // public static class AESCMAC // extends BaseMac @@ -110,6 +129,24 @@ public final class AES // super(new GMac(new GCMBlockCipher(new AESFastEngine()))); // } // } + // + // public static class Poly1305 + // extends BaseMac + // { + // public Poly1305() + // { + // super(new org.bouncycastle.crypto.macs.Poly1305(new AESFastEngine())); + // } + // } + // + // public static class Poly1305KeyGen + // extends BaseKeyGenerator + // { + // public Poly1305KeyGen() + // { + // super("Poly1305-AES", 256, new Poly1305KeyGenerator()); + // } + // } // END android-removed static public class Wrap @@ -345,6 +382,95 @@ public final class AES } } + public static class AlgParamsGCM + extends BaseAlgorithmParameters + { + private GCMParameters gcmParams; + + protected void engineInit(AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException + { + if (gcmSpecClass != null) + { + try + { + Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]); + Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]); + + + gcmParams = new GCMParameters((byte[])iv.invoke(paramSpec, new Object[0]), ((Integer)tLen.invoke(paramSpec, new Object[0])).intValue()); + } + catch (Exception e) + { + throw new InvalidParameterSpecException("Cannot process GCMParameterSpec."); + } + } + } + + protected void engineInit(byte[] params) + throws IOException + { + gcmParams = GCMParameters.getInstance(params); + } + + protected void engineInit(byte[] params, String format) + throws IOException + { + if (!isASN1FormatString(format)) + { + throw new IOException("unknown format specified"); + } + + gcmParams = GCMParameters.getInstance(params); + } + + protected byte[] engineGetEncoded() + throws IOException + { + return gcmParams.getEncoded(); + } + + protected byte[] engineGetEncoded(String format) + throws IOException + { + if (!isASN1FormatString(format)) + { + throw new IOException("unknown format specified"); + } + + return gcmParams.getEncoded(); + } + + protected String engineToString() + { + return "GCM"; + } + + protected AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException + { + if (gcmSpecClass != null) + { + try + { + Constructor constructor = gcmSpecClass.getConstructor(new Class[] { byte[].class, Integer.class }); + + return (AlgorithmParameterSpec)constructor.newInstance(new Object[] { gcmParams.getNonce(), Integers.valueOf(gcmParams.getIcvLen()) }); + } + catch (NoSuchMethodException e) + { + throw new InvalidParameterSpecException("no constructor found!"); // should never happen + } + catch (Exception e) + { + throw new InvalidParameterSpecException("construction failed: " + e.getMessage()); // should never happen + } + } + + throw new InvalidParameterSpecException("unknown parameter spec: " + paramSpec.getName()); + } + } + public static class Mappings extends SymmetricAlgorithmProvider { @@ -373,6 +499,11 @@ public final class AES provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES"); + provider.addAlgorithm("AlgorithmParameters.GCM", PREFIX + "$AlgParamsGCM"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_GCM, "GCM"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_GCM, "GCM"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_GCM, "GCM"); + // BEGIN android-removed // provider.addAlgorithm("AlgorithmParameterGenerator.AES", PREFIX + "$AlgParamGen"); // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES"); @@ -409,6 +540,11 @@ public final class AES // provider.addAlgorithm("Cipher.AESRFC3211WRAP", PREFIX + "$RFC3211Wrap"); // END android-removed + provider.addAlgorithm("Cipher.GCM", PREFIX + "$GCM"); + provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_GCM, "GCM"); + provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_GCM, "GCM"); + provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_GCM, "GCM"); + provider.addAlgorithm("KeyGenerator.AES", PREFIX + "$KeyGen"); // BEGIN android-removed // provider.addAlgorithm("KeyGenerator." + wrongAES128, PREFIX + "$KeyGen128"); @@ -513,7 +649,22 @@ public final class AES // BEGIN android-removed // addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128"); + // addPoly1305Algorithm(provider, "AES", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen"); // END android-removed } } + + private static Class lookup(String className) + { + try + { + Class def = AES.class.getClassLoader().loadClass(className); + + return def; + } + catch (Exception e) + { + return null; + } + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java index d96d5e6..fc34865 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java @@ -19,5 +19,18 @@ abstract class SymmetricAlgorithmProvider // provider.addAlgorithm("KeyGenerator." + algorithm + "-GMAC", keyGeneratorClassName); // provider.addAlgorithm("Alg.Alias.KeyGenerator." + algorithm + "GMAC", algorithm + "-GMAC"); // } + // + // protected void addPoly1305Algorithm(ConfigurableProvider provider, + // String algorithm, + // String algorithmClassName, + // String keyGeneratorClassName) + // { + // provider.addAlgorithm("Mac.POLY1305-" + algorithm, algorithmClassName); + // provider.addAlgorithm("Alg.Alias.Mac.POLY1305" + algorithm, "POLY1305-" + algorithm); + // + // provider.addAlgorithm("KeyGenerator.POLY1305-" + algorithm, keyGeneratorClassName); + // provider.addAlgorithm("Alg.Alias.KeyGenerator.POLY1305" + algorithm, "POLY1305-" + algorithm); + // } // END android-removed + } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java index dafdc39..e2b2efd 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java @@ -6,6 +6,7 @@ package org.bouncycastle.jcajce.provider.symmetric; // END android-removed import org.bouncycastle.crypto.engines.TwofishEngine; // BEGIN android-removed +// import org.bouncycastle.crypto.generators.Poly1305KeyGenerator; // import org.bouncycastle.crypto.macs.GMac; // END android-removed import org.bouncycastle.crypto.modes.CBCBlockCipher; @@ -61,6 +62,24 @@ public final class Twofish // super(new GMac(new GCMBlockCipher(new TwofishEngine()))); // } // } + // + // public static class Poly1305 + // extends BaseMac + // { + // public Poly1305() + // { + // super(new org.bouncycastle.crypto.macs.Poly1305(new TwofishEngine())); + // } + // } + // + // public static class Poly1305KeyGen + // extends BaseKeyGenerator + // { + // public Poly1305KeyGen() + // { + // super("Poly1305-Twofish", 256, new Poly1305KeyGenerator()); + // } + // } // END android-removed /** @@ -122,6 +141,7 @@ public final class Twofish // BEGIN android-removed // addGMacAlgorithm(provider, "Twofish", PREFIX + "$GMAC", PREFIX + "$KeyGen"); + // addPoly1305Algorithm(provider, "Twofish", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen"); // END android-removed } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java index d342775..90d98b2 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java @@ -1,5 +1,7 @@ package org.bouncycastle.jcajce.provider.symmetric.util; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -22,6 +24,7 @@ import javax.crypto.spec.PBEParameterSpec; // import javax.crypto.spec.RC5ParameterSpec; // END android-removed +import org.bouncycastle.asn1.cms.GCMParameters; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherParameters; @@ -35,6 +38,7 @@ import org.bouncycastle.crypto.modes.CFBBlockCipher; import org.bouncycastle.crypto.modes.CTSBlockCipher; // BEGIN android-removed // import org.bouncycastle.crypto.modes.EAXBlockCipher; +// import org.bouncycastle.crypto.modes.GCFBBlockCipher; // END android-removed import org.bouncycastle.crypto.modes.GCMBlockCipher; // BEGIN android-removed @@ -54,6 +58,7 @@ import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.bouncycastle.crypto.paddings.TBCPadding; import org.bouncycastle.crypto.paddings.X923Padding; import org.bouncycastle.crypto.paddings.ZeroBytePadding; +import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.crypto.params.ParametersWithRandom; @@ -63,18 +68,18 @@ import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.params.RC2Parameters; // BEGIN android-removed // import org.bouncycastle.crypto.params.RC5Parameters; +// import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; +// import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec; // END android-removed import org.bouncycastle.jce.provider.BouncyCastleProvider; -// BEGIN android-removed -// import org.bouncycastle.jce.spec.GOST28147ParameterSpec; -// END android-removed -import org.bouncycastle.jce.spec.RepeatedSecretKeySpec; import org.bouncycastle.util.Strings; public class BaseBlockCipher extends BaseWrapCipher implements PBE { + private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec"); + // // specs we can handle. // @@ -87,14 +92,16 @@ public class BaseBlockCipher IvParameterSpec.class, PBEParameterSpec.class, // BEGIN android-removed - // GOST28147ParameterSpec.class + // GOST28147ParameterSpec.class, // END android-removed + gcmSpecClass }; private BlockCipher baseEngine; private BlockCipherProvider engineProvider; private GenericBlockCipher cipher; private ParametersWithIV ivParam; + private AEADParameters aeadParams; private int ivLength = 0; @@ -105,6 +112,20 @@ public class BaseBlockCipher private String modeName = null; + private static Class lookup(String className) + { + try + { + Class def = BaseBlockCipher.class.getClassLoader().loadClass(className); + + return def; + } + catch (Exception e) + { + return null; + } + } + protected BaseBlockCipher( BlockCipher engine) { @@ -123,6 +144,14 @@ public class BaseBlockCipher } protected BaseBlockCipher( + AEADBlockCipher engine) + { + baseEngine = engine.getUnderlyingCipher(); + ivLength = baseEngine.getBlockSize(); + cipher = new AEADGenericBlockCipher(engine); + } + + protected BaseBlockCipher( org.bouncycastle.crypto.BlockCipher engine, int ivLength) { @@ -199,6 +228,18 @@ public class BaseBlockCipher throw new RuntimeException(e.toString()); } } + else if (aeadParams != null) + { + try + { + engineParams = AlgorithmParameters.getInstance("GCM", BouncyCastleProvider.PROVIDER_NAME); + engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize()).getEncoded()); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } + } } return engineParams; @@ -257,7 +298,7 @@ public class BaseBlockCipher // else if (modeName.startsWith("PGP")) // { // boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV"); - + // // ivLength = baseEngine.getBlockSize(); // cipher = new BufferedGenericBlockCipher( // new PGPCFBBlockCipher(baseEngine, inlineIV)); @@ -268,17 +309,17 @@ public class BaseBlockCipher // cipher = new BufferedGenericBlockCipher( // new OpenPGPCFBBlockCipher(baseEngine)); // } + // else if (modeName.startsWith("SIC")) + // { + // ivLength = baseEngine.getBlockSize(); + // if (ivLength < 16) + // { + // throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)"); + // } + // cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( + // new SICBlockCipher(baseEngine))); + // } // END android-removed - else if (modeName.startsWith("SIC")) - { - ivLength = baseEngine.getBlockSize(); - if (ivLength < 16) - { - throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)"); - } - cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( - new SICBlockCipher(baseEngine))); - } else if (modeName.startsWith("CTR")) { ivLength = baseEngine.getBlockSize(); @@ -292,6 +333,12 @@ public class BaseBlockCipher // cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( // new GOFBBlockCipher(baseEngine))); // } + // else if (modeName.startsWith("GCFB")) + // { + // ivLength = baseEngine.getBlockSize(); + // cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( + // new GCFBBlockCipher(baseEngine))); + // } // END android-removed else if (modeName.startsWith("CTS")) { @@ -300,7 +347,7 @@ public class BaseBlockCipher } else if (modeName.startsWith("CCM")) { - ivLength = baseEngine.getBlockSize(); + ivLength = 13; // CCM nonce 7..13 bytes cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine)); } // BEGIN android-removed @@ -308,7 +355,8 @@ public class BaseBlockCipher // { // if (engineProvider != null) // { - // ivLength = baseEngine.getBlockSize(); + // // Nonce restricted to max 120 bits over 128 bit block cipher since draft-irtf-cfrg-ocb-03 + // ivLength = 15; // cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get())); // } // else @@ -401,6 +449,7 @@ public class BaseBlockCipher this.pbeSpec = null; this.pbeAlgorithm = null; this.engineParams = null; + this.aeadParams = null; // // basic key check @@ -443,6 +492,20 @@ public class BaseBlockCipher param = new ParametersWithIV(param, iv.getIV()); } + // BEGIN android-removed + // else if (params instanceof GOST28147ParameterSpec) + // { + // // need to pick up IV and SBox. + // GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params; + // + // param = new ParametersWithSBox(param, gost28147Param.getSbox()); + // + // if (gost28147Param.getIV() != null && ivLength != 0) + // { + // param = new ParametersWithIV(param, gost28147Param.getIV()); + // } + // } + // END android-removed } else if (params instanceof PBEParameterSpec) { @@ -474,12 +537,14 @@ public class BaseBlockCipher throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long."); } - if (key instanceof RepeatedSecretKeySpec) - { - param = new ParametersWithIV(null, p.getIV()); - ivParam = (ParametersWithIV)param; - } - else + // BEGIN android-removed + // if (key instanceof RepeatedSecretKeySpec) + // { + // param = new ParametersWithIV(null, p.getIV()); + // ivParam = (ParametersWithIV)param; + // } + // else + // END android-removed { param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV()); ivParam = (ParametersWithIV)param; @@ -554,12 +619,40 @@ public class BaseBlockCipher // } // } // END android-removed + else if (gcmSpecClass != null && gcmSpecClass.isInstance(params)) + { + if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher)) + { + throw new InvalidAlgorithmParameterException("GCMParameterSpec can only be used with AEAD modes."); + } + + try + { + Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]); + Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]); + + // BEGIN android-removed + // if (key instanceof RepeatedSecretKeySpec) + // { + // param = aeadParams = new AEADParameters(null, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0])); + // } + // else + // END android-removed + { + param = aeadParams = new AEADParameters(new KeyParameter(key.getEncoded()), ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0])); + } + } + catch (Exception e) + { + throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec."); + } + } else { throw new InvalidAlgorithmParameterException("unknown parameter type."); } - if ((ivLength != 0) && !(param instanceof ParametersWithIV)) + if ((ivLength != 0) && !(param instanceof ParametersWithIV) && !(param instanceof AEADParameters)) { SecureRandom ivRandom = random; @@ -622,6 +715,11 @@ public class BaseBlockCipher { for (int i = 0; i != availableSpecs.length; i++) { + if (availableSpecs[i] == null) + { + continue; + } + try { paramSpec = params.getParameterSpec(availableSpecs[i]); @@ -660,6 +758,18 @@ public class BaseBlockCipher } } + protected void engineUpdateAAD(byte[] input, int offset, int length) + { + cipher.updateAAD(input, offset, length); + } + + protected void engineUpdateAAD(ByteBuffer bytebuffer) + { + int offset = bytebuffer.arrayOffset() + bytebuffer.position(); + int length = bytebuffer.limit() - bytebuffer.position(); + engineUpdateAAD(bytebuffer.array(), offset, length); + } + protected byte[] engineUpdate( byte[] input, int inputOffset, @@ -811,6 +921,8 @@ public class BaseBlockCipher public int getUpdateOutputSize(int len); + public void updateAAD(byte[] input, int offset, int length); + public int processByte(byte in, byte[] out, int outOff) throws DataLengthException; @@ -872,6 +984,11 @@ public class BaseBlockCipher return cipher.getUpdateOutputSize(len); } + public void updateAAD(byte[] input, int offset, int length) + { + throw new UnsupportedOperationException("AAD is not supported in the current mode."); + } + public int processByte(byte in, byte[] out, int outOff) throws DataLengthException { return cipher.processByte(in, out, outOff); @@ -929,6 +1046,11 @@ public class BaseBlockCipher return cipher.getUpdateOutputSize(len); } + public void updateAAD(byte[] input, int offset, int length) + { + cipher.processAADBytes(input, offset, length); + } + public int processByte(byte in, byte[] out, int outOff) throws DataLengthException { return cipher.processByte(in, out, outOff); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java index 442dcdd..d014972 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java @@ -4,6 +4,9 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.spec.AlgorithmParameterSpec; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; import javax.crypto.MacSpi; import javax.crypto.spec.IvParameterSpec; @@ -13,6 +16,10 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; +// BEGIN android-removed +// import org.bouncycastle.crypto.params.SkeinParameters; +// import org.bouncycastle.jcajce.spec.SkeinParameterSpec; +// END android-removed public class BaseMac extends MacSpi implements PBE @@ -74,6 +81,12 @@ public class BaseMac { param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV()); } + // BEGIN android-removed + // else if (params instanceof SkeinParameterSpec) + // { + // param = new SkeinParameters.Builder(copyMap(((SkeinParameterSpec)params).getParameters())).setKey(key.getEncoded()).build(); + // } + // END android-removed else if (params == null) { param = new KeyParameter(key.getEncoded()); @@ -118,4 +131,18 @@ public class BaseMac return out; } + + private static Hashtable copyMap(Map paramsMap) + { + Hashtable newTable = new Hashtable(); + + Iterator keys = paramsMap.keySet().iterator(); + while (keys.hasNext()) + { + Object key = keys.next(); + newTable.put(key, paramsMap.get(key)); + } + + return newTable; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java index 2031929..eb045bf 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java @@ -3,6 +3,7 @@ package org.bouncycastle.jcajce.provider.symmetric.util; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; +import java.security.InvalidParameterException; import java.security.Key; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; @@ -205,7 +206,7 @@ public class BaseStreamCipher } else { - throw new IllegalArgumentException("unknown parameter type."); + throw new InvalidAlgorithmParameterException("unknown parameter type."); } if ((ivLength != 0) && !(param instanceof ParametersWithIV)) @@ -231,18 +232,25 @@ public class BaseStreamCipher } } - switch (opmode) + try + { + switch (opmode) + { + case Cipher.ENCRYPT_MODE: + case Cipher.WRAP_MODE: + cipher.init(true, param); + break; + case Cipher.DECRYPT_MODE: + case Cipher.UNWRAP_MODE: + cipher.init(false, param); + break; + default: + throw new InvalidParameterException("unknown opmode " + opmode + " passed"); + } + } + catch (Exception e) { - case Cipher.ENCRYPT_MODE: - case Cipher.WRAP_MODE: - cipher.init(true, param); - break; - case Cipher.DECRYPT_MODE: - case Cipher.UNWRAP_MODE: - cipher.init(false, param); - break; - default: - System.out.println("eeek!"); + throw new InvalidKeyException(e.getMessage()); } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java index 951beee..c39a2d3 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java @@ -87,7 +87,44 @@ public interface PBE } else if (type == PKCS5S2 || type == PKCS5S2_UTF8) { - generator = new PKCS5S2ParametersGenerator(); + switch (hash) + { + // BEGIN android-removed + // case MD2: + // generator = new PKCS5S2ParametersGenerator(new MD2Digest()); + // break; + // END android-removed + case MD5: + // BEGIN android-changed + generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getMD5()); + // END android-changed + break; + case SHA1: + // BEGIN android-changed + generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA1()); + // END android-changed + break; + // BEGIN android-removed + // case RIPEMD160: + // generator = new PKCS5S2ParametersGenerator(new RIPEMD160Digest()); + // break; + // case TIGER: + // generator = new PKCS5S2ParametersGenerator(new TigerDigest()); + // break; + // END android-removed + case SHA256: + // BEGIN android-changed + generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA256()); + // END android-changed + break; + // BEGIN android-removed + // case GOST3411: + // generator = new PKCS5S2ParametersGenerator(new GOST3411Digest()); + // break; + // END android-removed + default: + throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption."); + } } else if (type == PKCS12) { @@ -288,9 +325,9 @@ public interface PBE key = convertPassword(type, keySpec); generator.init(key, keySpec.getSalt(), keySpec.getIterationCount()); - + param = generator.generateDerivedMacParameters(keySize); - + for (int i = 0; i != key.length; i++) { key[i] = 0; diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java new file mode 100644 index 0000000..214a5eb --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java @@ -0,0 +1,23 @@ +package org.bouncycastle.jcajce.spec; + +import javax.crypto.spec.PBEKeySpec; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class PBKDF2KeySpec + extends PBEKeySpec +{ + private AlgorithmIdentifier prf; + + public PBKDF2KeySpec(char[] password, byte[] salt, int iterationCount, int keySize, AlgorithmIdentifier prf) + { + super(password, salt, iterationCount, keySize); + + this.prf = prf; + } + + public AlgorithmIdentifier getPrf() + { + return prf; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java b/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java new file mode 100644 index 0000000..941f476 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java @@ -0,0 +1,60 @@ +package org.bouncycastle.jce; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; + +/** + * a table of locally supported named curves. + */ +public class ECNamedCurveTable +{ + /** + * return a parameter spec representing the passed in named + * curve. The routine returns null if the curve is not present. + * + * @param name the name of the curve requested + * @return a parameter spec for the curve, null if it is not available. + */ + public static ECNamedCurveParameterSpec getParameterSpec( + String name) + { + X9ECParameters ecP = org.bouncycastle.asn1.x9.ECNamedCurveTable.getByName(name); + if (ecP == null) + { + try + { + ecP = org.bouncycastle.asn1.x9.ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(name)); + } + catch (IllegalArgumentException e) + { + // ignore - not an oid + } + } + + if (ecP == null) + { + return null; + } + + return new ECNamedCurveParameterSpec( + name, + ecP.getCurve(), + ecP.getG(), + ecP.getN(), + ecP.getH(), + ecP.getSeed()); + } + + /** + * return an enumeration of the names of the available curves. + * + * @return an enumeration of the names of the available curves. + */ + public static Enumeration getNames() + { + return org.bouncycastle.asn1.x9.ECNamedCurveTable.getNames(); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java b/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java index efa0f66..ddd38e8 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java @@ -19,6 +19,7 @@ import org.bouncycastle.asn1.x509.X509Name; * PrincipalUtil class. * </p> * @see org.bouncycastle.jce.PrincipalUtil + * @deprecated use the X500Name class. */ public class X509Principal extends X509Name diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java index 665f85b..ab6c42f 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java @@ -44,7 +44,7 @@ import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; public final class BouncyCastleProvider extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Security Provider v1.49"; + private static String info = "BouncyCastle Security Provider v1.50"; public static final String PROVIDER_NAME = "BC"; @@ -72,11 +72,13 @@ public final class BouncyCastleProvider extends Provider private static final String[] SYMMETRIC_CIPHERS = { // BEGIN android-removed - // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DES", "DESede", "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", - // "Noekeon", "RC2", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA" + // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede", + // "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5", + // "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "TEA", "Twofish", "Threefish", + // "VMPC", "VMPCKSA3", "XTEA", "XSalsa20" // END android-removed // BEGIN android-added - "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish" + "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish", // END android-added }; @@ -114,7 +116,7 @@ public final class BouncyCastleProvider extends Provider private static final String[] DIGESTS = { // BEGIN android-removed - // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Tiger", "Whirlpool" + // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool" // END android-removed // BEGIN android-added "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", @@ -122,7 +124,7 @@ public final class BouncyCastleProvider extends Provider }; /* - * Configurable digests + * Configurable keystores */ private static final String KEYSTORE_PACKAGE = "org.bouncycastle.jcajce.provider.keystore."; private static final String[] KEYSTORES = @@ -137,7 +139,7 @@ public final class BouncyCastleProvider extends Provider */ public BouncyCastleProvider() { - super(PROVIDER_NAME, 1.49, info); + super(PROVIDER_NAME, 1.50, info); AccessController.doPrivileged(new PrivilegedAction() { diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java index a76aff7..eb663dc 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java @@ -76,7 +76,9 @@ import org.bouncycastle.x509.ExtendedPKIXParameters; import org.bouncycastle.x509.X509AttributeCertificate; import org.bouncycastle.x509.X509CRLStoreSelector; import org.bouncycastle.x509.X509CertStoreSelector; -import org.bouncycastle.x509.X509Store; +// BEGIN android-removed +// import org.bouncycastle.x509.X509Store; +// END android-removed public class CertPathValidatorUtilities { @@ -726,20 +728,22 @@ public class CertPathValidatorUtilities { Object obj = iter.next(); - if (obj instanceof X509Store) - { - X509Store certStore = (X509Store)obj; - try - { - certs.addAll(certStore.getMatches(certSelect)); - } - catch (StoreException e) - { - throw new AnnotatedException( - "Problem while picking certificates from X.509 store.", e); - } - } - else + // BEGIN android-removed + // if (obj instanceof X509Store) + // { + // X509Store certStore = (X509Store)obj; + // try + // { + // certs.addAll(certStore.getMatches(certSelect)); + // } + // catch (StoreException e) + // { + // throw new AnnotatedException( + // "Problem while picking certificates from X.509 store.", e); + // } + // } + // else + // END android-removed { CertStore certStore = (CertStore)obj; diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java index 7d561b3..53f4ec7 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java @@ -127,8 +127,8 @@ public class JCEECPrivateKey this.ecSpec = new ECParameterSpec( ellipticCurve, new ECPoint( - dp.getG().getX().toBigInteger(), - dp.getG().getY().toBigInteger()), + dp.getG().getAffineXCoord().toBigInteger(), + dp.getG().getAffineYCoord().toBigInteger()), dp.getN(), dp.getH().intValue()); } @@ -158,8 +158,8 @@ public class JCEECPrivateKey this.ecSpec = new ECParameterSpec( ellipticCurve, new ECPoint( - dp.getG().getX().toBigInteger(), - dp.getG().getY().toBigInteger()), + dp.getG().getAffineXCoord().toBigInteger(), + dp.getG().getAffineYCoord().toBigInteger()), dp.getN(), dp.getH().intValue()); } @@ -170,8 +170,8 @@ public class JCEECPrivateKey this.ecSpec = new ECParameterSpec( ellipticCurve, new ECPoint( - spec.getG().getX().toBigInteger(), - spec.getG().getY().toBigInteger()), + spec.getG().getAffineXCoord().toBigInteger(), + spec.getG().getAffineYCoord().toBigInteger()), spec.getN(), spec.getH().intValue()); } @@ -215,8 +215,8 @@ public class JCEECPrivateKey // ECGOST3410NamedCurves.getName(oid), // ellipticCurve, // new ECPoint( - // gParam.getG().getX().toBigInteger(), - // gParam.getG().getY().toBigInteger()), + // gParam.getG().getAffineXCoord().toBigInteger(), + // gParam.getG().getAffineYCoord().toBigInteger()), // gParam.getN(), // gParam.getH()); // } @@ -229,8 +229,8 @@ public class JCEECPrivateKey ECUtil.getCurveName(oid), ellipticCurve, new ECPoint( - ecP.getG().getX().toBigInteger(), - ecP.getG().getY().toBigInteger()), + ecP.getG().getAffineXCoord().toBigInteger(), + ecP.getG().getAffineYCoord().toBigInteger()), ecP.getN(), ecP.getH()); } @@ -247,8 +247,8 @@ public class JCEECPrivateKey this.ecSpec = new ECParameterSpec( ellipticCurve, new ECPoint( - ecP.getG().getX().toBigInteger(), - ecP.getG().getY().toBigInteger()), + ecP.getG().getAffineXCoord().toBigInteger(), + ecP.getG().getAffineYCoord().toBigInteger()), ecP.getN(), ecP.getH().intValue()); } diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java index cfed770..6fff8a6 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java @@ -98,7 +98,7 @@ public class JCEECPublicKey { org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false); + q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger(), false); } this.ecSpec = null; } @@ -167,8 +167,8 @@ public class JCEECPublicKey return new ECParameterSpec( ellipticCurve, new ECPoint( - dp.getG().getX().toBigInteger(), - dp.getG().getY().toBigInteger()), + dp.getG().getAffineXCoord().toBigInteger(), + dp.getG().getAffineYCoord().toBigInteger()), dp.getN(), dp.getH().intValue()); } @@ -189,7 +189,6 @@ public class JCEECPublicKey private void populateFromPubKeyInfo(SubjectPublicKeyInfo info) { - // BEGIN android-removed // if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001)) // { // DERBitString bits = info.getPublicKeyData(); @@ -232,8 +231,8 @@ public class JCEECPublicKey // ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()), // ellipticCurve, // new ECPoint( - // spec.getG().getX().toBigInteger(), - // spec.getG().getY().toBigInteger()), + // spec.getG().getAffineXCoord().toBigInteger(), + // spec.getG().getAffineYCoord().toBigInteger()), // spec.getN(), spec.getH()); // // } @@ -256,8 +255,8 @@ public class JCEECPublicKey ECUtil.getCurveName(oid), ellipticCurve, new ECPoint( - ecP.getG().getX().toBigInteger(), - ecP.getG().getY().toBigInteger()), + ecP.getG().getAffineXCoord().toBigInteger(), + ecP.getG().getAffineYCoord().toBigInteger()), ecP.getN(), ecP.getH()); } @@ -276,8 +275,8 @@ public class JCEECPublicKey this.ecSpec = new ECParameterSpec( ellipticCurve, new ECPoint( - ecP.getG().getX().toBigInteger(), - ecP.getG().getY().toBigInteger()), + ecP.getG().getAffineXCoord().toBigInteger(), + ecP.getG().getAffineYCoord().toBigInteger()), ecP.getN(), ecP.getH().intValue()); } @@ -357,8 +356,8 @@ public class JCEECPublicKey // } // } // - // BigInteger bX = this.q.getX().toBigInteger(); - // BigInteger bY = this.q.getY().toBigInteger(); + // BigInteger bX = this.q.getAffineXCoord().toBigInteger(); + // BigInteger bY = this.q.getAffineYCoord().toBigInteger(); // byte[] encKey = new byte[64]; // // extractBytes(encKey, 0, bX); @@ -405,7 +404,7 @@ public class JCEECPublicKey ECCurve curve = this.engineGetQ().getCurve(); ASN1OctetString p = (ASN1OctetString) - new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).toASN1Primitive(); + new X9ECPoint(curve.createPoint(this.getQ().getAffineXCoord().toBigInteger(), this.getQ().getAffineYCoord().toBigInteger(), withCompression)).toASN1Primitive(); info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); } @@ -446,7 +445,7 @@ public class JCEECPublicKey public ECPoint getW() { - return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger()); + return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger()); } public org.bouncycastle.math.ec.ECPoint getQ() @@ -455,11 +454,11 @@ public class JCEECPublicKey { if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp) { - return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY()); + return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getAffineXCoord(), q.getAffineYCoord()); } else { - return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY()); + return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getAffineXCoord(), q.getAffineYCoord()); } } @@ -487,8 +486,8 @@ public class JCEECPublicKey String nl = System.getProperty("line.separator"); buf.append("EC Public Key").append(nl); - buf.append(" X: ").append(this.q.getX().toBigInteger().toString(16)).append(nl); - buf.append(" Y: ").append(this.q.getY().toBigInteger().toString(16)).append(nl); + buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl); + buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl); return buf.toString(); diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java index c94016d..ebd2f2a 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java @@ -15,7 +15,9 @@ import java.util.Set; import org.bouncycastle.util.StoreException; import org.bouncycastle.x509.ExtendedPKIXParameters; import org.bouncycastle.x509.X509CRLStoreSelector; -import org.bouncycastle.x509.X509Store; +// BEGIN android-removed +// import org.bouncycastle.x509.X509Store; +// END android-removed public class PKIXCRLUtil { @@ -114,22 +116,24 @@ public class PKIXCRLUtil { Object obj = iter.next(); - if (obj instanceof X509Store) - { - X509Store store = (X509Store)obj; - - try - { - crls.addAll(store.getMatches(crlSelect)); - foundValidStore = true; - } - catch (StoreException e) - { - lastException = new AnnotatedException( - "Exception searching in X.509 CRL store.", e); - } - } - else + // BEGIN android-removed + // if (obj instanceof X509Store) + // { + // X509Store store = (X509Store)obj; + // + // try + // { + // crls.addAll(store.getMatches(crlSelect)); + // foundValidStore = true; + // } + // catch (StoreException e) + // { + // lastException = new AnnotatedException( + // "Exception searching in X.509 CRL store.", e); + // } + // } + // else + // END android-removed { CertStore store = (CertStore)obj; diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java index d5c3700..7e76a89 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java @@ -211,6 +211,23 @@ public class X509CRLEntryObject extends X509CRLEntry return hashValue; } + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof X509CRLEntryObject) + { + X509CRLEntryObject other = (X509CRLEntryObject)o; + + return this.c.equals(other.c); + } + + return super.equals(this); + } + public byte[] getEncoded() throws CRLException { diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java index cd83211..b5b4f13 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java @@ -59,6 +59,8 @@ public class X509CRLObject private String sigAlgName; private byte[] sigAlgParams; private boolean isIndirect; + private boolean isHashCodeSet = false; + private int hashCodeValue; static boolean isIndirectCRL(X509CRL crl) throws CRLException @@ -520,7 +522,7 @@ public class X509CRLObject throw new RuntimeException("X.509 CRL used with non X.509 Cert"); } - TBSCertList.CRLEntry[] certs = c.getRevokedCertificates(); + Enumeration certs = c.getRevokedCertificateEnumeration(); X500Name caName = c.getIssuer(); @@ -528,11 +530,13 @@ public class X509CRLObject { BigInteger serial = ((X509Certificate)cert).getSerialNumber(); - for (int i = 0; i < certs.length; i++) + while (certs.hasMoreElements()) { - if (isIndirect && certs[i].hasExtensions()) + TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement()); + + if (isIndirect && entry.hasExtensions()) { - Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer); + Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); if (currentCaName != null) { @@ -540,7 +544,7 @@ public class X509CRLObject } } - if (certs[i].getUserCertificate().getValue().equals(serial)) + if (entry.getUserCertificate().getValue().equals(serial)) { X500Name issuer; @@ -572,5 +576,50 @@ public class X509CRLObject return false; } + + public boolean equals(Object other) + { + if (this == other) + { + return true; + } + + if (!(other instanceof X509CRL)) + { + return false; + } + + if (other instanceof X509CRLObject) + { + X509CRLObject crlObject = (X509CRLObject)other; + + if (isHashCodeSet) + { + boolean otherIsHashCodeSet = crlObject.isHashCodeSet; + if (otherIsHashCodeSet) + { + if (crlObject.hashCodeValue != hashCodeValue) + { + return false; + } + } + } + + return this.c.equals(crlObject.c); + } + + return super.equals(other); + } + + public int hashCode() + { + if (!isHashCodeSet) + { + isHashCodeSet = true; + hashCodeValue = super.hashCode(); + } + + return hashCodeValue; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java index 84ebf70..b3d239e 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java @@ -49,7 +49,8 @@ public class ECNamedCurveSpec private static ECPoint convertPoint( org.bouncycastle.math.ec.ECPoint g) { - return new ECPoint(g.getX().toBigInteger(), g.getY().toBigInteger()); + g = g.normalize(); + return new ECPoint(g.getAffineXCoord().toBigInteger(), g.getAffineYCoord().toBigInteger()); } public ECNamedCurveSpec( diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java index e774a11..df91412 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java @@ -24,7 +24,7 @@ public class ECParameterSpec BigInteger n) { this.curve = curve; - this.G = G; + this.G = G.normalize(); this.n = n; this.h = BigInteger.valueOf(1); this.seed = null; @@ -37,7 +37,7 @@ public class ECParameterSpec BigInteger h) { this.curve = curve; - this.G = G; + this.G = G.normalize(); this.n = n; this.h = h; this.seed = null; @@ -51,7 +51,7 @@ public class ECParameterSpec byte[] seed) { this.curve = curve; - this.G = G; + this.G = G.normalize(); this.n = n; this.h = h; this.seed = seed; diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java index debab00..0e21a5b 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java @@ -22,7 +22,14 @@ public class ECPublicKeySpec { super(spec); - this.q = q; + if (q.getCurve() != null) + { + this.q = q.normalize(); + } + else + { + this.q = q; + } } /** diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java deleted file mode 100644 index 2a7ceb5..0000000 --- a/bcprov/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bouncycastle.jce.spec; - - -import javax.crypto.SecretKey; - -/** - * A simple object to indicate that a symmetric cipher should reuse the - * last key provided. - */ -public class RepeatedSecretKeySpec - implements SecretKey -{ - private String algorithm; - - public RepeatedSecretKeySpec(String algorithm) - { - this.algorithm = algorithm; - } - - public String getAlgorithm() - { - return algorithm; - } - - public String getFormat() - { - return null; - } - - public byte[] getEncoded() - { - return null; - } -} diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java new file mode 100644 index 0000000..69ab797 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java @@ -0,0 +1,20 @@ +package org.bouncycastle.math.ec; + +import java.math.BigInteger; + +public abstract class AbstractECMultiplier implements ECMultiplier +{ + public ECPoint multiply(ECPoint p, BigInteger k) + { + int sign = k.signum(); + if (sign == 0 || p.isInfinity()) + { + return p.getCurve().getInfinity(); + } + + ECPoint positive = multiplyPositive(p, k.abs()); + return sign > 0 ? positive : positive.negate(); + } + + protected abstract ECPoint multiplyPositive(ECPoint p, BigInteger k); +} diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java index 78a7a8f..d640b5f 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java @@ -7,16 +7,13 @@ public class ECAlgorithms public static ECPoint sumOfTwoMultiplies(ECPoint P, BigInteger a, ECPoint Q, BigInteger b) { - ECCurve c = P.getCurve(); - if (!c.equals(Q.getCurve())) - { - throw new IllegalArgumentException("P and Q must be on same curve"); - } + ECCurve cp = P.getCurve(); + Q = importPoint(cp, Q); // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick - if (c instanceof ECCurve.F2m) + if (cp instanceof ECCurve.F2m) { - ECCurve.F2m f2mCurve = (ECCurve.F2m)c; + ECCurve.F2m f2mCurve = (ECCurve.F2m)cp; if (f2mCurve.isKoblitz()) { return P.multiply(a).add(Q.multiply(b)); @@ -48,43 +45,83 @@ public class ECAlgorithms public static ECPoint shamirsTrick(ECPoint P, BigInteger k, ECPoint Q, BigInteger l) { - if (!P.getCurve().equals(Q.getCurve())) + ECCurve cp = P.getCurve(); + Q = importPoint(cp, Q); + + return implShamirsTrick(P, k, Q, l); + } + + public static ECPoint importPoint(ECCurve c, ECPoint p) + { + ECCurve cp = p.getCurve(); + if (!c.equals(cp)) { - throw new IllegalArgumentException("P and Q must be on same curve"); + throw new IllegalArgumentException("Point must be on the same curve"); } + return c.importPoint(p); + } - return implShamirsTrick(P, k, Q, l); + static void implMontgomeryTrick(ECFieldElement[] zs, int off, int len) + { + /* + * Uses the "Montgomery Trick" to invert many field elements, with only a single actual + * field inversion. See e.g. the paper: + * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick" + * by Katsuyuki Okeya, Kouichi Sakurai. + */ + + ECFieldElement[] c = new ECFieldElement[len]; + c[0] = zs[off]; + + int i = 0; + while (++i < len) + { + c[i] = c[i - 1].multiply(zs[off + i]); + } + + ECFieldElement u = c[--i].invert(); + + while (i > 0) + { + int j = off + i--; + ECFieldElement tmp = zs[j]; + zs[j] = c[i].multiply(u); + u = u.multiply(tmp); + } + + zs[off] = u; } - private static ECPoint implShamirsTrick(ECPoint P, BigInteger k, + static ECPoint implShamirsTrick(ECPoint P, BigInteger k, ECPoint Q, BigInteger l) { - int m = Math.max(k.bitLength(), l.bitLength()); - ECPoint Z = P.add(Q); - ECPoint R = P.getCurve().getInfinity(); + ECCurve curve = P.getCurve(); + ECPoint infinity = curve.getInfinity(); + + // TODO conjugate co-Z addition (ZADDC) can return both of these + ECPoint PaddQ = P.add(Q); + ECPoint PsubQ = P.subtract(Q); + + ECPoint[] points = new ECPoint[]{ Q, PsubQ, P, PaddQ }; + curve.normalizeAll(points); - for (int i = m - 1; i >= 0; --i) + ECPoint[] table = new ECPoint[] { + points[3].negate(), points[2].negate(), points[1].negate(), + points[0].negate(), infinity, points[0], + points[1], points[2], points[3] }; + + byte[] jsf = WNafUtil.generateJSF(k, l); + + ECPoint R = infinity; + + int i = jsf.length; + while (--i >= 0) { - R = R.twice(); + int jsfi = jsf[i]; + int kDigit = (jsfi >> 4), lDigit = ((jsfi << 28) >> 28); - if (k.testBit(i)) - { - if (l.testBit(i)) - { - R = R.add(Z); - } - else - { - R = R.add(P); - } - } - else - { - if (l.testBit(i)) - { - R = R.add(Q); - } - } + int index = 4 + (kDigit * 3) + lDigit; + R = R.twicePlus(table[index]); } return R; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java index 58281af..19f0062 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java @@ -3,18 +3,199 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; import java.util.Random; +import org.bouncycastle.util.BigIntegers; + /** * base class for an elliptic curve */ public abstract class ECCurve { - ECFieldElement a, b; + public static final int COORD_AFFINE = 0; + public static final int COORD_HOMOGENEOUS = 1; + public static final int COORD_JACOBIAN = 2; + public static final int COORD_JACOBIAN_CHUDNOVSKY = 3; + public static final int COORD_JACOBIAN_MODIFIED = 4; + public static final int COORD_LAMBDA_AFFINE = 5; + public static final int COORD_LAMBDA_PROJECTIVE = 6; + public static final int COORD_SKEWED = 7; + + public static int[] getAllCoordinateSystems() + { + return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY, + COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED }; + } + + public class Config + { + protected int coord; + protected ECMultiplier multiplier; + + Config(int coord, ECMultiplier multiplier) + { + this.coord = coord; + this.multiplier = multiplier; + } + + public Config setCoordinateSystem(int coord) + { + this.coord = coord; + return this; + } + + public Config setMultiplier(ECMultiplier multiplier) + { + this.multiplier = multiplier; + return this; + } + + public ECCurve create() + { + if (!supportsCoordinateSystem(coord)) + { + throw new IllegalStateException("unsupported coordinate system"); + } + + ECCurve c = cloneCurve(); + if (c == ECCurve.this) + { + throw new IllegalStateException("implementation returned current curve"); + } + + c.coord = coord; + c.multiplier = multiplier; + + return c; + } + } + + protected ECFieldElement a, b; + protected int coord = COORD_AFFINE; + protected ECMultiplier multiplier = null; public abstract int getFieldSize(); public abstract ECFieldElement fromBigInteger(BigInteger x); - public abstract ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression); + public Config configure() + { + return new Config(this.coord, this.multiplier); + } + + 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); + } + + protected abstract ECCurve cloneCurve(); + + protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression); + + protected ECMultiplier createDefaultMultiplier() + { + return new WNafL2RMultiplier(); + } + + public boolean supportsCoordinateSystem(int coord) + { + return coord == COORD_AFFINE; + } + + public PreCompInfo getPreCompInfo(ECPoint p) + { + checkPoint(p); + return p.preCompInfo; + } + + /** + * Sets the <code>PreCompInfo</code> for a point on this curve. Used by + * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use + * by subsequent multiplication. + * + * @param point + * The <code>ECPoint</code> to store precomputations for. + * @param preCompInfo + * The values precomputed by the <code>ECMultiplier</code>. + */ + public void setPreCompInfo(ECPoint point, PreCompInfo preCompInfo) + { + checkPoint(point); + point.preCompInfo = preCompInfo; + } + + public ECPoint importPoint(ECPoint p) + { + if (this == p.getCurve()) + { + return p; + } + if (p.isInfinity()) + { + return getInfinity(); + } + + // 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); + } + + /** + * Normalization ensures that any projective coordinate is 1, and therefore that the x, y + * coordinates reflect those of the equivalent point in an affine coordinate system. Where more + * than one point is to be normalized, this method will generally be more efficient than + * normalizing each point separately. + * + * @param points + * An array of points that will be updated in place with their normalized versions, + * where necessary + */ + public void normalizeAll(ECPoint[] points) + { + checkPoints(points); + + if (this.getCoordinateSystem() == ECCurve.COORD_AFFINE) + { + return; + } + + /* + * Figure out which of the points actually need to be normalized + */ + ECFieldElement[] zs = new ECFieldElement[points.length]; + int[] indices = new int[points.length]; + int count = 0; + for (int i = 0; i < points.length; ++i) + { + ECPoint p = points[i]; + if (null != p && !p.isNormalized()) + { + zs[count] = p.getZCoord(0); + indices[count++] = i; + } + } + + if (count == 0) + { + return; + } + + ECAlgorithms.implMontgomeryTrick(zs, 0, count); + + for (int j = 0; j < count; ++j) + { + int index = indices[j]; + points[index] = points[index].normalize(zs[j]); + } + } public abstract ECPoint getInfinity(); @@ -28,9 +209,26 @@ public abstract class ECCurve return b; } + public int getCoordinateSystem() + { + return coord; + } + protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1); /** + * Sets the default <code>ECMultiplier</code>, unless already set. + */ + public ECMultiplier getMultiplier() + { + if (this.multiplier == null) + { + this.multiplier = createDefaultMultiplier(); + } + return this.multiplier; + } + + /** * Decode a point on this curve from its ASN.1 encoding. The different * encodings are taken account of, including point compression for * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17). @@ -62,9 +260,9 @@ public abstract class ECCurve } int yTilde = encoded[0] & 1; - BigInteger X1 = fromArray(encoded, 1, expectedLength); + BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength); - p = decompressPoint(yTilde, X1); + p = decompressPoint(yTilde, X); break; } case 0x04: // uncompressed @@ -76,10 +274,10 @@ public abstract class ECCurve throw new IllegalArgumentException("Incorrect length for uncompressed/hybrid encoding"); } - BigInteger X1 = fromArray(encoded, 1, expectedLength); - BigInteger Y1 = fromArray(encoded, 1 + expectedLength, expectedLength); + BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength); + BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength); - p = createPoint(X1, Y1, false); + p = createPoint(X, Y); break; } default: @@ -89,11 +287,29 @@ public abstract class ECCurve return p; } - private static BigInteger fromArray(byte[] buf, int off, int length) + protected void checkPoint(ECPoint point) { - byte[] mag = new byte[length]; - System.arraycopy(buf, off, mag, 0, length); - return new BigInteger(1, mag); + if (null == point || (this != point.getCurve())) + { + throw new IllegalArgumentException("'point' must be non-null and on this curve"); + } + } + + protected void checkPoints(ECPoint[] points) + { + if (points == null) + { + throw new IllegalArgumentException("'points' cannot be null"); + } + + for (int i = 0; i < points.length; ++i) + { + ECPoint point = points[i]; + if (null != point && this != point.getCurve()) + { + throw new IllegalArgumentException("'points' entries must be null or on this curve"); + } + } } /** @@ -101,15 +317,50 @@ public abstract class ECCurve */ public static class Fp extends ECCurve { - BigInteger q; + private static final int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED; + + BigInteger q, r; ECPoint.Fp infinity; public Fp(BigInteger q, BigInteger a, BigInteger b) { this.q = q; + this.r = ECFieldElement.Fp.calculateResidue(q); + this.infinity = new ECPoint.Fp(this, null, null); + this.a = fromBigInteger(a); this.b = fromBigInteger(b); + this.coord = FP_DEFAULT_COORDS; + } + + protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b) + { + this.q = q; + this.r = r; this.infinity = new ECPoint.Fp(this, null, null); + + this.a = a; + this.b = b; + this.coord = FP_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new Fp(q, r, a, b); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_AFFINE: + case COORD_HOMOGENEOUS: + case COORD_JACOBIAN: + case COORD_JACOBIAN_MODIFIED: + return true; + default: + return false; + } } public BigInteger getQ() @@ -124,12 +375,34 @@ public abstract class ECCurve public ECFieldElement fromBigInteger(BigInteger x) { - return new ECFieldElement.Fp(this.q, x); + return new ECFieldElement.Fp(this.q, this.r, x); } - public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) { - return new ECPoint.Fp(this, fromBigInteger(x), fromBigInteger(y), withCompression); + return new ECPoint.Fp(this, x, y, withCompression); + } + + public ECPoint importPoint(ECPoint p) + { + if (this != p.getCurve() && this.getCoordinateSystem() == COORD_JACOBIAN && !p.isInfinity()) + { + switch (p.getCurve().getCoordinateSystem()) + { + case COORD_JACOBIAN: + case COORD_JACOBIAN_CHUDNOVSKY: + case COORD_JACOBIAN_MODIFIED: + return new ECPoint.Fp(this, + fromBigInteger(p.x.toBigInteger()), + fromBigInteger(p.y.toBigInteger()), + new ECFieldElement[]{ fromBigInteger(p.zs[0].toBigInteger()) }, + p.withCompression); + default: + break; + } + } + + return super.importPoint(p); } protected ECPoint decompressPoint(int yTilde, BigInteger X1) @@ -148,9 +421,7 @@ public abstract class ECCurve } BigInteger betaValue = beta.toBigInteger(); - int bit0 = betaValue.testBit(0) ? 1 : 0; - - if (bit0 != yTilde) + if (betaValue.testBit(0) != (yTilde == 1)) { // Use the other root beta = fromBigInteger(q.subtract(betaValue)); @@ -195,6 +466,8 @@ public abstract class ECCurve */ public static class F2m extends ECCurve { + private static final int F2M_DEFAULT_COORDS = COORD_AFFINE; + /** * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>. */ @@ -401,9 +674,53 @@ public abstract class ECCurve } } + this.infinity = new ECPoint.F2m(this, null, null); this.a = fromBigInteger(a); this.b = fromBigInteger(b); + this.coord = F2M_DEFAULT_COORDS; + } + + protected F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger n, BigInteger h) + { + this.m = m; + this.k1 = k1; + this.k2 = k2; + this.k3 = k3; + this.n = n; + this.h = h; + this.infinity = new ECPoint.F2m(this, null, null); + this.a = a; + this.b = b; + this.coord = F2M_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new F2m(m, k1, k2, k3, a, b, n, h); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_AFFINE: + case COORD_HOMOGENEOUS: + case COORD_LAMBDA_PROJECTIVE: + return true; + default: + return false; + } + } + + protected ECMultiplier createDefaultMultiplier() + { + if (isKoblitz()) + { + return new WTauNafMultiplier(); + } + + return super.createDefaultMultiplier(); } public int getFieldSize() @@ -418,7 +735,32 @@ public abstract class ECCurve public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression) { - return new ECPoint.F2m(this, fromBigInteger(x), fromBigInteger(y), withCompression); + ECFieldElement X = fromBigInteger(x), Y = fromBigInteger(y); + + switch (this.getCoordinateSystem()) + { + case COORD_LAMBDA_AFFINE: + case COORD_LAMBDA_PROJECTIVE: + { + if (!X.isZero()) + { + // Y becomes Lambda (X + Y/X) here + Y = Y.divide(X).add(X); + } + break; + } + default: + { + break; + } + } + + return createRawPoint(X, Y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new ECPoint.F2m(this, x, y, withCompression); } public ECPoint getInfinity() @@ -432,10 +774,7 @@ public abstract class ECCurve */ public boolean isKoblitz() { - return ((n != null) && (h != null) && - ((a.toBigInteger().equals(ECConstants.ZERO)) || - (a.toBigInteger().equals(ECConstants.ONE))) && - (b.toBigInteger().equals(ECConstants.ONE))); + return n != null && h != null && a.bitLength() <= 1 && b.bitLength() == 1; } /** @@ -480,7 +819,7 @@ public abstract class ECCurve { ECFieldElement xp = fromBigInteger(X1); ECFieldElement yp = null; - if (xp.toBigInteger().equals(ECConstants.ZERO)) + if (xp.isZero()) { yp = (ECFieldElement.F2m)b; for (int i = 0; i < m - 1; i++) @@ -491,17 +830,31 @@ public abstract class ECCurve else { ECFieldElement beta = xp.add(a).add(b.multiply(xp.square().invert())); - ECFieldElement z = solveQuadradicEquation(beta); + ECFieldElement z = solveQuadraticEquation(beta); if (z == null) { throw new IllegalArgumentException("Invalid point compression"); } - int zBit = z.toBigInteger().testBit(0) ? 1 : 0; - if (zBit != yTilde) + if (z.testBitZero() != (yTilde == 1)) { - z = z.add(fromBigInteger(ECConstants.ONE)); + z = z.addOne(); } + yp = xp.multiply(z); + + switch (this.getCoordinateSystem()) + { + case COORD_LAMBDA_AFFINE: + case COORD_LAMBDA_PROJECTIVE: + { + yp = yp.divide(xp).add(xp); + break; + } + default: + { + break; + } + } } return new ECPoint.F2m(this, xp, yp, true); @@ -512,28 +865,26 @@ public abstract class ECCurve * D.1.6) The other solution is <code>z + 1</code>. * * @param beta - * The value to solve the qradratic equation for. + * The value to solve the quadratic equation for. * @return the solution for <code>z<sup>2</sup> + z = beta</code> or * <code>null</code> if no solution exists. */ - private ECFieldElement solveQuadradicEquation(ECFieldElement beta) + private ECFieldElement solveQuadraticEquation(ECFieldElement beta) { - ECFieldElement zeroElement = new ECFieldElement.F2m( - this.m, this.k1, this.k2, this.k3, ECConstants.ZERO); - - if (beta.toBigInteger().equals(ECConstants.ZERO)) + if (beta.isZero()) { - return zeroElement; + return beta; } + ECFieldElement zeroElement = fromBigInteger(ECConstants.ZERO); + ECFieldElement z = null; - ECFieldElement gamma = zeroElement; + ECFieldElement gamma = null; Random rand = new Random(); do { - ECFieldElement t = new ECFieldElement.F2m(this.m, this.k1, - this.k2, this.k3, new BigInteger(m, rand)); + ECFieldElement t = fromBigInteger(new BigInteger(m, rand)); z = zeroElement; ECFieldElement w = beta; for (int i = 1; i <= m - 1; i++) @@ -542,13 +893,13 @@ public abstract class ECCurve z = z.square().add(w2.multiply(t)); w = w2.add(beta); } - if (!w.toBigInteger().equals(ECConstants.ZERO)) + if (!w.isZero()) { return null; } gamma = z.square().add(z); } - while (gamma.toBigInteger().equals(ECConstants.ZERO)); + while (gamma.isZero()); return z; } @@ -567,7 +918,7 @@ public abstract class ECCurve } ECCurve.F2m other = (ECCurve.F2m)anObject; - + return (this.m == other.m) && (this.k1 == other.k1) && (this.k2 == other.k2) && (this.k3 == other.k3) && a.equals(other.a) && b.equals(other.b); diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java index b5e9aa5..87608eb 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java @@ -3,14 +3,17 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; import java.util.Random; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; + public abstract class ECFieldElement implements ECConstants { - public abstract BigInteger toBigInteger(); public abstract String getFieldName(); public abstract int getFieldSize(); public abstract ECFieldElement add(ECFieldElement b); + public abstract ECFieldElement addOne(); public abstract ECFieldElement subtract(ECFieldElement b); public abstract ECFieldElement multiply(ECFieldElement b); public abstract ECFieldElement divide(ECFieldElement b); @@ -19,27 +22,99 @@ public abstract class ECFieldElement public abstract ECFieldElement invert(); public abstract ECFieldElement sqrt(); + public int bitLength() + { + return toBigInteger().bitLength(); + } + + public boolean isZero() + { + return 0 == toBigInteger().signum(); + } + + public boolean testBitZero() + { + return toBigInteger().testBit(0); + } + public String toString() { - return this.toBigInteger().toString(2); + return this.toBigInteger().toString(16); + } + + public byte[] getEncoded() + { + return BigIntegers.asUnsignedByteArray((getFieldSize() + 7) / 8, toBigInteger()); } public static class Fp extends ECFieldElement { - BigInteger x; + BigInteger q, r, x; - BigInteger q; - +// static int[] calculateNaf(BigInteger p) +// { +// int[] naf = WNafUtil.generateCompactNaf(p); +// +// int bit = 0; +// for (int i = 0; i < naf.length; ++i) +// { +// int ni = naf[i]; +// int digit = ni >> 16, zeroes = ni & 0xFFFF; +// +// bit += zeroes; +// naf[i] = digit < 0 ? ~bit : bit; +// ++bit; +// } +// +// int last = naf.length - 1; +// if (last > 0 && last <= 16) +// { +// int top = naf[last], top2 = naf[last - 1]; +// if (top2 < 0) +// { +// top2 = ~top2; +// } +// if (top - top2 >= 64) +// { +// return naf; +// } +// } +// +// return null; +// } + + static BigInteger calculateResidue(BigInteger p) + { + int bitLength = p.bitLength(); + if (bitLength > 128) + { + BigInteger firstWord = p.shiftRight(bitLength - 64); + if (firstWord.longValue() == -1L) + { + return ONE.shiftLeft(bitLength).subtract(p); + } + } + return null; + } + + /** + * @deprecated Use ECCurve.fromBigInteger to construct field elements + */ public Fp(BigInteger q, BigInteger x) { - this.x = x; - - if (x.compareTo(q) >= 0) + this(q, calculateResidue(q), x); + } + + Fp(BigInteger q, BigInteger r, BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(q) >= 0) { - throw new IllegalArgumentException("x value too large in field element"); + throw new IllegalArgumentException("x value invalid in Fp field element"); } this.q = q; + this.r = r; + this.x = x; } public BigInteger toBigInteger() @@ -66,40 +141,70 @@ public abstract class ECFieldElement { return q; } - + public ECFieldElement add(ECFieldElement b) { - return new Fp(q, x.add(b.toBigInteger()).mod(q)); + return new Fp(q, r, modAdd(x, b.toBigInteger())); + } + + public ECFieldElement addOne() + { + BigInteger x2 = x.add(ECConstants.ONE); + if (x2.compareTo(q) == 0) + { + x2 = ECConstants.ZERO; + } + return new Fp(q, r, x2); } public ECFieldElement subtract(ECFieldElement b) { - return new Fp(q, x.subtract(b.toBigInteger()).mod(q)); + BigInteger x2 = b.toBigInteger(); + BigInteger x3 = x.subtract(x2); + if (x3.signum() < 0) + { + x3 = x3.add(q); + } + return new Fp(q, r, x3); } public ECFieldElement multiply(ECFieldElement b) { - return new Fp(q, x.multiply(b.toBigInteger()).mod(q)); + return new Fp(q, r, modMult(x, b.toBigInteger())); } public ECFieldElement divide(ECFieldElement b) { - return new Fp(q, x.multiply(b.toBigInteger().modInverse(q)).mod(q)); + return new Fp(q, modMult(x, b.toBigInteger().modInverse(q))); } public ECFieldElement negate() { - return new Fp(q, x.negate().mod(q)); + BigInteger x2; + if (x.signum() == 0) + { + x2 = x; + } + else if (ONE.equals(r)) + { + x2 = q.xor(x); + } + else + { + x2 = q.subtract(x); + } + return new Fp(q, r, x2); } public ECFieldElement square() { - return new Fp(q, x.multiply(x).mod(q)); + return new Fp(q, r, modMult(x, x)); } public ECFieldElement invert() { - return new Fp(q, x.modInverse(q)); + // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime. + return new Fp(q, r, x.modInverse(q)); } // D.1.4 91 @@ -120,7 +225,7 @@ public abstract class ECFieldElement if (q.testBit(1)) { // z = g^(u+1) + p, p = 4u + 3 - ECFieldElement z = new Fp(q, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q)); + ECFieldElement z = new Fp(q, r, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q)); return z.square().equals(this) ? z : null; } @@ -138,7 +243,7 @@ public abstract class ECFieldElement BigInteger k = u.shiftLeft(1).add(ECConstants.ONE); BigInteger Q = this.x; - BigInteger fourQ = Q.shiftLeft(2).mod(q); + BigInteger fourQ = modDouble(modDouble(Q)); BigInteger U, V; Random rand = new Random(); @@ -152,11 +257,11 @@ public abstract class ECFieldElement while (P.compareTo(q) >= 0 || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, q).equals(qMinusOne))); - BigInteger[] result = lucasSequence(q, P, Q, k); + BigInteger[] result = lucasSequence(P, Q, k); U = result[0]; V = result[1]; - if (V.multiply(V).mod(q).equals(fourQ)) + if (modMult(V, V).equals(fourQ)) { // Integer division by 2, mod q if (V.testBit(0)) @@ -168,7 +273,7 @@ public abstract class ECFieldElement //assert V.multiply(V).mod(q).equals(x); - return new ECFieldElement.Fp(q, V); + return new ECFieldElement.Fp(q, r, V); } } while (U.equals(ECConstants.ONE) || U.equals(qMinusOne)); @@ -230,8 +335,7 @@ public abstract class ECFieldElement // return r.multiply(r).multiply(x.modPow(q.subtract(ECConstants.TWO), q)).subtract(ECConstants.TWO).mod(p); // } - private static BigInteger[] lucasSequence( - BigInteger p, + private BigInteger[] lucasSequence( BigInteger P, BigInteger Q, BigInteger k) @@ -247,40 +351,122 @@ public abstract class ECFieldElement for (int j = n - 1; j >= s + 1; --j) { - Ql = Ql.multiply(Qh).mod(p); + Ql = modMult(Ql, Qh); if (k.testBit(j)) { - Qh = Ql.multiply(Q).mod(p); - Uh = Uh.multiply(Vh).mod(p); - Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p); - Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p); + Qh = modMult(Ql, Q); + Uh = modMult(Uh, Vh); + Vl = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql))); + Vh = modReduce(Vh.multiply(Vh).subtract(Qh.shiftLeft(1))); } else { Qh = Ql; - Uh = Uh.multiply(Vl).subtract(Ql).mod(p); - Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p); - Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p); + Uh = modReduce(Uh.multiply(Vl).subtract(Ql)); + Vh = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql))); + Vl = modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1))); } } - Ql = Ql.multiply(Qh).mod(p); - Qh = Ql.multiply(Q).mod(p); - Uh = Uh.multiply(Vl).subtract(Ql).mod(p); - Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p); - Ql = Ql.multiply(Qh).mod(p); + Ql = modMult(Ql, Qh); + Qh = modMult(Ql, Q); + Uh = modReduce(Uh.multiply(Vl).subtract(Ql)); + Vl = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql))); + Ql = modMult(Ql, Qh); for (int j = 1; j <= s; ++j) { - Uh = Uh.multiply(Vl).mod(p); - Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p); - Ql = Ql.multiply(Ql).mod(p); + Uh = modMult(Uh, Vl); + Vl = modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1))); + Ql = modMult(Ql, Ql); } return new BigInteger[]{ Uh, Vl }; } - + + protected BigInteger modAdd(BigInteger x1, BigInteger x2) + { + BigInteger x3 = x1.add(x2); + if (x3.compareTo(q) >= 0) + { + x3 = x3.subtract(q); + } + return x3; + } + + protected BigInteger modDouble(BigInteger x) + { + BigInteger _2x = x.shiftLeft(1); + if (_2x.compareTo(q) >= 0) + { + _2x = _2x.subtract(q); + } + return _2x; + } + + protected BigInteger modMult(BigInteger x1, BigInteger x2) + { + return modReduce(x1.multiply(x2)); + } + + protected BigInteger modReduce(BigInteger x) + { +// if (naf != null) +// { +// int last = naf.length - 1; +// int bits = naf[last]; +// while (x.bitLength() > (bits + 1)) +// { +// BigInteger u = x.shiftRight(bits); +// BigInteger v = x.subtract(u.shiftLeft(bits)); +// +// x = v; +// +// for (int i = 0; i < last; ++i) +// { +// int ni = naf[i]; +// if (ni < 0) +// { +// x = x.add(u.shiftLeft(~ni)); +// } +// else +// { +// x = x.subtract(u.shiftLeft(ni)); +// } +// } +// } +// while (x.compareTo(q) >= 0) +// { +// x = x.subtract(q); +// } +// } +// else + if (r != null) + { + int qLen = q.bitLength(); + while (x.bitLength() > (qLen + 1)) + { + BigInteger u = x.shiftRight(qLen); + BigInteger v = x.subtract(u.shiftLeft(qLen)); + if (!r.equals(ONE)) + { + u = u.multiply(r); + } + x = u.add(v); + } + while (x.compareTo(q) >= 0) + { + x = x.subtract(q); + } + } + else + { + x = x.mod(q); + } + return x; + } + public boolean equals(Object other) { if (other == this) @@ -669,7 +855,7 @@ public abstract class ECFieldElement // g1z = g1z.xor(g2z.shiftLeft(j)); //// if (g1z.bitLength() > this.m) { //// throw new ArithmeticException( -//// "deg(g1z) >= m, g1z = " + g1z.toString(2)); +//// "deg(g1z) >= m, g1z = " + g1z.toString(16)); //// } // } // return new ECFieldElement.F2m( @@ -801,41 +987,38 @@ public abstract class ECFieldElement */ private int m; - /** - * TPB: The integer <code>k</code> where <code>x<sup>m</sup> + - * x<sup>k</sup> + 1</code> represents the reduction polynomial - * <code>f(z)</code>.<br> - * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> + - * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> - * represents the reduction polynomial <code>f(z)</code>.<br> - */ - private int k1; - - /** - * TPB: Always set to <code>0</code><br> - * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> + - * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> - * represents the reduction polynomial <code>f(z)</code>.<br> - */ - private int k2; - - /** - * TPB: Always set to <code>0</code><br> - * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> + - * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> - * represents the reduction polynomial <code>f(z)</code>.<br> - */ - private int k3; +// /** +// * TPB: The integer <code>k</code> where <code>x<sup>m</sup> + +// * x<sup>k</sup> + 1</code> represents the reduction polynomial +// * <code>f(z)</code>.<br> +// * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> + +// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> +// * represents the reduction polynomial <code>f(z)</code>.<br> +// */ +// private int k1; +// +// /** +// * TPB: Always set to <code>0</code><br> +// * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> + +// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> +// * represents the reduction polynomial <code>f(z)</code>.<br> +// */ +// private int k2; +// +// /** +// * TPB: Always set to <code>0</code><br> +// * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> + +// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> +// * represents the reduction polynomial <code>f(z)</code>.<br> +// */ +// private int k3; - /** - * The <code>IntArray</code> holding the bits. - */ - private IntArray x; + private int[] ks; /** - * The number of <code>int</code>s required to hold <code>m</code> bits. + * The <code>LongArray</code> holding the bits. */ - private int t; + private LongArray x; /** * Constructor for PPB. @@ -851,6 +1034,7 @@ public abstract class ECFieldElement * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> * represents the reduction polynomial <code>f(z)</code>. * @param x The BigInteger representing the value of the field element. + * @deprecated Use ECCurve.fromBigInteger to construct field elements */ public F2m( int m, @@ -859,13 +1043,10 @@ public abstract class ECFieldElement int k3, BigInteger x) { - // t = m / 32 rounded up to the next integer - t = (m + 31) >> 5; - this.x = new IntArray(x, t); - if ((k2 == 0) && (k3 == 0)) { this.representation = TPB; + this.ks = new int[]{ k1 }; } else { @@ -880,17 +1061,11 @@ public abstract class ECFieldElement "k2 must be larger than 0"); } this.representation = PPB; - } - - if (x.signum() < 0) - { - throw new IllegalArgumentException("x value cannot be negative"); + this.ks = new int[]{ k1, k2, k3 }; } this.m = m; - this.k1 = k1; - this.k2 = k2; - this.k3 = k3; + this.x = new LongArray(x); } /** @@ -901,6 +1076,7 @@ public abstract class ECFieldElement * x<sup>k</sup> + 1</code> represents the reduction * polynomial <code>f(z)</code>. * @param x The BigInteger representing the value of the field element. + * @deprecated Use ECCurve.fromBigInteger to construct field elements */ public F2m(int m, int k, BigInteger x) { @@ -908,24 +1084,27 @@ public abstract class ECFieldElement this(m, k, 0, 0, x); } - private F2m(int m, int k1, int k2, int k3, IntArray x) + private F2m(int m, int[] ks, LongArray x) { - t = (m + 31) >> 5; - this.x = x; this.m = m; - this.k1 = k1; - this.k2 = k2; - this.k3 = k3; + this.representation = (ks.length == 1) ? TPB : PPB; + this.ks = ks; + this.x = x; + } - if ((k2 == 0) && (k3 == 0)) - { - this.representation = TPB; - } - else - { - this.representation = PPB; - } + public int bitLength() + { + return x.degree(); + } + + public boolean isZero() + { + return x.isZero(); + } + public boolean testBitZero() + { + return x.testBitZero(); } public BigInteger toBigInteger() @@ -967,19 +1146,15 @@ public abstract class ECFieldElement ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a; ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b; - if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1) - || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3)) + if (aF2m.representation != bF2m.representation) { - throw new IllegalArgumentException("Field elements are not " - + "elements of the same field F2m"); + // Should never occur + throw new IllegalArgumentException("One of the F2m field elements has incorrect representation"); } - if (aF2m.representation != bF2m.representation) + if ((aF2m.m != bF2m.m) || !Arrays.areEqual(aF2m.ks, bF2m.ks)) { - // Should never occur - throw new IllegalArgumentException( - "One of the field " - + "elements are not elements has incorrect representation"); + throw new IllegalArgumentException("Field elements are not elements of the same field F2m"); } } @@ -988,10 +1163,15 @@ public abstract class ECFieldElement // No check performed here for performance reasons. Instead the // elements involved are checked in ECPoint.F2m // checkFieldElements(this, b); - IntArray iarrClone = (IntArray)this.x.clone(); + LongArray iarrClone = (LongArray)this.x.clone(); F2m bF2m = (F2m)b; - iarrClone.addShifted(bF2m.x, 0); - return new F2m(m, k1, k2, k3, iarrClone); + iarrClone.addShiftedByWords(bF2m.x, 0); + return new F2m(m, ks, iarrClone); + } + + public ECFieldElement addOne() + { + return new F2m(m, ks, x.addOne()); } public ECFieldElement subtract(final ECFieldElement b) @@ -1002,17 +1182,14 @@ public abstract class ECFieldElement public ECFieldElement multiply(final ECFieldElement b) { - // Right-to-left comb multiplication in the IntArray + // Right-to-left comb multiplication in the LongArray // Input: Binary polynomials a(z) and b(z) of degree at most m-1 // Output: c(z) = a(z) * b(z) mod f(z) // No check performed here for performance reasons. Instead the // elements involved are checked in ECPoint.F2m // checkFieldElements(this, b); - F2m bF2m = (F2m)b; - IntArray mult = x.multiply(bF2m.x, m); - mult.reduce(m, new int[]{k1, k2, k3}); - return new F2m(m, k1, k2, k3, mult); + return new F2m(m, ks, x.modMultiply(((F2m)b).x, m, ks)); } public ECFieldElement divide(final ECFieldElement b) @@ -1030,80 +1207,12 @@ public abstract class ECFieldElement public ECFieldElement square() { - IntArray squared = x.square(m); - squared.reduce(m, new int[]{k1, k2, k3}); - return new F2m(m, k1, k2, k3, squared); + return new F2m(m, ks, x.modSquare(m, ks)); } - public ECFieldElement invert() { - // Inversion in F2m using the extended Euclidean algorithm - // Input: A nonzero polynomial a(z) of degree at most m-1 - // Output: a(z)^(-1) mod f(z) - - // u(z) := a(z) - IntArray uz = (IntArray)this.x.clone(); - - // v(z) := f(z) - IntArray vz = new IntArray(t); - vz.setBit(m); - vz.setBit(0); - vz.setBit(this.k1); - if (this.representation == PPB) - { - vz.setBit(this.k2); - vz.setBit(this.k3); - } - - // g1(z) := 1, g2(z) := 0 - IntArray g1z = new IntArray(t); - g1z.setBit(0); - IntArray g2z = new IntArray(t); - - // while u != 0 - while (!uz.isZero()) -// while (uz.getUsedLength() > 0) -// while (uz.bitLength() > 1) - { - // j := deg(u(z)) - deg(v(z)) - int j = uz.bitLength() - vz.bitLength(); - - // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j - if (j < 0) - { - final IntArray uzCopy = uz; - uz = vz; - vz = uzCopy; - - final IntArray g1zCopy = g1z; - g1z = g2z; - g2z = g1zCopy; - - j = -j; - } - - // u(z) := u(z) + z^j * v(z) - // Note, that no reduction modulo f(z) is required, because - // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z))) - // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z)) - // = deg(u(z)) - // uz = uz.xor(vz.shiftLeft(j)); - // jInt = n / 32 - int jInt = j >> 5; - // jInt = n % 32 - int jBit = j & 0x1F; - IntArray vzShift = vz.shiftLeft(jBit); - uz.addShifted(vzShift, jInt); - - // g1(z) := g1(z) + z^j * g2(z) -// g1z = g1z.xor(g2z.shiftLeft(j)); - IntArray g2zShift = g2z.shiftLeft(jBit); - g1z.addShifted(g2zShift, jInt); - - } - return new ECFieldElement.F2m( - this.m, this.k1, this.k2, this.k3, g2z); + return new ECFieldElement.F2m(this.m, this.ks, this.x.modInverse(m, ks)); } public ECFieldElement sqrt() @@ -1143,7 +1252,7 @@ public abstract class ECFieldElement */ public int getK1() { - return this.k1; + return this.ks[0]; } /** @@ -1154,7 +1263,7 @@ public abstract class ECFieldElement */ public int getK2() { - return this.k2; + return this.ks.length >= 2 ? this.ks[1] : 0; } /** @@ -1165,7 +1274,7 @@ public abstract class ECFieldElement */ public int getK3() { - return this.k3; + return this.ks.length >= 3 ? this.ks[2] : 0; } public boolean equals(Object anObject) @@ -1182,15 +1291,15 @@ public abstract class ECFieldElement ECFieldElement.F2m b = (ECFieldElement.F2m)anObject; - return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2) - && (this.k3 == b.k3) + return ((this.m == b.m) && (this.representation == b.representation) + && Arrays.areEqual(this.ks, b.ks) && (this.x.equals(b.x))); } public int hashCode() { - return x.hashCode() ^ m ^ k1 ^ k2 ^ k3; + return x.hashCode() ^ m ^ Arrays.hashCode(ks); } } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java index 4d72e33..da1013a 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java @@ -6,14 +6,14 @@ import java.math.BigInteger; * Interface for classes encapsulating a point multiplication algorithm * for <code>ECPoint</code>s. */ -interface ECMultiplier +public interface ECMultiplier { /** * Multiplies the <code>ECPoint p</code> by <code>k</code>, i.e. * <code>p</code> is added <code>k</code> times to itself. * @param p The <code>ECPoint</code> to be multiplied. - * @param k The factor by which <code>p</code> i multiplied. + * @param k The factor by which <code>p</code> is multiplied. * @return <code>p</code> multiplied by <code>k</code>. */ - ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo); + ECPoint multiply(ECPoint p, BigInteger k); } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java index cbc5aaf..7f740e4 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java @@ -2,59 +2,324 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; -import org.bouncycastle.asn1.x9.X9IntegerConverter; - /** * base class for points on elliptic curves. */ public abstract class ECPoint { - ECCurve curve; - ECFieldElement x; - ECFieldElement y; + protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0]; - protected boolean withCompression; + protected static ECFieldElement[] getInitialZCoords(ECCurve curve) + { + // Cope with null curve, most commonly used by implicitlyCa + int coord = null == curve ? ECCurve.COORD_AFFINE : curve.getCoordinateSystem(); - protected ECMultiplier multiplier = null; + switch (coord) + { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + return EMPTY_ZS; + default: + break; + } - protected PreCompInfo preCompInfo = null; + ECFieldElement one = curve.fromBigInteger(ECConstants.ONE); - private static X9IntegerConverter converter = new X9IntegerConverter(); + switch (coord) + { + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + return new ECFieldElement[]{ one }; + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + return new ECFieldElement[]{ one, one, one }; + case ECCurve.COORD_JACOBIAN_MODIFIED: + return new ECFieldElement[]{ one, curve.getA() }; + default: + throw new IllegalArgumentException("unknown coordinate system"); + } + } + + protected ECCurve curve; + protected ECFieldElement x; + protected ECFieldElement y; + protected ECFieldElement[] zs; + + protected boolean withCompression; + + protected PreCompInfo preCompInfo = null; protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y) { + this(curve, x, y, getInitialZCoords(curve)); + } + + protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) + { this.curve = curve; this.x = x; this.y = y; + this.zs = zs; } - + public ECCurve getCurve() { return curve; } - + + protected int getCurveCoordinateSystem() + { + // Cope with null curve, most commonly used by implicitlyCa + return null == curve ? ECCurve.COORD_AFFINE : curve.getCoordinateSystem(); + } + + /** + * Normalizes this point, and then returns the affine x-coordinate. + * + * Note: normalization can be expensive, this method is deprecated in favour + * of caller-controlled normalization. + * + * @deprecated Use getAffineXCoord, or normalize() and getXCoord(), instead + */ public ECFieldElement getX() { - return x; + return normalize().getXCoord(); } + + /** + * Normalizes this point, and then returns the affine y-coordinate. + * + * Note: normalization can be expensive, this method is deprecated in favour + * of caller-controlled normalization. + * + * @deprecated Use getAffineYCoord, or normalize() and getYCoord(), instead + */ public ECFieldElement getY() { + return normalize().getYCoord(); + } + + /** + * Returns the affine x-coordinate after checking that this point is normalized. + * + * @return The affine x-coordinate of this point + * @throws IllegalStateException if the point is not normalized + */ + public ECFieldElement getAffineXCoord() + { + checkNormalized(); + return getXCoord(); + } + + /** + * Returns the affine y-coordinate after checking that this point is normalized + * + * @return The affine y-coordinate of this point + * @throws IllegalStateException if the point is not normalized + */ + public ECFieldElement getAffineYCoord() + { + checkNormalized(); + return getYCoord(); + } + + /** + * Returns the x-coordinate. + * + * Caution: depending on the curve's coordinate system, this may not be the same value as in an + * affine coordinate system; use normalize() to get a point where the coordinates have their + * affine values, or use getAffineXCoord if you expect the point to already have been + * normalized. + * + * @return the x-coordinate of this point + */ + public ECFieldElement getXCoord() + { + return x; + } + + /** + * Returns the y-coordinate. + * + * Caution: depending on the curve's coordinate system, this may not be the same value as in an + * affine coordinate system; use normalize() to get a point where the coordinates have their + * affine values, or use getAffineYCoord if you expect the point to already have been + * normalized. + * + * @return the y-coordinate of this point + */ + public ECFieldElement getYCoord() + { return y; } + public ECFieldElement getZCoord(int index) + { + return (index < 0 || index >= zs.length) ? null : zs[index]; + } + + public ECFieldElement[] getZCoords() + { + int zsLen = zs.length; + if (zsLen == 0) + { + return zs; + } + ECFieldElement[] copy = new ECFieldElement[zsLen]; + System.arraycopy(zs, 0, copy, 0, zsLen); + return copy; + } + + protected ECFieldElement getRawXCoord() + { + return x; + } + + protected ECFieldElement getRawYCoord() + { + return y; + } + + protected void checkNormalized() + { + if (!isNormalized()) + { + throw new IllegalStateException("point not in normal form"); + } + } + + public boolean isNormalized() + { + int coord = this.getCurveCoordinateSystem(); + + return coord == ECCurve.COORD_AFFINE + || coord == ECCurve.COORD_LAMBDA_AFFINE + || isInfinity() + || zs[0].bitLength() == 1; + } + + /** + * Normalization ensures that any projective coordinate is 1, and therefore that the x, y + * coordinates reflect those of the equivalent point in an affine coordinate system. + * + * @return a new ECPoint instance representing the same point, but with normalized coordinates + */ + public ECPoint normalize() + { + if (this.isInfinity()) + { + return this; + } + + switch (this.getCurveCoordinateSystem()) + { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + { + return this; + } + default: + { + ECFieldElement Z1 = getZCoord(0); + if (Z1.bitLength() == 1) + { + return this; + } + + return normalize(Z1.invert()); + } + } + } + + ECPoint normalize(ECFieldElement zInv) + { + switch (this.getCurveCoordinateSystem()) + { + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + return createScaledPoint(zInv, zInv); + } + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + ECFieldElement zInv2 = zInv.square(), zInv3 = zInv2.multiply(zInv); + return createScaledPoint(zInv2, zInv3); + } + default: + { + throw new IllegalStateException("not a projective coordinate system"); + } + } + } + + protected ECPoint createScaledPoint(ECFieldElement sx, ECFieldElement sy) + { + return this.getCurve().createRawPoint(getRawXCoord().multiply(sx), getRawYCoord().multiply(sy), this.withCompression); + } + public boolean isInfinity() { - return x == null && y == null; + return x == null || y == null || (zs.length > 0 && zs[0].isZero()); } public boolean isCompressed() { - return withCompression; + return this.withCompression; + } + + public boolean equals(ECPoint other) + { + if (null == other) + { + return false; + } + + ECCurve c1 = this.getCurve(), c2 = other.getCurve(); + boolean n1 = (null == c1), n2 = (null == c2); + boolean i1 = isInfinity(), i2 = other.isInfinity(); + + if (i1 || i2) + { + return (i1 && i2) && (n1 || n2 || c1.equals(c2)); + } + + ECPoint p1 = this, p2 = other; + if (n1 && n2) + { + // Points with null curve are in affine form, so already normalized + } + else if (n1) + { + p2 = p2.normalize(); + } + else if (n2) + { + p1 = p1.normalize(); + } + else if (!c1.equals(c2)) + { + return false; + } + else + { + // TODO Consider just requiring already normalized, to avoid silent performance degradation + + ECPoint[] points = new ECPoint[]{ this, c1.importPoint(p2) }; + + // TODO This is a little strong, really only requires coZNormalizeAll to get Zs equal + c1.normalizeAll(points); + + p1 = points[0]; + p2 = points[1]; + } + + return p1.getXCoord().equals(p2.getXCoord()) && p1.getYCoord().equals(p2.getYCoord()); } - public boolean equals( - Object other) + public boolean equals(Object other) { if (other == this) { @@ -66,69 +331,117 @@ public abstract class ECPoint return false; } - ECPoint o = (ECPoint)other; + return equals((ECPoint)other); + } - if (this.isInfinity()) + public int hashCode() + { + ECCurve c = this.getCurve(); + int hc = (null == c) ? 0 : ~c.hashCode(); + + if (!this.isInfinity()) { - return o.isInfinity(); + // TODO Consider just requiring already normalized, to avoid silent performance degradation + + ECPoint p = normalize(); + + hc ^= p.getXCoord().hashCode() * 17; + hc ^= p.getYCoord().hashCode() * 257; } - return x.equals(o.x) && y.equals(o.y); + return hc; } - public int hashCode() + public String toString() { if (this.isInfinity()) { - return 0; + return "INF"; } - - return x.hashCode() ^ y.hashCode(); + + StringBuffer sb = new StringBuffer(); + sb.append('('); + sb.append(getRawXCoord()); + sb.append(','); + sb.append(getRawYCoord()); + for (int i = 0; i < zs.length; ++i) + { + sb.append(','); + sb.append(zs[i]); + } + sb.append(')'); + return sb.toString(); } -// /** -// * Mainly for testing. Explicitly set the <code>ECMultiplier</code>. -// * @param multiplier The <code>ECMultiplier</code> to be used to multiply -// * this <code>ECPoint</code>. -// */ -// public void setECMultiplier(ECMultiplier multiplier) -// { -// this.multiplier = multiplier; -// } + public byte[] getEncoded() + { + return getEncoded(this.withCompression); + } /** - * Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s - * to save the precomputation for this <code>ECPoint</code> to store the - * precomputation result for use by subsequent multiplication. - * @param preCompInfo The values precomputed by the - * <code>ECMultiplier</code>. + * return the field element encoded with point compression. (S 4.3.6) */ - void setPreCompInfo(PreCompInfo preCompInfo) + public byte[] getEncoded(boolean compressed) { - this.preCompInfo = preCompInfo; - } + if (this.isInfinity()) + { + return new byte[1]; + } - public byte[] getEncoded() - { - return getEncoded(withCompression); + ECPoint normed = normalize(); + + byte[] X = normed.getXCoord().getEncoded(); + + if (compressed) + { + byte[] PO = new byte[X.length + 1]; + PO[0] = (byte)(normed.getCompressionYTilde() ? 0x03 : 0x02); + System.arraycopy(X, 0, PO, 1, X.length); + return PO; + } + + byte[] Y = normed.getYCoord().getEncoded(); + + byte[] PO = new byte[X.length + Y.length + 1]; + PO[0] = 0x04; + System.arraycopy(X, 0, PO, 1, X.length); + System.arraycopy(Y, 0, PO, X.length + 1, Y.length); + return PO; } - public abstract byte[] getEncoded(boolean compressed); + protected abstract boolean getCompressionYTilde(); public abstract ECPoint add(ECPoint b); - public abstract ECPoint subtract(ECPoint b); + public abstract ECPoint negate(); - public abstract ECPoint twice(); - /** - * Sets the default <code>ECMultiplier</code>, unless already set. - */ - synchronized void assertECMultiplier() + public abstract ECPoint subtract(ECPoint b); + + public ECPoint timesPow2(int e) { - if (this.multiplier == null) + if (e < 0) + { + throw new IllegalArgumentException("'e' cannot be negative"); + } + + ECPoint p = this; + while (--e >= 0) { - this.multiplier = new FpNafMultiplier(); + p = p.twice(); } + return p; + } + + public abstract ECPoint twice(); + + public ECPoint twicePlus(ECPoint b) + { + return twice().add(b); + } + + public ECPoint threeTimes() + { + return twicePlus(this); } /** @@ -138,23 +451,7 @@ public abstract class ECPoint */ public ECPoint multiply(BigInteger k) { - if (k.signum() < 0) - { - throw new IllegalArgumentException("The multiplicator cannot be negative"); - } - - if (this.isInfinity()) - { - return this; - } - - if (k.signum() == 0) - { - return this.curve.getInfinity(); - } - - assertECMultiplier(); - return this.multiplier.multiply(this, k, preCompInfo); + return this.getCurve().getMultiplier().multiply(this, k); } /** @@ -162,13 +459,14 @@ public abstract class ECPoint */ public static class Fp extends ECPoint { - /** * 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 Fp(ECCurve curve, ECFieldElement x, ECFieldElement y) { @@ -182,6 +480,8 @@ public abstract class ECPoint * @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) { @@ -194,112 +494,537 @@ public abstract class ECPoint this.withCompression = withCompression; } - - /** - * return the field element encoded with point compression. (S 4.3.6) - */ - public byte[] getEncoded(boolean compressed) + + Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) { - if (this.isInfinity()) + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected boolean getCompressionYTilde() + { + return this.getAffineYCoord().testBitZero(); + } + + public ECFieldElement getZCoord(int index) + { + if (index == 1 && ECCurve.COORD_JACOBIAN_MODIFIED == this.getCurveCoordinateSystem()) { - return new byte[1]; + return getJacobianModifiedW(); } - int qLength = converter.getByteLength(x); - - if (compressed) + return super.getZCoord(index); + } + + // B.3 pg 62 + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) { - byte PC; - - if (this.getY().toBigInteger().testBit(0)) + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + int coord = curve.getCoordinateSystem(); + + ECFieldElement X1 = this.x, Y1 = this.y; + ECFieldElement X2 = b.x, Y2 = b.y; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement dx = X2.subtract(X1), dy = Y2.subtract(Y1); + + if (dx.isZero()) { - PC = 0x03; + if (dy.isZero()) + { + // this == b, i.e. this must be doubled + return twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); } - else + + ECFieldElement gamma = dy.divide(dx); + 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); + } + + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Z1 = this.zs[0]; + ECFieldElement Z2 = b.zs[0]; + + boolean Z1IsOne = Z1.bitLength() == 1; + boolean Z2IsOne = Z2.bitLength() == 1; + + ECFieldElement u1 = Z1IsOne ? Y2 : Y2.multiply(Z1); + ECFieldElement u2 = Z2IsOne ? Y1 : Y1.multiply(Z2); + ECFieldElement u = u1.subtract(u2); + ECFieldElement v1 = Z1IsOne ? X2 : X2.multiply(Z1); + ECFieldElement v2 = Z2IsOne ? X1 : X1.multiply(Z2); + ECFieldElement v = v1.subtract(v2); + + // Check if b == this or b == -this + if (v.isZero()) { - PC = 0x02; + if (u.isZero()) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); } + + // TODO Optimize for when w == 1 + ECFieldElement w = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.multiply(Z2); + ECFieldElement vSquared = v.square(); + ECFieldElement vCubed = vSquared.multiply(v); + ECFieldElement vSquaredV2 = vSquared.multiply(v2); + ECFieldElement A = u.square().multiply(w).subtract(vCubed).subtract(two(vSquaredV2)); + + ECFieldElement X3 = v.multiply(A); + ECFieldElement Y3 = vSquaredV2.subtract(A).multiply(u).subtract(vCubed.multiply(u2)); + ECFieldElement Z3 = vCubed.multiply(w); + + return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + ECFieldElement Z1 = this.zs[0]; + ECFieldElement Z2 = b.zs[0]; + + boolean Z1IsOne = Z1.bitLength() == 1; + + ECFieldElement X3, Y3, Z3, Z3Squared = null; + + if (!Z1IsOne && Z1.equals(Z2)) + { + // TODO Make this available as public method coZAdd? + + ECFieldElement dx = X1.subtract(X2), dy = Y1.subtract(Y2); + if (dx.isZero()) + { + if (dy.isZero()) + { + return twice(); + } + return curve.getInfinity(); + } + + ECFieldElement C = dx.square(); + ECFieldElement W1 = X1.multiply(C), W2 = X2.multiply(C); + ECFieldElement A1 = W1.subtract(W2).multiply(Y1); + + X3 = dy.square().subtract(W1).subtract(W2); + Y3 = W1.subtract(X3).multiply(dy).subtract(A1); + Z3 = dx; + + if (Z1IsOne) + { + Z3Squared = C; + } + else + { + Z3 = Z3.multiply(Z1); + } + } + else + { + ECFieldElement Z1Squared, U2, S2; + if (Z1IsOne) + { + Z1Squared = Z1; U2 = X2; S2 = Y2; + } + else + { + Z1Squared = Z1.square(); + U2 = Z1Squared.multiply(X2); + ECFieldElement Z1Cubed = Z1Squared.multiply(Z1); + S2 = Z1Cubed.multiply(Y2); + } + + boolean Z2IsOne = Z2.bitLength() == 1; + ECFieldElement Z2Squared, U1, S1; + if (Z2IsOne) + { + Z2Squared = Z2; U1 = X1; S1 = Y1; + } + else + { + Z2Squared = Z2.square(); + U1 = Z2Squared.multiply(X1); + ECFieldElement Z2Cubed = Z2Squared.multiply(Z2); + S1 = Z2Cubed.multiply(Y1); + } + + ECFieldElement H = U1.subtract(U2); + ECFieldElement R = S1.subtract(S2); + + // Check if b == this or b == -this + if (H.isZero()) + { + if (R.isZero()) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } - byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength); - byte[] PO = new byte[X.length + 1]; + ECFieldElement HSquared = H.square(); + ECFieldElement G = HSquared.multiply(H); + ECFieldElement V = HSquared.multiply(U1); - PO[0] = PC; - System.arraycopy(X, 0, PO, 1, X.length); + X3 = R.square().add(G).subtract(two(V)); + Y3 = V.subtract(X3).multiply(R).subtract(S1.multiply(G)); - return PO; + Z3 = H; + if (!Z1IsOne) + { + Z3 = Z3.multiply(Z1); + } + if (!Z2IsOne) + { + Z3 = Z3.multiply(Z2); + } + + // Alternative calculation of Z3 using fast square + // X3 = four(X3); + // Y3 = eight(Y3); + // Z3 = doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).multiply(H); + + if (Z3 == H) + { + Z3Squared = HSquared; + } + } + + ECFieldElement[] zs; + if (coord == ECCurve.COORD_JACOBIAN_MODIFIED) + { + // TODO If the result will only be used in a subsequent addition, we don't need W3 + ECFieldElement W3 = calculateJacobianModifiedW(Z3, Z3Squared); + + zs = new ECFieldElement[]{ Z3, W3 }; + } + else + { + zs = new ECFieldElement[]{ Z3 }; + } + + return new ECPoint.Fp(curve, X3, Y3, zs, this.withCompression); } - else + default: + { + throw new IllegalStateException("unsupported coordinate system"); + } + } + } + + // B.3 pg 62 + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + int coord = curve.getCoordinateSystem(); + + ECFieldElement X1 = this.x; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement X1Squared = X1.square(); + ECFieldElement gamma = three(X1Squared).add(this.getCurve().getA()).divide(two(Y1)); + 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); + } + + case ECCurve.COORD_HOMOGENEOUS: { - byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength); - byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), qLength); - byte[] PO = new byte[X.length + Y.length + 1]; + ECFieldElement Z1 = this.zs[0]; + + boolean Z1IsOne = Z1.bitLength() == 1; + ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.square(); + + // TODO Optimize for small negative a4 and -3 + ECFieldElement w = curve.getA(); + if (!Z1IsOne) + { + w = w.multiply(Z1Squared); + } + w = w.add(three(X1.square())); - PO[0] = 0x04; - System.arraycopy(X, 0, PO, 1, X.length); - System.arraycopy(Y, 0, PO, X.length + 1, Y.length); + ECFieldElement s = Z1IsOne ? Y1 : Y1.multiply(Z1); + ECFieldElement t = Z1IsOne ? Y1.square() : s.multiply(Y1); + ECFieldElement B = X1.multiply(t); + ECFieldElement _4B = four(B); + ECFieldElement h = w.square().subtract(two(_4B)); + + ECFieldElement X3 = two(h.multiply(s)); + ECFieldElement Y3 = w.multiply(_4B.subtract(h)).subtract(two(two(t).square())); + ECFieldElement _4sSquared = Z1IsOne ? four(t) : two(s).square(); + ECFieldElement Z3 = two(_4sSquared).multiply(s); + + return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + + case ECCurve.COORD_JACOBIAN: + { + ECFieldElement Z1 = this.zs[0]; + + boolean Z1IsOne = Z1.bitLength() == 1; + ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.square(); + + ECFieldElement Y1Squared = Y1.square(); + ECFieldElement T = Y1Squared.square(); + + ECFieldElement a4 = curve.getA(); + ECFieldElement a4Neg = a4.negate(); + + ECFieldElement M, S; + if (a4Neg.toBigInteger().equals(BigInteger.valueOf(3))) + { + M = three(X1.add(Z1Squared).multiply(X1.subtract(Z1Squared))); + S = four(Y1Squared.multiply(X1)); + } + else + { + ECFieldElement X1Squared = X1.square(); + M = three(X1Squared); + if (Z1IsOne) + { + M = M.add(a4); + } + else + { + ECFieldElement Z1Pow4 = Z1Squared.square(); + if (a4Neg.bitLength() < a4.bitLength()) + { + M = M.subtract(Z1Pow4.multiply(a4Neg)); + } + else + { + M = M.add(Z1Pow4.multiply(a4)); + } + } + S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T)); + } + + ECFieldElement X3 = M.square().subtract(two(S)); + ECFieldElement Y3 = S.subtract(X3).multiply(M).subtract(eight(T)); + + ECFieldElement Z3 = two(Y1); + if (!Z1IsOne) + { + Z3 = Z3.multiply(Z1); + } - return PO; + // 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); + } + + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + return twiceJacobianModified(true); + } + + default: + { + throw new IllegalStateException("unsupported coordinate system"); + } } } - // B.3 pg 62 - public ECPoint add(ECPoint b) + public ECPoint twicePlus(ECPoint b) { + if (this == b) + { + return threeTimes(); + } if (this.isInfinity()) { return b; } - if (b.isInfinity()) { - return this; + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; } - // Check if b = this or b = -this - if (this.x.equals(b.x)) + ECCurve curve = this.getCurve(); + int coord = curve.getCoordinateSystem(); + + switch (coord) + { + case ECCurve.COORD_AFFINE: { - if (this.y.equals(b.y)) + ECFieldElement X1 = this.x; + ECFieldElement X2 = b.x, Y2 = b.y; + + ECFieldElement dx = X2.subtract(X1), dy = Y2.subtract(Y1); + + if (dx.isZero()) { - // this = b, i.e. this must be doubled - return this.twice(); + if (dy.isZero()) + { + // this == b i.e. the result is 3P + return threeTimes(); + } + + // this == -b, i.e. the result is P + return this; } - // this = -b, i.e. the result is the point at infinity - return this.curve.getInfinity(); - } + /* + * Optimized calculation of 2P + Q, as described in "Trading Inversions for + * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery. + */ - ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x)); + ECFieldElement X = dx.square(), Y = dy.square(); + ECFieldElement d = X.multiply(two(X1).add(X2)).subtract(Y); + if (d.isZero()) + { + return curve.getInfinity(); + } - ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x); - ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y); + ECFieldElement D = d.multiply(dx); + ECFieldElement I = D.invert(); + ECFieldElement L1 = d.multiply(I).multiply(dy); + ECFieldElement L2 = two(Y1).multiply(X).multiply(dx).multiply(I).subtract(L1); + 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, x3, y3, withCompression); + return new ECPoint.Fp(curve, X4, Y4, this.withCompression); + } + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + return twiceJacobianModified(false).add(b); + } + default: + { + return twice().add(b); + } + } } - // B.3 pg 62 - public ECPoint twice() + public ECPoint threeTimes() { - if (this.isInfinity()) + if (this.isInfinity() || this.y.isZero()) { - // Twice identity element (point at infinity) is identity return this; } - if (this.y.toBigInteger().signum() == 0) + ECCurve curve = this.getCurve(); + int coord = curve.getCoordinateSystem(); + + switch (coord) + { + case ECCurve.COORD_AFFINE: { - // if y1 == 0, then (x1, y1) == (x1, -y1) - // and hence this = -this and thus 2(x1, y1) == infinity - return this.curve.getInfinity(); + ECFieldElement X1 = this.x, Y1 = this.y; + + ECFieldElement _2Y1 = two(Y1); + ECFieldElement X = _2Y1.square(); + ECFieldElement Z = three(X1.square()).add(this.getCurve().getA()); + ECFieldElement Y = Z.square(); + + ECFieldElement d = three(X1).multiply(X).subtract(Y); + if (d.isZero()) + { + return this.getCurve().getInfinity(); + } + + ECFieldElement D = d.multiply(_2Y1); + ECFieldElement I = D.invert(); + ECFieldElement L1 = d.multiply(I).multiply(Z); + ECFieldElement L2 = X.square().multiply(I).subtract(L1); + + 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); + } + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + return twiceJacobianModified(false).add(this); + } + default: + { + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); } + } + } - ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2)); - ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3)); - ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO)); + protected ECFieldElement two(ECFieldElement x) + { + return x.add(x); + } - ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO)); - ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y); - - return new ECPoint.Fp(curve, x3, y3, this.withCompression); + protected ECFieldElement three(ECFieldElement x) + { + return two(x).add(x); + } + + protected ECFieldElement four(ECFieldElement x) + { + return two(two(x)); + } + + protected ECFieldElement eight(ECFieldElement x) + { + return four(two(x)); + } + + protected ECFieldElement doubleProductFromSquares(ECFieldElement a, ECFieldElement b, + ECFieldElement aSquared, ECFieldElement bSquared) + { + /* + * NOTE: If squaring in the field is faster than multiplication, then this is a quicker + * way to calculate 2.A.B, if A^2 and B^2 are already known. + */ + return a.add(b).square().subtract(aSquared).subtract(bSquared); } // D.3.2 pg 102 (see Note:) @@ -316,18 +1041,70 @@ public abstract class ECPoint public ECPoint negate() { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + int coord = curve.getCoordinateSystem(); + + 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.withCompression); } - /** - * Sets the default <code>ECMultiplier</code>, unless already set. - */ - synchronized void assertECMultiplier() + protected ECFieldElement calculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared) { - if (this.multiplier == null) + if (ZSquared == null) + { + ZSquared = Z.square(); + } + + ECFieldElement W = ZSquared.square(); + ECFieldElement a4 = this.getCurve().getA(); + ECFieldElement a4Neg = a4.negate(); + if (a4Neg.bitLength() < a4.bitLength()) { - this.multiplier = new WNafMultiplier(); + W = W.multiply(a4Neg).negate(); } + else + { + W = W.multiply(a4); + } + return W; + } + + protected ECFieldElement getJacobianModifiedW() + { + ECFieldElement W = this.zs[1]; + if (W == null) + { + // NOTE: Rarely, twicePlus will result in the need for a lazy W1 calculation here + this.zs[1] = W = calculateJacobianModifiedW(this.zs[0], null); + } + return W; + } + + protected ECPoint.Fp twiceJacobianModified(boolean calculateW) + { + ECFieldElement X1 = this.x, Y1 = this.y, Z1 = this.zs[0], W1 = getJacobianModifiedW(); + + ECFieldElement X1Squared = X1.square(); + ECFieldElement M = three(X1Squared).add(W1); + ECFieldElement Y1Squared = Y1.square(); + ECFieldElement T = Y1Squared.square(); + ECFieldElement S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T)); + ECFieldElement X3 = M.square().subtract(two(S)); + ECFieldElement _8T = eight(T); + ECFieldElement Y3 = M.multiply(S.subtract(X3)).subtract(_8T); + ECFieldElement W3 = calculateW ? two(_8T.multiply(W1)) : null; + ECFieldElement Z3 = two(Z1.bitLength() == 1 ? Y1 : Y1.multiply(Z1)); + + return new ECPoint.Fp(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }, this.withCompression); } } @@ -340,6 +1117,8 @@ public abstract class ECPoint * @param curve base curve * @param x x point * @param y y point + * + * @deprecated Use ECCurve.createPoint to construct points */ public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y) { @@ -351,6 +1130,8 @@ public abstract class ECPoint * @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) { @@ -360,71 +1141,91 @@ public abstract class ECPoint { 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(); } - /* (non-Javadoc) - * @see org.bouncycastle.math.ec.ECPoint#getEncoded() - */ - public byte[] getEncoded(boolean compressed) + F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) { - if (this.isInfinity()) - { - return new byte[1]; - } + super(curve, x, y, zs); + + this.withCompression = withCompression; + +// checkCurveEquation(); + } - int byteCount = converter.getByteLength(this.x); - byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount); - byte[] PO; + public ECFieldElement getYCoord() + { + int coord = this.getCurveCoordinateSystem(); - if (compressed) + switch (coord) + { + case ECCurve.COORD_LAMBDA_AFFINE: + case ECCurve.COORD_LAMBDA_PROJECTIVE: { - // See X9.62 4.3.6 and 4.2.2 - PO = new byte[byteCount + 1]; + // TODO The X == 0 stuff needs further thought + if (this.isInfinity() || x.isZero()) + { + return y; + } - PO[0] = 0x02; - // X9.62 4.2.2 and 4.3.6: - // if x = 0 then ypTilde := 0, else ypTilde is the rightmost - // bit of y * x^(-1) - // if ypTilde = 0, then PC := 02, else PC := 03 - // Note: PC === PO[0] - if (!(this.getX().toBigInteger().equals(ECConstants.ZERO))) + // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly + ECFieldElement X = x, L = y; + ECFieldElement Y = L.subtract(X).multiply(X); + if (ECCurve.COORD_LAMBDA_PROJECTIVE == coord) { - if (this.getY().multiply(this.getX().invert()) - .toBigInteger().testBit(0)) + ECFieldElement Z = zs[0]; + if (Z.bitLength() != 1) { - // ypTilde = 1, hence PC = 03 - PO[0] = 0x03; + Y = Y.divide(Z); } } - - System.arraycopy(X, 0, PO, 1, byteCount); + return Y; } - else + default: { - byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount); - - PO = new byte[byteCount + byteCount + 1]; - - PO[0] = 0x04; - System.arraycopy(X, 0, PO, 1, byteCount); - System.arraycopy(Y, 0, PO, byteCount + 1, byteCount); + return y; + } + } + } + + protected boolean getCompressionYTilde() + { + ECFieldElement X = this.getRawXCoord(); + if (X.isZero()) + { + return false; } - return PO; + ECFieldElement Y = this.getRawYCoord(); + + switch (this.getCurveCoordinateSystem()) + { + case ECCurve.COORD_LAMBDA_AFFINE: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + // Y is actually Lambda (X + Y/X) here + return Y.subtract(X).testBitZero(); + } + default: + { + return Y.divide(X).testBitZero(); + } + } } /** @@ -437,7 +1238,7 @@ public abstract class ECPoint private static void checkPoints(ECPoint a, ECPoint b) { // Check, if points are on the same curve - if (!(a.curve.equals(b.curve))) + if (a.curve != b.curve) { throw new IllegalArgumentException("Only points on the same " + "curve can be added or subtracted"); @@ -466,43 +1267,162 @@ public abstract class ECPoint */ public ECPoint.F2m addSimple(ECPoint.F2m b) { - ECPoint.F2m other = b; if (this.isInfinity()) { - return other; + return b; } - - if (other.isInfinity()) + if (b.isInfinity()) { return this; } - ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX(); - ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY(); + ECCurve curve = this.getCurve(); + int coord = curve.getCoordinateSystem(); + + ECFieldElement X1 = this.x; + ECFieldElement X2 = b.x; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement Y1 = this.y; + ECFieldElement Y2 = b.y; + + if (X1.equals(X2)) + { + if (Y1.equals(Y2)) + { + return (ECPoint.F2m)twice(); + } + + return (ECPoint.F2m)curve.getInfinity(); + } + + ECFieldElement sumX = X1.add(X2); + ECFieldElement L = Y1.add(Y2).divide(sumX); + + ECFieldElement X3 = L.square().add(L).add(sumX).add(curve.getA()); + ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); - // Check if other = this or other = -this - if (this.x.equals(x2)) + return new ECPoint.F2m(curve, X3, Y3, this.withCompression); + } + case ECCurve.COORD_HOMOGENEOUS: { - if (this.y.equals(y2)) + ECFieldElement Y1 = this.y, Z1 = this.zs[0]; + ECFieldElement Y2 = b.y, Z2 = b.zs[0]; + + boolean Z2IsOne = Z2.bitLength() == 1; + + ECFieldElement U1 = Z1.multiply(Y2); + ECFieldElement U2 = Z2IsOne ? Y1 : Y1.multiply(Z2); + ECFieldElement U = U1.subtract(U2); + ECFieldElement V1 = Z1.multiply(X2); + ECFieldElement V2 = Z2IsOne ? X1 : X1.multiply(Z2); + ECFieldElement V = V1.subtract(V2); + + if (V1.equals(V2)) { - // this = other, i.e. this must be doubled - return (ECPoint.F2m)this.twice(); + if (U1.equals(U2)) + { + return (ECPoint.F2m)twice(); + } + + return (ECPoint.F2m)curve.getInfinity(); } - // this = -other, i.e. the result is the point at infinity - return (ECPoint.F2m)this.curve.getInfinity(); + ECFieldElement VSq = V.square(); + ECFieldElement W = Z2IsOne ? Z1 : Z1.multiply(Z2); + ECFieldElement A = U.square().add(U.multiply(V).add(VSq.multiply(curve.getA()))).multiply(W).add(V.multiply(VSq)); + + ECFieldElement X3 = V.multiply(A); + ECFieldElement VSqZ2 = Z2IsOne ? VSq : VSq.multiply(Z2); + ECFieldElement Y3 = VSqZ2.multiply(U.multiply(X1).add(Y1.multiply(V))).add(A.multiply(U.add(V))); + ECFieldElement Z3 = VSq.multiply(V).multiply(W); + + return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); } + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + if (X1.isZero()) + { + return b.addSimple(this); + } - ECFieldElement.F2m lambda - = (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2)); + ECFieldElement L1 = this.y, Z1 = this.zs[0]; + ECFieldElement L2 = b.y, Z2 = b.zs[0]; + + boolean Z1IsOne = Z1.bitLength() == 1; + ECFieldElement U2 = X2, S2 = L2; + if (!Z1IsOne) + { + U2 = U2.multiply(Z1); + S2 = S2.multiply(Z1); + } - ECFieldElement.F2m x3 - = (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA()); + boolean Z2IsOne = Z2.bitLength() == 1; + ECFieldElement U1 = X1, S1 = L1; + if (!Z2IsOne) + { + U1 = U1.multiply(Z2); + S1 = S1.multiply(Z2); + } - ECFieldElement.F2m y3 - = (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y); + ECFieldElement A = S1.add(S2); + ECFieldElement B = U1.add(U2); - return new ECPoint.F2m(curve, x3, y3, withCompression); + if (B.isZero()) + { + if (A.isZero()) + { + return (ECPoint.F2m)twice(); + } + + return (ECPoint.F2m)curve.getInfinity(); + } + + ECFieldElement X3, L3, Z3; + if (X2.isZero()) + { + // TODO This can probably be optimized quite a bit + + ECFieldElement Y1 = getYCoord(), Y2 = L2; + ECFieldElement L = Y1.add(Y2).divide(X1); + + X3 = L.square().add(L).add(X1).add(curve.getA()); + ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); + L3 = X3.isZero() ? Y3 : Y3.divide(X3).add(X3); + Z3 = curve.fromBigInteger(ECConstants.ONE); + } + else + { + B = B.square(); + + ECFieldElement AU1 = A.multiply(U1); + ECFieldElement AU2 = A.multiply(U2); + ECFieldElement ABZ2 = A.multiply(B); + if (!Z2IsOne) + { + ABZ2 = ABZ2.multiply(Z2); + } + + X3 = AU1.multiply(AU2); + L3 = AU2.add(B).square().add(ABZ2.multiply(L1.add(Z1))); + + Z3 = ABZ2; + if (!Z1IsOne) + { + Z3 = Z3.multiply(Z1); + } + } + + return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + default: + { + throw new IllegalStateException("unsupported coordinate system"); + } + } } /* (non-Javadoc) @@ -534,59 +1454,279 @@ public abstract class ECPoint return addSimple((ECPoint.F2m)b.negate()); } - /* (non-Javadoc) - * @see org.bouncycastle.math.ec.ECPoint#twice() - */ + public ECPoint.F2m tau() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + int coord = curve.getCoordinateSystem(); + + ECFieldElement X1 = this.x; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + { + ECFieldElement Y1 = this.y; + return new ECPoint.F2m(curve, X1.square(), Y1.square(), this.withCompression); + } + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement Y1 = this.y, Z1 = this.zs[0]; + return new ECPoint.F2m(curve, X1.square(), Y1.square(), new ECFieldElement[]{ Z1.square() }, this.withCompression); + } + default: + { + throw new IllegalStateException("unsupported coordinate system"); + } + } + } + public ECPoint twice() { if (this.isInfinity()) { - // Twice identity element (point at infinity) is identity return this; } - if (this.x.toBigInteger().signum() == 0) + ECCurve curve = this.getCurve(); + + ECFieldElement X1 = this.x; + if (X1.isZero()) { - // if x1 == 0, then (x1, y1) == (x1, x1 + y1) - // and hence this = -this and thus 2(x1, y1) == infinity - return this.curve.getInfinity(); + // A point with X == 0 is it's own additive inverse + return curve.getInfinity(); } - ECFieldElement.F2m lambda - = (ECFieldElement.F2m)this.x.add(this.y.divide(this.x)); + int coord = curve.getCoordinateSystem(); - ECFieldElement.F2m x3 - = (ECFieldElement.F2m)lambda.square().add(lambda). - add(this.curve.getA()); + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement Y1 = this.y; - ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE); - ECFieldElement.F2m y3 - = (ECFieldElement.F2m)this.x.square().add( - x3.multiply(lambda.add(ONE))); + ECFieldElement L1 = Y1.divide(X1).add(X1); - return new ECPoint.F2m(this.curve, x3, y3, withCompression); - } + ECFieldElement X3 = L1.square().add(L1).add(curve.getA()); + ECFieldElement Y3 = X1.square().add(X3.multiply(L1.addOne())); - public ECPoint negate() - { - return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression); + return new ECPoint.F2m(curve, X3, Y3, this.withCompression); + } + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Y1 = this.y, Z1 = this.zs[0]; + + boolean Z1IsOne = Z1.bitLength() == 1; + ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); + ECFieldElement Y1Z1 = Z1IsOne ? Y1 : Y1.multiply(Z1); + + ECFieldElement X1Sq = X1.square(); + ECFieldElement S = X1Sq.add(Y1Z1); + ECFieldElement V = X1Z1; + ECFieldElement vSquared = V.square(); + ECFieldElement h = S.square().add(S.multiply(V)).add(curve.getA().multiply(vSquared)); + + ECFieldElement X3 = V.multiply(h); + ECFieldElement Y3 = h.multiply(S.add(V)).add(X1Sq.square().multiply(V)); + ECFieldElement Z3 = V.multiply(vSquared); + + return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement L1 = this.y, Z1 = this.zs[0]; + + boolean Z1IsOne = Z1.bitLength() == 1; + ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.multiply(Z1); + ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.square(); + ECFieldElement a = curve.getA(); + ECFieldElement aZ1Sq = Z1IsOne ? a : a.multiply(Z1Sq); + ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq); + + ECFieldElement X3 = T.square(); + ECFieldElement Z3 = Z1IsOne ? T : T.multiply(Z1Sq); + + ECFieldElement b = curve.getB(); + ECFieldElement L3; + if (b.bitLength() < (curve.getFieldSize() >> 1)) + { + ECFieldElement t1 = L1.add(X1).square(); + ECFieldElement t2 = aZ1Sq.square(); + ECFieldElement t3 = curve.getB().multiply(Z1Sq.square()); + L3 = t1.add(T).add(Z1Sq).multiply(t1).add(t2.add(t3)).add(X3).add(a.addOne().multiply(Z3)); + } + else + { + ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); + L3 = X1Z1.square().add(X3).add(T.multiply(L1Z1)).add(Z3); + } + + return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + default: + { + throw new IllegalStateException("unsupported coordinate system"); + } + } } - /** - * Sets the appropriate <code>ECMultiplier</code>, unless already set. - */ - synchronized void assertECMultiplier() + public ECPoint twicePlus(ECPoint b) { - if (this.multiplier == null) + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) { - if (((ECCurve.F2m)this.curve).isKoblitz()) + return twice(); + } + + ECCurve curve = this.getCurve(); + + ECFieldElement X1 = this.x; + if (X1.isZero()) + { + // A point with X == 0 is it's own additive inverse + return b; + } + + int coord = curve.getCoordinateSystem(); + + switch (coord) + { + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + // NOTE: twicePlus() only optimized for lambda-affine argument + ECFieldElement X2 = b.x, Z2 = b.zs[0]; + if (X2.isZero() || Z2.bitLength() != 1) { - this.multiplier = new WTauNafMultiplier(); + return twice().add(b); } - else + + ECFieldElement L1 = this.y, Z1 = this.zs[0]; + ECFieldElement L2 = b.y; + + ECFieldElement X1Sq = X1.square(); + ECFieldElement L1Sq = L1.square(); + ECFieldElement Z1Sq = Z1.square(); + ECFieldElement L1Z1 = L1.multiply(Z1); + + ECFieldElement T = curve.getA().multiply(Z1Sq).add(L1Sq).add(L1Z1); + ECFieldElement L2plus1 = L2.addOne(); + ECFieldElement A = curve.getA().add(L2plus1).multiply(Z1Sq).add(L1Sq).multiply(T).add(X1Sq.multiply(Z1Sq)); + ECFieldElement X2Z1Sq = X2.multiply(Z1Sq); + ECFieldElement B = X2Z1Sq.add(T).square(); + + ECFieldElement X3 = A.square().multiply(X2Z1Sq); + ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); + ECFieldElement L3 = A.add(B).square().multiply(T).add(L2plus1.multiply(Z3)); + + return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + default: + { + return twice().add(b); + } + } + } + + protected void checkCurveEquation() + { + if (this.isInfinity()) + { + return; + } + + ECFieldElement Z; + switch (this.getCurveCoordinateSystem()) + { + case ECCurve.COORD_LAMBDA_AFFINE: + Z = curve.fromBigInteger(ECConstants.ONE); + break; + case ECCurve.COORD_LAMBDA_PROJECTIVE: + Z = this.zs[0]; + break; + default: + return; + } + + if (Z.isZero()) + { + throw new IllegalStateException(); + } + + ECFieldElement X = this.x; + if (X.isZero()) + { + // NOTE: For x == 0, we expect the affine-y instead of the lambda-y + ECFieldElement Y = this.y; + if (!Y.square().equals(curve.getB().multiply(Z))) { - this.multiplier = new WNafMultiplier(); + throw new IllegalStateException(); } + + return; + } + + ECFieldElement L = this.y; + ECFieldElement XSq = X.square(); + ECFieldElement ZSq = Z.square(); + + ECFieldElement lhs = L.square().add(L.multiply(Z)).add(this.getCurve().getA().multiply(ZSq)).multiply(XSq); + ECFieldElement rhs = ZSq.square().multiply(this.getCurve().getB()).add(XSq.square()); + + if (!lhs.equals(rhs)) + { + throw new IllegalStateException("F2m Lambda-Projective invariant broken"); + } + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + ECFieldElement X = this.x; + if (X.isZero()) + { + return this; + } + + switch (this.getCurveCoordinateSystem()) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement Y = this.y; + return new ECPoint.F2m(curve, X, Y.add(X), this.withCompression); + } + 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); + } + case ECCurve.COORD_LAMBDA_AFFINE: + { + ECFieldElement L = this.y; + return new ECPoint.F2m(curve, X, L.addOne(), this.withCompression); + } + 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); + } + default: + { + throw new IllegalStateException("unsupported coordinate system"); + } } } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java deleted file mode 100644 index 35e601d..0000000 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.bouncycastle.math.ec; - -import java.math.BigInteger; - -/** - * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm. - */ -class FpNafMultiplier implements ECMultiplier -{ - /** - * D.3.2 pg 101 - * @see org.bouncycastle.math.ec.ECMultiplier#multiply(org.bouncycastle.math.ec.ECPoint, java.math.BigInteger) - */ - public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo) - { - // TODO Probably should try to add this - // BigInteger e = k.mod(n); // n == order of p - BigInteger e = k; - BigInteger h = e.multiply(BigInteger.valueOf(3)); - - ECPoint neg = p.negate(); - ECPoint R = p; - - for (int i = h.bitLength() - 2; i > 0; --i) - { - R = R.twice(); - - boolean hBit = h.testBit(i); - boolean eBit = e.testBit(i); - - if (hBit != eBit) - { - R = R.add(hBit ? p : neg); - } - } - - return R; - } -} diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java b/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java index ead38c4..34395a5 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java @@ -6,6 +6,60 @@ import java.math.BigInteger; class IntArray { +// private static int DEINTERLEAVE_MASK = 0x55555555; + + /* + * This expands 8 bit indices into 16 bit contents, by inserting 0s between bits. + * In a binary field, this operation is the same as squaring an 8 bit number. + */ + private static final int[] INTERLEAVE_TABLE = new int[] { 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, + 0x0015, 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, + 0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, 0x0400, 0x0401, 0x0404, + 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 0x0500, + 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, + 0x0555, 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, + 0x1051, 0x1054, 0x1055, 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 0x1140, 0x1141, 0x1144, + 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 0x1440, + 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, + 0x1515, 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, + 0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, 0x4100, 0x4101, 0x4104, + 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, 0x4400, + 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, + 0x4455, 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, + 0x4551, 0x4554, 0x4555, 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, 0x5040, 0x5041, 0x5044, + 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140, + 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, + 0x5415, 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, + 0x5511, 0x5514, 0x5515, 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 }; + + // For toString(); must have length 32 + private static final String ZEROES = "00000000000000000000000000000000"; + + private final static byte[] bitLengths = + { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 + }; + + public static int getWordLength(int bits) + { + return (bits + 31) >>> 5; + } + // TODO make m fixed for the IntArray, and hence compute T once and for all private int[] m_ints; @@ -22,16 +76,12 @@ class IntArray public IntArray(BigInteger bigInt) { - this(bigInt, 0); - } - - public IntArray(BigInteger bigInt, int minIntLen) - { - if (bigInt.signum() == -1) + if (bigInt == null || bigInt.signum() < 0) { - throw new IllegalArgumentException("Only positive Integers allowed"); + throw new IllegalArgumentException("invalid F2m field value"); } - if (bigInt.equals(ECConstants.ZERO)) + + if (bigInt.signum() == 0) { m_ints = new int[] { 0 }; return; @@ -48,14 +98,7 @@ class IntArray barrStart = 1; } int intLen = (barrLen + 3) / 4; - if (intLen < minIntLen) - { - m_ints = new int[minIntLen]; - } - else - { - m_ints = new int[intLen]; - } + m_ints = new int[intLen]; int iarrJ = intLen - 1; int rem = barrLen % 4 + barrStart; @@ -66,11 +109,7 @@ class IntArray for (; barrI < rem; barrI++) { temp <<= 8; - int barrBarrI = barr[barrI]; - if (barrBarrI < 0) - { - barrBarrI += 256; - } + int barrBarrI = barr[barrI] & 0xFF; temp |= barrBarrI; } m_ints[iarrJ--] = temp; @@ -82,11 +121,7 @@ class IntArray for (int i = 0; i < 4; i++) { temp <<= 8; - int barrBarrI = barr[barrI++]; - if (barrBarrI < 0) - { - barrBarrI += 256; - } + int barrBarrI = barr[barrI++] & 0xFF; temp |= barrBarrI; } m_ints[iarrJ] = temp; @@ -95,88 +130,86 @@ class IntArray public boolean isZero() { - return m_ints.length == 0 - || (m_ints[0] == 0 && getUsedLength() == 0); + int[] a = m_ints; + for (int i = 0; i < a.length; ++i) + { + if (a[i] != 0) + { + return false; + } + } + return true; } public int getUsedLength() { - int highestIntPos = m_ints.length; + return getUsedLengthFrom(m_ints.length); + } - if (highestIntPos < 1) + public int getUsedLengthFrom(int from) + { + int[] a = m_ints; + from = Math.min(from, a.length); + + if (from < 1) { return 0; } // Check if first element will act as sentinel - if (m_ints[0] != 0) + if (a[0] != 0) { - while (m_ints[--highestIntPos] == 0) + while (a[--from] == 0) { } - return highestIntPos + 1; + return from + 1; } do { - if (m_ints[--highestIntPos] != 0) + if (a[--from] != 0) { - return highestIntPos + 1; + return from + 1; } } - while (highestIntPos > 0); + while (from > 0); return 0; } - public int bitLength() + public int degree() { - // JDK 1.5: see Integer.numberOfLeadingZeros() - int intLen = getUsedLength(); - if (intLen == 0) - { - return 0; - } - - int last = intLen - 1; - int highest = m_ints[last]; - int bits = (last << 5) + 1; - - // A couple of binary search steps - if ((highest & 0xffff0000) != 0) + int i = m_ints.length, w; + do { - if ((highest & 0xff000000) != 0) - { - bits += 24; - highest >>>= 24; - } - else + if (i == 0) { - bits += 16; - highest >>>= 16; + return 0; } + w = m_ints[--i]; } - else if (highest > 0x000000ff) - { - bits += 8; - highest >>>= 8; - } + while (w == 0); - while (highest != 1) + return (i << 5) + bitLength(w); + } + + private static int bitLength(int w) + { + int t = w >>> 16; + if (t == 0) { - ++bits; - highest >>>= 1; + t = w >>> 8; + return (t == 0) ? bitLengths[w] : 8 + bitLengths[t]; } - return bits; + int u = t >>> 8; + return (u == 0) ? 16 + bitLengths[t] : 24 + bitLengths[u]; } private int[] resizedInts(int newLen) { int[] newInts = new int[newLen]; - int oldLen = m_ints.length; - int copyLen = oldLen < newLen ? oldLen : newLen; - System.arraycopy(m_ints, 0, newInts, 0, copyLen); + System.arraycopy(m_ints, 0, newInts, 0, Math.min(m_ints.length, newLen)); return newInts; } @@ -220,86 +253,128 @@ class IntArray return new BigInteger(1, barr); } - public void shiftLeft() + private static int shiftLeft(int[] x, int count) { - int usedLen = getUsedLength(); - if (usedLen == 0) + int prev = 0; + for (int i = 0; i < count; ++i) + { + int next = x[i]; + x[i] = (next << 1) | prev; + prev = next >>> 31; + } + return prev; + } + + public void addOneShifted(int shift) + { + if (shift >= m_ints.length) + { + m_ints = resizedInts(shift + 1); + } + + m_ints[shift] ^= 1; + } + + private void addShiftedByBits(IntArray other, int bits) + { + int words = bits >>> 5; + int shift = bits & 0x1F; + + if (shift == 0) + { + addShiftedByWords(other, words); + return; + } + + int otherUsedLen = other.getUsedLength(); + if (otherUsedLen == 0) { return; } - if (m_ints[usedLen - 1] < 0) + + int minLen = otherUsedLen + words + 1; + if (minLen > m_ints.length) { - // highest bit of highest used byte is set, so shifting left will - // make the IntArray one byte longer - usedLen++; - if (usedLen > m_ints.length) - { - // make the m_ints one byte longer, because we need one more - // byte which is not available in m_ints - m_ints = resizedInts(m_ints.length + 1); - } + m_ints = resizedInts(minLen); } - boolean carry = false; - for (int i = 0; i < usedLen; i++) + int shiftInv = 32 - shift, prev = 0; + for (int i = 0; i < otherUsedLen; ++i) { - // nextCarry is true if highest bit is set - boolean nextCarry = m_ints[i] < 0; - m_ints[i] <<= 1; - if (carry) - { - // set lowest bit - m_ints[i] |= 1; - } - carry = nextCarry; + int next = other.m_ints[i]; + m_ints[i + words] ^= (next << shift) | prev; + prev = next >>> shiftInv; } + m_ints[otherUsedLen + words] ^= prev; } - public IntArray shiftLeft(int n) + private static int addShiftedByBits(int[] x, int[] y, int count, int shift) { - int usedLen = getUsedLength(); - if (usedLen == 0) + int shiftInv = 32 - shift, prev = 0; + for (int i = 0; i < count; ++i) { - return this; + int next = y[i]; + x[i] ^= (next << shift) | prev; + prev = next >>> shiftInv; } + return prev; + } - if (n == 0) + private static int addShiftedByBits(int[] x, int xOff, int[] y, int yOff, int count, int shift) + { + int shiftInv = 32 - shift, prev = 0; + for (int i = 0; i < count; ++i) { - return this; + int next = y[yOff + i]; + x[xOff + i] ^= (next << shift) | prev; + prev = next >>> shiftInv; } + return prev; + } - if (n > 31) + public void addShiftedByWords(IntArray other, int words) + { + int otherUsedLen = other.getUsedLength(); + if (otherUsedLen == 0) { - throw new IllegalArgumentException("shiftLeft() for max 31 bits " - + ", " + n + "bit shift is not possible"); + return; } - int[] newInts = new int[usedLen + 1]; + int minLen = otherUsedLen + words; + if (minLen > m_ints.length) + { + m_ints = resizedInts(minLen); + } - int nm32 = 32 - n; - newInts[0] = m_ints[0] << n; - for (int i = 1; i < usedLen; i++) + for (int i = 0; i < otherUsedLen; i++) { - newInts[i] = (m_ints[i] << n) | (m_ints[i - 1] >>> nm32); + m_ints[words + i] ^= other.m_ints[i]; } - newInts[usedLen] = m_ints[usedLen - 1] >>> nm32; + } - return new IntArray(newInts); + private static void addShiftedByWords(int[] x, int xOff, int[] y, int count) + { + for (int i = 0; i < count; ++i) + { + x[xOff + i] ^= y[i]; + } } - public void addShifted(IntArray other, int shift) + private static void add(int[] x, int[] y, int count) { - int usedLenOther = other.getUsedLength(); - int newMinUsedLen = usedLenOther + shift; - if (newMinUsedLen > m_ints.length) + for (int i = 0; i < count; ++i) { - m_ints = resizedInts(newMinUsedLen); - //System.out.println("Resize required"); + x[i] ^= y[i]; } + } - for (int i = 0; i < usedLenOther; i++) + private static void distribute(int[] x, int dst1, int dst2, int src, int count) + { + for (int i = 0; i < count; ++i) { - m_ints[i + shift] ^= other.m_ints[i]; + int v = x[src + i]; + x[dst1 + i] ^= v; + x[dst2 + i] ^= v; } } @@ -308,10 +383,58 @@ class IntArray return m_ints.length; } + public void flipWord(int bit, int word) + { + int len = m_ints.length; + int n = bit >>> 5; + if (n < len) + { + int shift = bit & 0x1F; + if (shift == 0) + { + m_ints[n] ^= word; + } + else + { + m_ints[n] ^= word << shift; + if (++n < len) + { + m_ints[n] ^= word >>> (32 - shift); + } + } + } + } + + public int getWord(int bit) + { + int len = m_ints.length; + int n = bit >>> 5; + if (n >= len) + { + return 0; + } + int shift = bit & 0x1F; + if (shift == 0) + { + return m_ints[n]; + } + int result = m_ints[n] >>> shift; + if (++n < len) + { + result |= m_ints[n] << (32 - shift); + } + return result; + } + + public boolean testBitZero() + { + return m_ints.length > 0 && (m_ints[0] & 1) != 0; + } + public boolean testBit(int n) { // theInt = n / 32 - int theInt = n >> 5; + int theInt = n >>> 5; // theBit = n % 32 int theBit = n & 0x1F; int tester = 1 << theBit; @@ -321,7 +444,7 @@ class IntArray public void flipBit(int n) { // theInt = n / 32 - int theInt = n >> 5; + int theInt = n >>> 5; // theBit = n % 32 int theBit = n & 0x1F; int flipper = 1 << theBit; @@ -331,127 +454,344 @@ class IntArray public void setBit(int n) { // theInt = n / 32 - int theInt = n >> 5; + int theInt = n >>> 5; // theBit = n % 32 int theBit = n & 0x1F; int setter = 1 << theBit; m_ints[theInt] |= setter; } + public void clearBit(int n) + { + // theInt = n / 32 + int theInt = n >>> 5; + // theBit = n % 32 + int theBit = n & 0x1F; + int setter = 1 << theBit; + m_ints[theInt] &= ~setter; + } + public IntArray multiply(IntArray other, int m) { - // Lenght of c is 2m bits rounded up to the next int (32 bit) - int t = (m + 31) >> 5; - if (m_ints.length < t) + int aLen = getUsedLength(); + if (aLen == 0) + { + return new IntArray(1); + } + + int bLen = other.getUsedLength(); + if (bLen == 0) + { + return new IntArray(1); + } + + IntArray A = this, B = other; + if (aLen > bLen) + { + A = other; B = this; + int tmp = aLen; aLen = bLen; bLen = tmp; + } + + if (aLen == 1) + { + int a = A.m_ints[0]; + int[] b = B.m_ints; + int[] c = new int[aLen + bLen]; + if ((a & 1) != 0) + { + add(c, b, bLen); + } + int k = 1; + while ((a >>>= 1) != 0) + { + if ((a & 1) != 0) + { + addShiftedByBits(c, b, bLen, k); + } + ++k; + } + return new IntArray(c); + } + + // TODO It'd be better to be able to tune the width directly (need support for interleaving arbitrary widths) + int complexity = aLen <= 8 ? 1 : 2; + + int width = 1 << complexity; + int shifts = (32 >>> complexity); + + int bExt = bLen; + if ((B.m_ints[bLen - 1] >>> (33 - shifts)) != 0) { - m_ints = resizedInts(t); + ++bExt; } - IntArray b = new IntArray(other.resizedInts(other.getLength() + 1)); - IntArray c = new IntArray((m + m + 31) >> 5); - // IntArray c = new IntArray(t + t); - int testBit = 1; - for (int k = 0; k < 32; k++) + int cLen = bExt + aLen; + + int[] c = new int[cLen << width]; + System.arraycopy(B.m_ints, 0, c, 0, bLen); + interleave(A.m_ints, 0, c, bExt, aLen, complexity); + + int[] ci = new int[1 << width]; + for (int i = 1; i < ci.length; ++i) + { + ci[i] = ci[i - 1] + cLen; + } + + int MASK = (1 << width) - 1; + + int k = 0; + for (;;) { - for (int j = 0; j < t; j++) + for (int aPos = 0; aPos < aLen; ++aPos) { - if ((m_ints[j] & testBit) != 0) + int index = (c[bExt + aPos] >>> k) & MASK; + if (index != 0) { - // The kth bit of m_ints[j] is set - c.addShifted(b, j); + addShiftedByWords(c, aPos + ci[index], c, bExt); } } - testBit <<= 1; - b.shiftLeft(); - } - return c; - } - - // public IntArray multiplyLeftToRight(IntArray other, int m) { - // // Lenght of c is 2m bits rounded up to the next int (32 bit) - // int t = (m + 31) / 32; - // if (m_ints.length < t) { - // m_ints = resizedInts(t); - // } - // - // IntArray b = new IntArray(other.resizedInts(other.getLength() + 1)); - // IntArray c = new IntArray((m + m + 31) / 32); - // // IntArray c = new IntArray(t + t); - // int testBit = 1 << 31; - // for (int k = 31; k >= 0; k--) { - // for (int j = 0; j < t; j++) { - // if ((m_ints[j] & testBit) != 0) { - // // The kth bit of m_ints[j] is set - // c.addShifted(b, j); - // } - // } - // testBit >>>= 1; - // if (k > 0) { - // c.shiftLeft(); - // } - // } - // return c; - // } - - // TODO note, redPol.length must be 3 for TPB and 5 for PPB - public void reduce(int m, int[] redPol) - { - for (int i = m + m - 2; i >= m; i--) + + if ((k += width) >= 32) + { + break; + } + + shiftLeft(c, bExt); + } + + int ciPos = ci.length, pow2 = ciPos >>> 1, offset = 32; + while (--ciPos > 1) + { + if (ciPos == pow2) + { + offset -= shifts; + addShiftedByBits(c, ci[1], c, ci[pow2], cLen, offset); + pow2 >>>= 1; + } + else + { + distribute(c, ci[pow2], ci[ciPos - pow2], ci[ciPos], cLen); + } + } + + // TODO reduce in place to avoid extra copying + IntArray p = new IntArray(cLen); + System.arraycopy(c, ci[1], p.m_ints, 0, cLen); + return p; + } + +// private static void deInterleave(int[] x, int xOff, int[] z, int zOff, int count, int rounds) +// { +// for (int i = 0; i < count; ++i) +// { +// z[zOff + i] = deInterleave(x[zOff + i], rounds); +// } +// } +// +// private static int deInterleave(int x, int rounds) +// { +// while (--rounds >= 0) +// { +// x = deInterleave16(x & DEINTERLEAVE_MASK) | (deInterleave16((x >>> 1) & DEINTERLEAVE_MASK) << 16); +// } +// return x; +// } +// +// private static int deInterleave16(int x) +// { +// x = (x | (x >>> 1)) & 0x33333333; +// x = (x | (x >>> 2)) & 0x0F0F0F0F; +// x = (x | (x >>> 4)) & 0x00FF00FF; +// x = (x | (x >>> 8)) & 0x0000FFFF; +// return x; +// } + + public void reduce(int m, int[] ks) + { + int len = getUsedLength(); + int mLen = (m + 31) >>> 5; + if (len < mLen) + { + return; + } + + int _2m = m << 1; + int pos = Math.min(_2m - 2, (len << 5) - 1); + + int kMax = ks[ks.length - 1]; + if (kMax < m - 31) + { + reduceWordWise(pos, m, ks); + } + else + { + reduceBitWise(pos, m, ks); + } + + // Instead of flipping the high bits in the loop, explicitly clear any partial word above m bits + int partial = m & 0x1F; + if (partial != 0) + { + m_ints[mLen - 1] &= (1 << partial) - 1; + } + + if (len > mLen) + { + m_ints = resizedInts(mLen); + } + } + + private void reduceBitWise(int from, int m, int[] ks) + { + for (int i = from; i >= m; --i) { if (testBit(i)) { +// clearBit(i); int bit = i - m; flipBit(bit); - flipBit(i); - int l = redPol.length; - while (--l >= 0) + int j = ks.length; + while (--j >= 0) + { + flipBit(ks[j] + bit); + } + } + } + } + + private void reduceWordWise(int from, int m, int[] ks) + { + int pos = m + ((from - m) & ~0x1F); + for (int i = pos; i >= m; i -= 32) + { + int word = getWord(i); + if (word != 0) + { +// flipWord(i); + int bit = i - m; + flipWord(bit, word); + int j = ks.length; + while (--j >= 0) { - flipBit(redPol[l] + bit); + flipWord(ks[j] + bit, word); } } } - m_ints = resizedInts((m + 31) >> 5); } public IntArray square(int m) { - // TODO make the table static final - final int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40, - 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 }; + int len = getUsedLength(); + if (len == 0) + { + return this; + } - int t = (m + 31) >> 5; - if (m_ints.length < t) + int _2len = len << 1; + int[] r = new int[_2len]; + + int pos = 0; + while (pos < _2len) { - m_ints = resizedInts(t); + int mi = m_ints[pos >>> 1]; + r[pos++] = interleave16(mi & 0xFFFF); + r[pos++] = interleave16(mi >>> 16); } - IntArray c = new IntArray(t + t); + return new IntArray(r); + } - // TODO twice the same code, put in separate private method - for (int i = 0; i < t; i++) + private static void interleave(int[] x, int xOff, int[] z, int zOff, int count, int rounds) + { + for (int i = 0; i < count; ++i) { - int v0 = 0; - for (int j = 0; j < 4; j++) + z[zOff + i] = interleave(x[xOff + i], rounds); + } + } + + private static int interleave(int x, int rounds) + { + while (--rounds >= 0) + { + x = interleave16(x & 0xFFFF) | (interleave16(x >>> 16) << 1); + } + return x; + } + + private static int interleave16(int n) + { + return INTERLEAVE_TABLE[n & 0xFF] | INTERLEAVE_TABLE[n >>> 8] << 16; + } + + public IntArray modInverse(int m, int[] ks) + { + // Inversion in F2m using the extended Euclidean algorithm + // Input: A nonzero polynomial a(z) of degree at most m-1 + // Output: a(z)^(-1) mod f(z) + + int uzDegree = degree(); + if (uzDegree == 1) + { + return this; + } + + // u(z) := a(z) + IntArray uz = (IntArray)clone(); + + int t = getWordLength(m); + + // v(z) := f(z) + IntArray vz = new IntArray(t); + vz.setBit(m); + vz.setBit(0); + vz.setBit(ks[0]); + if (ks.length > 1) + { + vz.setBit(ks[1]); + vz.setBit(ks[2]); + } + + // g1(z) := 1, g2(z) := 0 + IntArray g1z = new IntArray(t); + g1z.setBit(0); + IntArray g2z = new IntArray(t); + + while (uzDegree != 0) + { + // j := deg(u(z)) - deg(v(z)) + int j = uzDegree - vz.degree(); + + // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j + if (j < 0) { - v0 = v0 >>> 8; - int u = (m_ints[i] >>> (j * 4)) & 0xF; - int w = table[u] << 24; - v0 |= w; + final IntArray uzCopy = uz; + uz = vz; + vz = uzCopy; + + final IntArray g1zCopy = g1z; + g1z = g2z; + g2z = g1zCopy; + + j = -j; } - c.m_ints[i + i] = v0; - v0 = 0; - int upper = m_ints[i] >>> 16; - for (int j = 0; j < 4; j++) + // u(z) := u(z) + z^j * v(z) + // Note, that no reduction modulo f(z) is required, because + // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z))) + // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z)) + // = deg(u(z)) + // uz = uz.xor(vz.shiftLeft(j)); + uz.addShiftedByBits(vz, j); + uzDegree = uz.degree(); + + // g1(z) := g1(z) + z^j * g2(z) +// g1z = g1z.xor(g2z.shiftLeft(j)); + if (uzDegree != 0) { - v0 = v0 >>> 8; - int u = (upper >>> (j * 4)) & 0xF; - int w = table[u] << 24; - v0 |= w; + g1z.addShiftedByBits(g2z, j); } - c.m_ints[i + i + 1] = v0; } - return c; + return g2z; } public boolean equals(Object o) @@ -482,7 +822,8 @@ class IntArray int hash = 1; for (int i = 0; i < usedLen; i++) { - hash = hash * 31 + m_ints[i]; + hash *= 31; + hash ^= m_ints[i]; } return hash; } @@ -494,25 +835,26 @@ class IntArray public String toString() { - int usedLen = getUsedLength(); - if (usedLen == 0) + int i = getUsedLength(); + if (i == 0) { return "0"; } - StringBuffer sb = new StringBuffer(Integer - .toBinaryString(m_ints[usedLen - 1])); - for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--) + StringBuffer sb = new StringBuffer(Integer.toBinaryString(m_ints[--i])); + while (--i >= 0) { - String hexString = Integer.toBinaryString(m_ints[iarrJ]); + String s = Integer.toBinaryString(m_ints[i]); - // Add leading zeroes, except for highest significant int - for (int i = hexString.length(); i < 8; i++) + // Add leading zeroes, except for highest significant word + int len = s.length(); + if (len < 32) { - hexString = "0" + hexString; + sb.append(ZEROES.substring(len)); } - sb.append(hexString); + + sb.append(s); } return sb.toString(); } -} +}
\ No newline at end of file diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java b/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java new file mode 100644 index 0000000..7e8b172 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java @@ -0,0 +1,1995 @@ +package org.bouncycastle.math.ec; + +import org.bouncycastle.util.Arrays; + +import java.math.BigInteger; + +class LongArray +{ +// private static long DEINTERLEAVE_MASK = 0x5555555555555555L; + + /* + * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits. + * In a binary field, this operation is the same as squaring an 8 bit number. + */ + private static final int[] INTERLEAVE2_TABLE = new int[] + { + 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, + 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, + 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, + 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, + 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, + 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, + 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, + 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, + 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, + 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, + 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, + 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, + 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, + 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, + 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, + 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, + 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, + 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, + 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, + 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, + 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, + 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, + 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, + 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, + 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, + 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, + 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, + 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, + 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, + 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, + 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, + 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 + }; + + /* + * This expands 7 bit indices into 21 bit contents (high bit 18), by inserting 0s between bits. + */ + private static final int[] INTERLEAVE3_TABLE = new int[] + { + 0x00000, 0x00001, 0x00008, 0x00009, 0x00040, 0x00041, 0x00048, 0x00049, + 0x00200, 0x00201, 0x00208, 0x00209, 0x00240, 0x00241, 0x00248, 0x00249, + 0x01000, 0x01001, 0x01008, 0x01009, 0x01040, 0x01041, 0x01048, 0x01049, + 0x01200, 0x01201, 0x01208, 0x01209, 0x01240, 0x01241, 0x01248, 0x01249, + 0x08000, 0x08001, 0x08008, 0x08009, 0x08040, 0x08041, 0x08048, 0x08049, + 0x08200, 0x08201, 0x08208, 0x08209, 0x08240, 0x08241, 0x08248, 0x08249, + 0x09000, 0x09001, 0x09008, 0x09009, 0x09040, 0x09041, 0x09048, 0x09049, + 0x09200, 0x09201, 0x09208, 0x09209, 0x09240, 0x09241, 0x09248, 0x09249, + 0x40000, 0x40001, 0x40008, 0x40009, 0x40040, 0x40041, 0x40048, 0x40049, + 0x40200, 0x40201, 0x40208, 0x40209, 0x40240, 0x40241, 0x40248, 0x40249, + 0x41000, 0x41001, 0x41008, 0x41009, 0x41040, 0x41041, 0x41048, 0x41049, + 0x41200, 0x41201, 0x41208, 0x41209, 0x41240, 0x41241, 0x41248, 0x41249, + 0x48000, 0x48001, 0x48008, 0x48009, 0x48040, 0x48041, 0x48048, 0x48049, + 0x48200, 0x48201, 0x48208, 0x48209, 0x48240, 0x48241, 0x48248, 0x48249, + 0x49000, 0x49001, 0x49008, 0x49009, 0x49040, 0x49041, 0x49048, 0x49049, + 0x49200, 0x49201, 0x49208, 0x49209, 0x49240, 0x49241, 0x49248, 0x49249 + }; + + /* + * This expands 8 bit indices into 32 bit contents (high bit 28), by inserting 0s between bits. + */ + private static final int[] INTERLEAVE4_TABLE = new int[] + { + 0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, 0x00000101, 0x00000110, 0x00000111, + 0x00001000, 0x00001001, 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, 0x00001111, + 0x00010000, 0x00010001, 0x00010010, 0x00010011, 0x00010100, 0x00010101, 0x00010110, 0x00010111, + 0x00011000, 0x00011001, 0x00011010, 0x00011011, 0x00011100, 0x00011101, 0x00011110, 0x00011111, + 0x00100000, 0x00100001, 0x00100010, 0x00100011, 0x00100100, 0x00100101, 0x00100110, 0x00100111, + 0x00101000, 0x00101001, 0x00101010, 0x00101011, 0x00101100, 0x00101101, 0x00101110, 0x00101111, + 0x00110000, 0x00110001, 0x00110010, 0x00110011, 0x00110100, 0x00110101, 0x00110110, 0x00110111, + 0x00111000, 0x00111001, 0x00111010, 0x00111011, 0x00111100, 0x00111101, 0x00111110, 0x00111111, + 0x01000000, 0x01000001, 0x01000010, 0x01000011, 0x01000100, 0x01000101, 0x01000110, 0x01000111, + 0x01001000, 0x01001001, 0x01001010, 0x01001011, 0x01001100, 0x01001101, 0x01001110, 0x01001111, + 0x01010000, 0x01010001, 0x01010010, 0x01010011, 0x01010100, 0x01010101, 0x01010110, 0x01010111, + 0x01011000, 0x01011001, 0x01011010, 0x01011011, 0x01011100, 0x01011101, 0x01011110, 0x01011111, + 0x01100000, 0x01100001, 0x01100010, 0x01100011, 0x01100100, 0x01100101, 0x01100110, 0x01100111, + 0x01101000, 0x01101001, 0x01101010, 0x01101011, 0x01101100, 0x01101101, 0x01101110, 0x01101111, + 0x01110000, 0x01110001, 0x01110010, 0x01110011, 0x01110100, 0x01110101, 0x01110110, 0x01110111, + 0x01111000, 0x01111001, 0x01111010, 0x01111011, 0x01111100, 0x01111101, 0x01111110, 0x01111111, + 0x10000000, 0x10000001, 0x10000010, 0x10000011, 0x10000100, 0x10000101, 0x10000110, 0x10000111, + 0x10001000, 0x10001001, 0x10001010, 0x10001011, 0x10001100, 0x10001101, 0x10001110, 0x10001111, + 0x10010000, 0x10010001, 0x10010010, 0x10010011, 0x10010100, 0x10010101, 0x10010110, 0x10010111, + 0x10011000, 0x10011001, 0x10011010, 0x10011011, 0x10011100, 0x10011101, 0x10011110, 0x10011111, + 0x10100000, 0x10100001, 0x10100010, 0x10100011, 0x10100100, 0x10100101, 0x10100110, 0x10100111, + 0x10101000, 0x10101001, 0x10101010, 0x10101011, 0x10101100, 0x10101101, 0x10101110, 0x10101111, + 0x10110000, 0x10110001, 0x10110010, 0x10110011, 0x10110100, 0x10110101, 0x10110110, 0x10110111, + 0x10111000, 0x10111001, 0x10111010, 0x10111011, 0x10111100, 0x10111101, 0x10111110, 0x10111111, + 0x11000000, 0x11000001, 0x11000010, 0x11000011, 0x11000100, 0x11000101, 0x11000110, 0x11000111, + 0x11001000, 0x11001001, 0x11001010, 0x11001011, 0x11001100, 0x11001101, 0x11001110, 0x11001111, + 0x11010000, 0x11010001, 0x11010010, 0x11010011, 0x11010100, 0x11010101, 0x11010110, 0x11010111, + 0x11011000, 0x11011001, 0x11011010, 0x11011011, 0x11011100, 0x11011101, 0x11011110, 0x11011111, + 0x11100000, 0x11100001, 0x11100010, 0x11100011, 0x11100100, 0x11100101, 0x11100110, 0x11100111, + 0x11101000, 0x11101001, 0x11101010, 0x11101011, 0x11101100, 0x11101101, 0x11101110, 0x11101111, + 0x11110000, 0x11110001, 0x11110010, 0x11110011, 0x11110100, 0x11110101, 0x11110110, 0x11110111, + 0x11111000, 0x11111001, 0x11111010, 0x11111011, 0x11111100, 0x11111101, 0x11111110, 0x11111111 + }; + + /* + * This expands 7 bit indices into 35 bit contents (high bit 30), by inserting 0s between bits. + */ + private static final int[] INTERLEAVE5_TABLE = new int[] { + 0x00000000, 0x00000001, 0x00000020, 0x00000021, 0x00000400, 0x00000401, 0x00000420, 0x00000421, + 0x00008000, 0x00008001, 0x00008020, 0x00008021, 0x00008400, 0x00008401, 0x00008420, 0x00008421, + 0x00100000, 0x00100001, 0x00100020, 0x00100021, 0x00100400, 0x00100401, 0x00100420, 0x00100421, + 0x00108000, 0x00108001, 0x00108020, 0x00108021, 0x00108400, 0x00108401, 0x00108420, 0x00108421, + 0x02000000, 0x02000001, 0x02000020, 0x02000021, 0x02000400, 0x02000401, 0x02000420, 0x02000421, + 0x02008000, 0x02008001, 0x02008020, 0x02008021, 0x02008400, 0x02008401, 0x02008420, 0x02008421, + 0x02100000, 0x02100001, 0x02100020, 0x02100021, 0x02100400, 0x02100401, 0x02100420, 0x02100421, + 0x02108000, 0x02108001, 0x02108020, 0x02108021, 0x02108400, 0x02108401, 0x02108420, 0x02108421, + 0x40000000, 0x40000001, 0x40000020, 0x40000021, 0x40000400, 0x40000401, 0x40000420, 0x40000421, + 0x40008000, 0x40008001, 0x40008020, 0x40008021, 0x40008400, 0x40008401, 0x40008420, 0x40008421, + 0x40100000, 0x40100001, 0x40100020, 0x40100021, 0x40100400, 0x40100401, 0x40100420, 0x40100421, + 0x40108000, 0x40108001, 0x40108020, 0x40108021, 0x40108400, 0x40108401, 0x40108420, 0x40108421, + 0x42000000, 0x42000001, 0x42000020, 0x42000021, 0x42000400, 0x42000401, 0x42000420, 0x42000421, + 0x42008000, 0x42008001, 0x42008020, 0x42008021, 0x42008400, 0x42008401, 0x42008420, 0x42008421, + 0x42100000, 0x42100001, 0x42100020, 0x42100021, 0x42100400, 0x42100401, 0x42100420, 0x42100421, + 0x42108000, 0x42108001, 0x42108020, 0x42108021, 0x42108400, 0x42108401, 0x42108420, 0x42108421 + }; + + /* + * This expands 9 bit indices into 63 bit (long) contents (high bit 56), by inserting 0s between bits. + */ + private static final long[] INTERLEAVE7_TABLE = new long[] + { + 0x0000000000000000L, 0x0000000000000001L, 0x0000000000000080L, 0x0000000000000081L, + 0x0000000000004000L, 0x0000000000004001L, 0x0000000000004080L, 0x0000000000004081L, + 0x0000000000200000L, 0x0000000000200001L, 0x0000000000200080L, 0x0000000000200081L, + 0x0000000000204000L, 0x0000000000204001L, 0x0000000000204080L, 0x0000000000204081L, + 0x0000000010000000L, 0x0000000010000001L, 0x0000000010000080L, 0x0000000010000081L, + 0x0000000010004000L, 0x0000000010004001L, 0x0000000010004080L, 0x0000000010004081L, + 0x0000000010200000L, 0x0000000010200001L, 0x0000000010200080L, 0x0000000010200081L, + 0x0000000010204000L, 0x0000000010204001L, 0x0000000010204080L, 0x0000000010204081L, + 0x0000000800000000L, 0x0000000800000001L, 0x0000000800000080L, 0x0000000800000081L, + 0x0000000800004000L, 0x0000000800004001L, 0x0000000800004080L, 0x0000000800004081L, + 0x0000000800200000L, 0x0000000800200001L, 0x0000000800200080L, 0x0000000800200081L, + 0x0000000800204000L, 0x0000000800204001L, 0x0000000800204080L, 0x0000000800204081L, + 0x0000000810000000L, 0x0000000810000001L, 0x0000000810000080L, 0x0000000810000081L, + 0x0000000810004000L, 0x0000000810004001L, 0x0000000810004080L, 0x0000000810004081L, + 0x0000000810200000L, 0x0000000810200001L, 0x0000000810200080L, 0x0000000810200081L, + 0x0000000810204000L, 0x0000000810204001L, 0x0000000810204080L, 0x0000000810204081L, + 0x0000040000000000L, 0x0000040000000001L, 0x0000040000000080L, 0x0000040000000081L, + 0x0000040000004000L, 0x0000040000004001L, 0x0000040000004080L, 0x0000040000004081L, + 0x0000040000200000L, 0x0000040000200001L, 0x0000040000200080L, 0x0000040000200081L, + 0x0000040000204000L, 0x0000040000204001L, 0x0000040000204080L, 0x0000040000204081L, + 0x0000040010000000L, 0x0000040010000001L, 0x0000040010000080L, 0x0000040010000081L, + 0x0000040010004000L, 0x0000040010004001L, 0x0000040010004080L, 0x0000040010004081L, + 0x0000040010200000L, 0x0000040010200001L, 0x0000040010200080L, 0x0000040010200081L, + 0x0000040010204000L, 0x0000040010204001L, 0x0000040010204080L, 0x0000040010204081L, + 0x0000040800000000L, 0x0000040800000001L, 0x0000040800000080L, 0x0000040800000081L, + 0x0000040800004000L, 0x0000040800004001L, 0x0000040800004080L, 0x0000040800004081L, + 0x0000040800200000L, 0x0000040800200001L, 0x0000040800200080L, 0x0000040800200081L, + 0x0000040800204000L, 0x0000040800204001L, 0x0000040800204080L, 0x0000040800204081L, + 0x0000040810000000L, 0x0000040810000001L, 0x0000040810000080L, 0x0000040810000081L, + 0x0000040810004000L, 0x0000040810004001L, 0x0000040810004080L, 0x0000040810004081L, + 0x0000040810200000L, 0x0000040810200001L, 0x0000040810200080L, 0x0000040810200081L, + 0x0000040810204000L, 0x0000040810204001L, 0x0000040810204080L, 0x0000040810204081L, + 0x0002000000000000L, 0x0002000000000001L, 0x0002000000000080L, 0x0002000000000081L, + 0x0002000000004000L, 0x0002000000004001L, 0x0002000000004080L, 0x0002000000004081L, + 0x0002000000200000L, 0x0002000000200001L, 0x0002000000200080L, 0x0002000000200081L, + 0x0002000000204000L, 0x0002000000204001L, 0x0002000000204080L, 0x0002000000204081L, + 0x0002000010000000L, 0x0002000010000001L, 0x0002000010000080L, 0x0002000010000081L, + 0x0002000010004000L, 0x0002000010004001L, 0x0002000010004080L, 0x0002000010004081L, + 0x0002000010200000L, 0x0002000010200001L, 0x0002000010200080L, 0x0002000010200081L, + 0x0002000010204000L, 0x0002000010204001L, 0x0002000010204080L, 0x0002000010204081L, + 0x0002000800000000L, 0x0002000800000001L, 0x0002000800000080L, 0x0002000800000081L, + 0x0002000800004000L, 0x0002000800004001L, 0x0002000800004080L, 0x0002000800004081L, + 0x0002000800200000L, 0x0002000800200001L, 0x0002000800200080L, 0x0002000800200081L, + 0x0002000800204000L, 0x0002000800204001L, 0x0002000800204080L, 0x0002000800204081L, + 0x0002000810000000L, 0x0002000810000001L, 0x0002000810000080L, 0x0002000810000081L, + 0x0002000810004000L, 0x0002000810004001L, 0x0002000810004080L, 0x0002000810004081L, + 0x0002000810200000L, 0x0002000810200001L, 0x0002000810200080L, 0x0002000810200081L, + 0x0002000810204000L, 0x0002000810204001L, 0x0002000810204080L, 0x0002000810204081L, + 0x0002040000000000L, 0x0002040000000001L, 0x0002040000000080L, 0x0002040000000081L, + 0x0002040000004000L, 0x0002040000004001L, 0x0002040000004080L, 0x0002040000004081L, + 0x0002040000200000L, 0x0002040000200001L, 0x0002040000200080L, 0x0002040000200081L, + 0x0002040000204000L, 0x0002040000204001L, 0x0002040000204080L, 0x0002040000204081L, + 0x0002040010000000L, 0x0002040010000001L, 0x0002040010000080L, 0x0002040010000081L, + 0x0002040010004000L, 0x0002040010004001L, 0x0002040010004080L, 0x0002040010004081L, + 0x0002040010200000L, 0x0002040010200001L, 0x0002040010200080L, 0x0002040010200081L, + 0x0002040010204000L, 0x0002040010204001L, 0x0002040010204080L, 0x0002040010204081L, + 0x0002040800000000L, 0x0002040800000001L, 0x0002040800000080L, 0x0002040800000081L, + 0x0002040800004000L, 0x0002040800004001L, 0x0002040800004080L, 0x0002040800004081L, + 0x0002040800200000L, 0x0002040800200001L, 0x0002040800200080L, 0x0002040800200081L, + 0x0002040800204000L, 0x0002040800204001L, 0x0002040800204080L, 0x0002040800204081L, + 0x0002040810000000L, 0x0002040810000001L, 0x0002040810000080L, 0x0002040810000081L, + 0x0002040810004000L, 0x0002040810004001L, 0x0002040810004080L, 0x0002040810004081L, + 0x0002040810200000L, 0x0002040810200001L, 0x0002040810200080L, 0x0002040810200081L, + 0x0002040810204000L, 0x0002040810204001L, 0x0002040810204080L, 0x0002040810204081L, + 0x0100000000000000L, 0x0100000000000001L, 0x0100000000000080L, 0x0100000000000081L, + 0x0100000000004000L, 0x0100000000004001L, 0x0100000000004080L, 0x0100000000004081L, + 0x0100000000200000L, 0x0100000000200001L, 0x0100000000200080L, 0x0100000000200081L, + 0x0100000000204000L, 0x0100000000204001L, 0x0100000000204080L, 0x0100000000204081L, + 0x0100000010000000L, 0x0100000010000001L, 0x0100000010000080L, 0x0100000010000081L, + 0x0100000010004000L, 0x0100000010004001L, 0x0100000010004080L, 0x0100000010004081L, + 0x0100000010200000L, 0x0100000010200001L, 0x0100000010200080L, 0x0100000010200081L, + 0x0100000010204000L, 0x0100000010204001L, 0x0100000010204080L, 0x0100000010204081L, + 0x0100000800000000L, 0x0100000800000001L, 0x0100000800000080L, 0x0100000800000081L, + 0x0100000800004000L, 0x0100000800004001L, 0x0100000800004080L, 0x0100000800004081L, + 0x0100000800200000L, 0x0100000800200001L, 0x0100000800200080L, 0x0100000800200081L, + 0x0100000800204000L, 0x0100000800204001L, 0x0100000800204080L, 0x0100000800204081L, + 0x0100000810000000L, 0x0100000810000001L, 0x0100000810000080L, 0x0100000810000081L, + 0x0100000810004000L, 0x0100000810004001L, 0x0100000810004080L, 0x0100000810004081L, + 0x0100000810200000L, 0x0100000810200001L, 0x0100000810200080L, 0x0100000810200081L, + 0x0100000810204000L, 0x0100000810204001L, 0x0100000810204080L, 0x0100000810204081L, + 0x0100040000000000L, 0x0100040000000001L, 0x0100040000000080L, 0x0100040000000081L, + 0x0100040000004000L, 0x0100040000004001L, 0x0100040000004080L, 0x0100040000004081L, + 0x0100040000200000L, 0x0100040000200001L, 0x0100040000200080L, 0x0100040000200081L, + 0x0100040000204000L, 0x0100040000204001L, 0x0100040000204080L, 0x0100040000204081L, + 0x0100040010000000L, 0x0100040010000001L, 0x0100040010000080L, 0x0100040010000081L, + 0x0100040010004000L, 0x0100040010004001L, 0x0100040010004080L, 0x0100040010004081L, + 0x0100040010200000L, 0x0100040010200001L, 0x0100040010200080L, 0x0100040010200081L, + 0x0100040010204000L, 0x0100040010204001L, 0x0100040010204080L, 0x0100040010204081L, + 0x0100040800000000L, 0x0100040800000001L, 0x0100040800000080L, 0x0100040800000081L, + 0x0100040800004000L, 0x0100040800004001L, 0x0100040800004080L, 0x0100040800004081L, + 0x0100040800200000L, 0x0100040800200001L, 0x0100040800200080L, 0x0100040800200081L, + 0x0100040800204000L, 0x0100040800204001L, 0x0100040800204080L, 0x0100040800204081L, + 0x0100040810000000L, 0x0100040810000001L, 0x0100040810000080L, 0x0100040810000081L, + 0x0100040810004000L, 0x0100040810004001L, 0x0100040810004080L, 0x0100040810004081L, + 0x0100040810200000L, 0x0100040810200001L, 0x0100040810200080L, 0x0100040810200081L, + 0x0100040810204000L, 0x0100040810204001L, 0x0100040810204080L, 0x0100040810204081L, + 0x0102000000000000L, 0x0102000000000001L, 0x0102000000000080L, 0x0102000000000081L, + 0x0102000000004000L, 0x0102000000004001L, 0x0102000000004080L, 0x0102000000004081L, + 0x0102000000200000L, 0x0102000000200001L, 0x0102000000200080L, 0x0102000000200081L, + 0x0102000000204000L, 0x0102000000204001L, 0x0102000000204080L, 0x0102000000204081L, + 0x0102000010000000L, 0x0102000010000001L, 0x0102000010000080L, 0x0102000010000081L, + 0x0102000010004000L, 0x0102000010004001L, 0x0102000010004080L, 0x0102000010004081L, + 0x0102000010200000L, 0x0102000010200001L, 0x0102000010200080L, 0x0102000010200081L, + 0x0102000010204000L, 0x0102000010204001L, 0x0102000010204080L, 0x0102000010204081L, + 0x0102000800000000L, 0x0102000800000001L, 0x0102000800000080L, 0x0102000800000081L, + 0x0102000800004000L, 0x0102000800004001L, 0x0102000800004080L, 0x0102000800004081L, + 0x0102000800200000L, 0x0102000800200001L, 0x0102000800200080L, 0x0102000800200081L, + 0x0102000800204000L, 0x0102000800204001L, 0x0102000800204080L, 0x0102000800204081L, + 0x0102000810000000L, 0x0102000810000001L, 0x0102000810000080L, 0x0102000810000081L, + 0x0102000810004000L, 0x0102000810004001L, 0x0102000810004080L, 0x0102000810004081L, + 0x0102000810200000L, 0x0102000810200001L, 0x0102000810200080L, 0x0102000810200081L, + 0x0102000810204000L, 0x0102000810204001L, 0x0102000810204080L, 0x0102000810204081L, + 0x0102040000000000L, 0x0102040000000001L, 0x0102040000000080L, 0x0102040000000081L, + 0x0102040000004000L, 0x0102040000004001L, 0x0102040000004080L, 0x0102040000004081L, + 0x0102040000200000L, 0x0102040000200001L, 0x0102040000200080L, 0x0102040000200081L, + 0x0102040000204000L, 0x0102040000204001L, 0x0102040000204080L, 0x0102040000204081L, + 0x0102040010000000L, 0x0102040010000001L, 0x0102040010000080L, 0x0102040010000081L, + 0x0102040010004000L, 0x0102040010004001L, 0x0102040010004080L, 0x0102040010004081L, + 0x0102040010200000L, 0x0102040010200001L, 0x0102040010200080L, 0x0102040010200081L, + 0x0102040010204000L, 0x0102040010204001L, 0x0102040010204080L, 0x0102040010204081L, + 0x0102040800000000L, 0x0102040800000001L, 0x0102040800000080L, 0x0102040800000081L, + 0x0102040800004000L, 0x0102040800004001L, 0x0102040800004080L, 0x0102040800004081L, + 0x0102040800200000L, 0x0102040800200001L, 0x0102040800200080L, 0x0102040800200081L, + 0x0102040800204000L, 0x0102040800204001L, 0x0102040800204080L, 0x0102040800204081L, + 0x0102040810000000L, 0x0102040810000001L, 0x0102040810000080L, 0x0102040810000081L, + 0x0102040810004000L, 0x0102040810004001L, 0x0102040810004080L, 0x0102040810004081L, + 0x0102040810200000L, 0x0102040810200001L, 0x0102040810200080L, 0x0102040810200081L, + 0x0102040810204000L, 0x0102040810204001L, 0x0102040810204080L, 0x0102040810204081L + }; + + // For toString(); must have length 64 + private static final String ZEROES = "0000000000000000000000000000000000000000000000000000000000000000"; + + final static byte[] bitLengths = + { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 + }; + + // TODO make m fixed for the LongArray, and hence compute T once and for all + + private long[] m_ints; + + public LongArray(int intLen) + { + m_ints = new long[intLen]; + } + + public LongArray(long[] ints) + { + m_ints = ints; + } + + public LongArray(long[] ints, int off, int len) + { + if (off == 0 && len == ints.length) + { + m_ints = ints; + } + else + { + m_ints = new long[len]; + System.arraycopy(ints, off, m_ints, 0, len); + } + } + + public LongArray(BigInteger bigInt) + { + if (bigInt == null || bigInt.signum() < 0) + { + throw new IllegalArgumentException("invalid F2m field value"); + } + + if (bigInt.signum() == 0) + { + m_ints = new long[] { 0L }; + return; + } + + byte[] barr = bigInt.toByteArray(); + int barrLen = barr.length; + int barrStart = 0; + if (barr[0] == 0) + { + // First byte is 0 to enforce highest (=sign) bit is zero. + // In this case ignore barr[0]. + barrLen--; + barrStart = 1; + } + int intLen = (barrLen + 7) / 8; + m_ints = new long[intLen]; + + int iarrJ = intLen - 1; + int rem = barrLen % 8 + barrStart; + long temp = 0; + int barrI = barrStart; + if (barrStart < rem) + { + for (; barrI < rem; barrI++) + { + temp <<= 8; + int barrBarrI = barr[barrI] & 0xFF; + temp |= barrBarrI; + } + m_ints[iarrJ--] = temp; + } + + for (; iarrJ >= 0; iarrJ--) + { + temp = 0; + for (int i = 0; i < 8; i++) + { + temp <<= 8; + int barrBarrI = barr[barrI++] & 0xFF; + temp |= barrBarrI; + } + m_ints[iarrJ] = temp; + } + } + + public boolean isZero() + { + long[] a = m_ints; + for (int i = 0; i < a.length; ++i) + { + if (a[i] != 0L) + { + return false; + } + } + return true; + } + + public int getUsedLength() + { + return getUsedLengthFrom(m_ints.length); + } + + public int getUsedLengthFrom(int from) + { + long[] a = m_ints; + from = Math.min(from, a.length); + + if (from < 1) + { + return 0; + } + + // Check if first element will act as sentinel + if (a[0] != 0) + { + while (a[--from] == 0) + { + } + return from + 1; + } + + do + { + if (a[--from] != 0) + { + return from + 1; + } + } + while (from > 0); + + return 0; + } + + public int degree() + { + int i = m_ints.length; + long w; + do + { + if (i == 0) + { + return 0; + } + w = m_ints[--i]; + } + while (w == 0); + + return (i << 6) + bitLength(w); + } + + private int degreeFrom(int limit) + { + int i = (limit + 62) >>> 6; + long w; + do + { + if (i == 0) + { + return 0; + } + w = m_ints[--i]; + } + while (w == 0); + + return (i << 6) + bitLength(w); + } + +// private int lowestCoefficient() +// { +// for (int i = 0; i < m_ints.length; ++i) +// { +// long mi = m_ints[i]; +// if (mi != 0) +// { +// int j = 0; +// while ((mi & 0xFFL) == 0) +// { +// j += 8; +// mi >>>= 8; +// } +// while ((mi & 1L) == 0) +// { +// ++j; +// mi >>>= 1; +// } +// return (i << 6) + j; +// } +// } +// return -1; +// } + + private static int bitLength(long w) + { + int u = (int)(w >>> 32), b; + if (u == 0) + { + u = (int)w; + b = 0; + } + else + { + b = 32; + } + + int t = u >>> 16, k; + if (t == 0) + { + t = u >>> 8; + k = (t == 0) ? bitLengths[u] : 8 + bitLengths[t]; + } + else + { + int v = t >>> 8; + k = (v == 0) ? 16 + bitLengths[t] : 24 + bitLengths[v]; + } + + return b + k; + } + + private long[] resizedInts(int newLen) + { + long[] newInts = new long[newLen]; + System.arraycopy(m_ints, 0, newInts, 0, Math.min(m_ints.length, newLen)); + return newInts; + } + + public BigInteger toBigInteger() + { + int usedLen = getUsedLength(); + if (usedLen == 0) + { + return ECConstants.ZERO; + } + + long highestInt = m_ints[usedLen - 1]; + byte[] temp = new byte[8]; + int barrI = 0; + boolean trailingZeroBytesDone = false; + for (int j = 7; j >= 0; j--) + { + byte thisByte = (byte)(highestInt >>> (8 * j)); + if (trailingZeroBytesDone || (thisByte != 0)) + { + trailingZeroBytesDone = true; + temp[barrI++] = thisByte; + } + } + + int barrLen = 8 * (usedLen - 1) + barrI; + byte[] barr = new byte[barrLen]; + for (int j = 0; j < barrI; j++) + { + barr[j] = temp[j]; + } + // Highest value int is done now + + for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--) + { + long mi = m_ints[iarrJ]; + for (int j = 7; j >= 0; j--) + { + barr[barrI++] = (byte)(mi >>> (8 * j)); + } + } + return new BigInteger(1, barr); + } + +// private static long shiftUp(long[] x, int xOff, int count) +// { +// long prev = 0; +// for (int i = 0; i < count; ++i) +// { +// long next = x[xOff + i]; +// x[xOff + i] = (next << 1) | prev; +// prev = next >>> 63; +// } +// return prev; +// } + + private static long shiftUp(long[] x, int xOff, int count, int shift) + { + int shiftInv = 64 - shift; + long prev = 0; + for (int i = 0; i < count; ++i) + { + long next = x[xOff + i]; + x[xOff + i] = (next << shift) | prev; + prev = next >>> shiftInv; + } + return prev; + } + + private static long shiftUp(long[] x, int xOff, long[] z, int zOff, int count, int shift) + { + int shiftInv = 64 - shift; + long prev = 0; + for (int i = 0; i < count; ++i) + { + long next = x[xOff + i]; + z[zOff + i] = (next << shift) | prev; + prev = next >>> shiftInv; + } + return prev; + } + + public LongArray addOne() + { + if (m_ints.length == 0) + { + return new LongArray(new long[]{ 1L }); + } + + int resultLen = Math.max(1, getUsedLength()); + long[] ints = resizedInts(resultLen); + ints[0] ^= 1L; + return new LongArray(ints); + } + +// private void addShiftedByBits(LongArray other, int bits) +// { +// int words = bits >>> 6; +// int shift = bits & 0x3F; +// +// if (shift == 0) +// { +// addShiftedByWords(other, words); +// return; +// } +// +// int otherUsedLen = other.getUsedLength(); +// if (otherUsedLen == 0) +// { +// return; +// } +// +// int minLen = otherUsedLen + words + 1; +// if (minLen > m_ints.length) +// { +// m_ints = resizedInts(minLen); +// } +// +// long carry = addShiftedByBits(m_ints, words, other.m_ints, 0, otherUsedLen, shift); +// m_ints[otherUsedLen + words] ^= carry; +// } + + private void addShiftedByBitsSafe(LongArray other, int otherDegree, int bits) + { + int otherLen = (otherDegree + 63) >>> 6; + + int words = bits >>> 6; + int shift = bits & 0x3F; + + if (shift == 0) + { + add(m_ints, words, other.m_ints, 0, otherLen); + return; + } + + long carry = addShiftedUp(m_ints, words, other.m_ints, 0, otherLen, shift); + if (carry != 0L) + { + m_ints[otherLen + words] ^= carry; + } + } + + private static long addShiftedUp(long[] x, int xOff, long[] y, int yOff, int count, int shift) + { + int shiftInv = 64 - shift; + long prev = 0; + for (int i = 0; i < count; ++i) + { + long next = y[yOff + i]; + x[xOff + i] ^= (next << shift) | prev; + prev = next >>> shiftInv; + } + return prev; + } + + private static long addShiftedDown(long[] x, int xOff, long[] y, int yOff, int count, int shift) + { + int shiftInv = 64 - shift; + long prev = 0; + int i = count; + while (--i >= 0) + { + long next = y[yOff + i]; + x[xOff + i] ^= (next >>> shift) | prev; + prev = next << shiftInv; + } + return prev; + } + + public void addShiftedByWords(LongArray other, int words) + { + int otherUsedLen = other.getUsedLength(); + if (otherUsedLen == 0) + { + return; + } + + int minLen = otherUsedLen + words; + if (minLen > m_ints.length) + { + m_ints = resizedInts(minLen); + } + + add(m_ints, words, other.m_ints, 0, otherUsedLen); + } + + private static void add(long[] x, int xOff, long[] y, int yOff, int count) + { + for (int i = 0; i < count; ++i) + { + x[xOff + i] ^= y[yOff + i]; + } + } + + private static void add(long[] x, int xOff, long[] y, int yOff, long[] z, int zOff, int count) + { + for (int i = 0; i < count; ++i) + { + z[zOff + i] = x[xOff + i] ^ y[yOff + i]; + } + } + + private static void addBoth(long[] x, int xOff, long[] y1, int y1Off, long[] y2, int y2Off, int count) + { + for (int i = 0; i < count; ++i) + { + x[xOff + i] ^= y1[y1Off + i] ^ y2[y2Off + i]; + } + } + + private static void distribute(long[] x, int src, int dst1, int dst2, int count) + { + for (int i = 0; i < count; ++i) + { + long v = x[src + i]; + x[dst1 + i] ^= v; + x[dst2 + i] ^= v; + } + } + + public int getLength() + { + return m_ints.length; + } + + private static void flipWord(long[] buf, int off, int bit, long word) + { + int n = off + (bit >>> 6); + int shift = bit & 0x3F; + if (shift == 0) + { + buf[n] ^= word; + } + else + { + buf[n] ^= word << shift; + word >>>= (64 - shift); + if (word != 0) + { + buf[++n] ^= word; + } + } + } + +// private static long getWord(long[] buf, int off, int len, int bit) +// { +// int n = off + (bit >>> 6); +// int shift = bit & 0x3F; +// if (shift == 0) +// { +// return buf[n]; +// } +// long result = buf[n] >>> shift; +// if (++n < len) +// { +// result |= buf[n] << (64 - shift); +// } +// return result; +// } + + public boolean testBitZero() + { + return m_ints.length > 0 && (m_ints[0] & 1L) != 0; + } + + private static boolean testBit(long[] buf, int off, int n) + { + // theInt = n / 64 + int theInt = n >>> 6; + // theBit = n % 64 + int theBit = n & 0x3F; + long tester = 1L << theBit; + return (buf[off + theInt] & tester) != 0; + } + + private static void flipBit(long[] buf, int off, int n) + { + // theInt = n / 64 + int theInt = n >>> 6; + // theBit = n % 64 + int theBit = n & 0x3F; + long flipper = 1L << theBit; + buf[off + theInt] ^= flipper; + } + +// private static void setBit(long[] buf, int off, int n) +// { +// // theInt = n / 64 +// int theInt = n >>> 6; +// // theBit = n % 64 +// int theBit = n & 0x3F; +// long setter = 1L << theBit; +// buf[off + theInt] |= setter; +// } +// +// private static void clearBit(long[] buf, int off, int n) +// { +// // theInt = n / 64 +// int theInt = n >>> 6; +// // theBit = n % 64 +// int theBit = n & 0x3F; +// long setter = 1L << theBit; +// buf[off + theInt] &= ~setter; +// } + + private static void multiplyWord(long a, long[] b, int bLen, long[] c, int cOff) + { + if ((a & 1L) != 0L) + { + add(c, cOff, b, 0, bLen); + } + int k = 1; + while ((a >>>= 1) != 0) + { + if ((a & 1L) != 0L) + { + long carry = addShiftedUp(c, cOff, b, 0, bLen, k); + if (carry != 0) + { + c[cOff + bLen] ^= carry; + } + } + ++k; + } + } + + public LongArray modMultiplyLD(LongArray other, int m, int[] ks) + { + /* + * Find out the degree of each argument and handle the zero cases + */ + int aDeg = degree(); + if (aDeg == 0) + { + return this; + } + int bDeg = other.degree(); + if (bDeg == 0) + { + return other; + } + + /* + * Swap if necessary so that A is the smaller argument + */ + LongArray A = this, B = other; + if (aDeg > bDeg) + { + A = other; B = this; + int tmp = aDeg; aDeg = bDeg; bDeg = tmp; + } + + /* + * Establish the word lengths of the arguments and result + */ + int aLen = (aDeg + 63) >>> 6; + int bLen = (bDeg + 63) >>> 6; + int cLen = (aDeg + bDeg + 62) >>> 6; + + if (aLen == 1) + { + long a = A.m_ints[0]; + if (a == 1L) + { + return B; + } + + /* + * Fast path for small A, with performance dependent only on the number of set bits + */ + long[] c = new long[cLen]; + multiplyWord(a, B.m_ints, bLen, c, 0); + + /* + * Reduce the raw answer against the reduction coefficients + */ + return reduceResult(c, 0, cLen, m, ks); + } + + /* + * Determine if B will get bigger during shifting + */ + int bMax = (bDeg + 7 + 63) >>> 6; + + /* + * Lookup table for the offset of each B in the tables + */ + int[] ti = new int[16]; + + /* + * Precompute table of all 4-bit products of B + */ + long[] T0 = new long[bMax << 4]; + int tOff = bMax; + ti[1] = tOff; + System.arraycopy(B.m_ints, 0, T0, tOff, bLen); + for (int i = 2; i < 16; ++i) + { + ti[i] = (tOff += bMax); + if ((i & 1) == 0) + { + shiftUp(T0, tOff >>> 1, T0, tOff, bMax, 1); + } + else + { + add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax); + } + } + + /* + * Second table with all 4-bit products of B shifted 4 bits + */ + long[] T1 = new long[T0.length]; + shiftUp(T0, 0, T1, 0, T0.length, 4); +// shiftUp(T0, bMax, T1, bMax, tOff, 4); + + long[] a = A.m_ints; + long[] c = new long[cLen]; + + int MASK = 0xF; + + /* + * Lopez-Dahab algorithm + */ + + for (int k = 56; k >= 0; k -= 8) + { + for (int j = 1; j < aLen; j += 2) + { + int aVal = (int)(a[j] >>> k); + int u = aVal & MASK; + int v = (aVal >>> 4) & MASK; + addBoth(c, j - 1, T0, ti[u], T1, ti[v], bMax); + } + shiftUp(c, 0, cLen, 8); + } + + for (int k = 56; k >= 0; k -= 8) + { + for (int j = 0; j < aLen; j += 2) + { + int aVal = (int)(a[j] >>> k); + int u = aVal & MASK; + int v = (aVal >>> 4) & MASK; + addBoth(c, j, T0, ti[u], T1, ti[v], bMax); + } + if (k > 0) + { + shiftUp(c, 0, cLen, 8); + } + } + + /* + * Finally the raw answer is collected, reduce it against the reduction coefficients + */ + return reduceResult(c, 0, cLen, m, ks); + } + + public LongArray modMultiply(LongArray other, int m, int[] ks) + { + /* + * Find out the degree of each argument and handle the zero cases + */ + int aDeg = degree(); + if (aDeg == 0) + { + return this; + } + int bDeg = other.degree(); + if (bDeg == 0) + { + return other; + } + + /* + * Swap if necessary so that A is the smaller argument + */ + LongArray A = this, B = other; + if (aDeg > bDeg) + { + A = other; B = this; + int tmp = aDeg; aDeg = bDeg; bDeg = tmp; + } + + /* + * Establish the word lengths of the arguments and result + */ + int aLen = (aDeg + 63) >>> 6; + int bLen = (bDeg + 63) >>> 6; + int cLen = (aDeg + bDeg + 62) >>> 6; + + if (aLen == 1) + { + long a = A.m_ints[0]; + if (a == 1L) + { + return B; + } + + /* + * Fast path for small A, with performance dependent only on the number of set bits + */ + long[] c = new long[cLen]; + multiplyWord(a, B.m_ints, bLen, c, 0); + + /* + * Reduce the raw answer against the reduction coefficients + */ + return reduceResult(c, 0, cLen, m, ks); + } + + /* + * Determine if B will get bigger during shifting + */ + int bMax = (bDeg + 7 + 63) >>> 6; + + /* + * Lookup table for the offset of each B in the tables + */ + int[] ti = new int[16]; + + /* + * Precompute table of all 4-bit products of B + */ + long[] T0 = new long[bMax << 4]; + int tOff = bMax; + ti[1] = tOff; + System.arraycopy(B.m_ints, 0, T0, tOff, bLen); + for (int i = 2; i < 16; ++i) + { + ti[i] = (tOff += bMax); + if ((i & 1) == 0) + { + shiftUp(T0, tOff >>> 1, T0, tOff, bMax, 1); + } + else + { + add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax); + } + } + + /* + * Second table with all 4-bit products of B shifted 4 bits + */ + long[] T1 = new long[T0.length]; + shiftUp(T0, 0, T1, 0, T0.length, 4); +// shiftUp(T0, bMax, T1, bMax, tOff, 4); + + long[] a = A.m_ints; + long[] c = new long[cLen << 3]; + + int MASK = 0xF; + + /* + * Lopez-Dahab (Modified) algorithm + */ + + for (int aPos = 0; aPos < aLen; ++aPos) + { + long aVal = a[aPos]; + int cOff = aPos; + for (;;) + { + int u = (int)aVal & MASK; + aVal >>>= 4; + int v = (int)aVal & MASK; + addBoth(c, cOff, T0, ti[u], T1, ti[v], bMax); + if ((aVal >>>= 4) == 0L) + { + break; + } + cOff += cLen; + } + } + + int cOff = c.length; + while ((cOff -= cLen) != 0) + { + addShiftedUp(c, cOff - cLen, c, cOff, cLen, 8); + } + + /* + * Finally the raw answer is collected, reduce it against the reduction coefficients + */ + return reduceResult(c, 0, cLen, m, ks); + } + + public LongArray modMultiplyAlt(LongArray other, int m, int[] ks) + { + /* + * Find out the degree of each argument and handle the zero cases + */ + int aDeg = degree(); + if (aDeg == 0) + { + return this; + } + int bDeg = other.degree(); + if (bDeg == 0) + { + return other; + } + + /* + * Swap if necessary so that A is the smaller argument + */ + LongArray A = this, B = other; + if (aDeg > bDeg) + { + A = other; B = this; + int tmp = aDeg; aDeg = bDeg; bDeg = tmp; + } + + /* + * Establish the word lengths of the arguments and result + */ + int aLen = (aDeg + 63) >>> 6; + int bLen = (bDeg + 63) >>> 6; + int cLen = (aDeg + bDeg + 62) >>> 6; + + if (aLen == 1) + { + long a = A.m_ints[0]; + if (a == 1L) + { + return B; + } + + /* + * Fast path for small A, with performance dependent only on the number of set bits + */ + long[] c = new long[cLen]; + multiplyWord(a, B.m_ints, bLen, c, 0); + + /* + * Reduce the raw answer against the reduction coefficients + */ + return reduceResult(c, 0, cLen, m, ks); + } + + // NOTE: This works, but is slower than width 4 processing +// if (aLen == 2) +// { +// /* +// * Use common-multiplicand optimization to save ~1/4 of the adds +// */ +// long a1 = A.m_ints[0], a2 = A.m_ints[1]; +// long aa = a1 & a2; a1 ^= aa; a2 ^= aa; +// +// long[] b = B.m_ints; +// long[] c = new long[cLen]; +// multiplyWord(aa, b, bLen, c, 1); +// add(c, 0, c, 1, cLen - 1); +// multiplyWord(a1, b, bLen, c, 0); +// multiplyWord(a2, b, bLen, c, 1); +// +// /* +// * Reduce the raw answer against the reduction coefficients +// */ +// return reduceResult(c, 0, cLen, m, ks); +// } + + /* + * Determine the parameters of the interleaved window algorithm: the 'width' in bits to + * process together, the number of evaluation 'positions' implied by that width, and the + * 'top' position at which the regular window algorithm stops. + */ + int width, positions, top, banks; + + // NOTE: width 4 is the fastest over the entire range of sizes used in current crypto +// width = 1; positions = 64; top = 64; banks = 4; +// width = 2; positions = 32; top = 64; banks = 4; +// width = 3; positions = 21; top = 63; banks = 3; + width = 4; positions = 16; top = 64; banks = 8; +// width = 5; positions = 13; top = 65; banks = 7; +// width = 7; positions = 9; top = 63; banks = 9; +// width = 8; positions = 8; top = 64; banks = 8; + + /* + * Determine if B will get bigger during shifting + */ + int shifts = top < 64 ? positions : positions - 1; + int bMax = (bDeg + shifts + 63) >>> 6; + + int bTotal = bMax * banks, stride = width * banks; + + /* + * Create a single temporary buffer, with an offset table to find the positions of things in it + */ + int[] ci = new int[1 << width]; + int cTotal = aLen; + { + ci[0] = cTotal; + cTotal += bTotal; + ci[1] = cTotal; + for (int i = 2; i < ci.length; ++i) + { + cTotal += cLen; + ci[i] = cTotal; + } + cTotal += cLen; + } + // NOTE: Provide a safe dump for "high zeroes" since we are adding 'bMax' and not 'bLen' + ++cTotal; + + long[] c = new long[cTotal]; + + // Prepare A in interleaved form, according to the chosen width + interleave(A.m_ints, 0, c, 0, aLen, width); + + // Make a working copy of B, since we will be shifting it + { + int bOff = aLen; + System.arraycopy(B.m_ints, 0, c, bOff, bLen); + for (int bank = 1; bank < banks; ++bank) + { + shiftUp(c, aLen, c, bOff += bMax, bMax, bank); + } + } + + /* + * The main loop analyzes the interleaved windows in A, and for each non-zero window + * a single word-array XOR is performed to a carefully selected slice of 'c'. The loop is + * breadth-first, checking the lowest window in each word, then looping again for the + * next higher window position. + */ + int MASK = (1 << width) - 1; + + int k = 0; + for (;;) + { + int aPos = 0; + do + { + long aVal = c[aPos] >>> k; + int bank = 0, bOff = aLen; + for (;;) + { + int index = (int)(aVal) & MASK; + if (index != 0) + { + /* + * Add to a 'c' buffer based on the bit-pattern of 'index'. Since A is in + * interleaved form, the bits represent the current B shifted by 0, 'positions', + * 'positions' * 2, ..., 'positions' * ('width' - 1) + */ + add(c, aPos + ci[index], c, bOff, bMax); + } + if (++bank == banks) + { + break; + } + bOff += bMax; + aVal >>>= width; + } + } + while (++aPos < aLen); + + if ((k += stride) >= top) + { + if (k >= 64) + { + break; + } + + /* + * Adjustment for window setups with top == 63, the final bit (if any) is processed + * as the top-bit of a window + */ + k = 64 - width; + MASK &= MASK << (top - k); + } + + /* + * After each position has been checked for all words of A, B is shifted up 1 place + */ + shiftUp(c, aLen, bTotal, banks); + } + + int ciPos = ci.length; + while (--ciPos > 1) + { + if ((ciPos & 1L) == 0L) + { + /* + * For even numbers, shift contents and add to the half-position + */ + addShiftedUp(c, ci[ciPos >>> 1], c, ci[ciPos], cLen, positions); + } + else + { + /* + * For odd numbers, 'distribute' contents to the result and the next-lowest position + */ + distribute(c, ci[ciPos], ci[ciPos - 1], ci[1], cLen); + } + } + + /* + * Finally the raw answer is collected, reduce it against the reduction coefficients + */ + return reduceResult(c, ci[1], cLen, m, ks); + } + + private static LongArray reduceResult(long[] buf, int off, int len, int m, int[] ks) + { + int rLen = reduceInPlace(buf, off, len, m, ks); + return new LongArray(buf, off, rLen); + } + +// private static void deInterleave(long[] x, int xOff, long[] z, int zOff, int count, int rounds) +// { +// for (int i = 0; i < count; ++i) +// { +// z[zOff + i] = deInterleave(x[zOff + i], rounds); +// } +// } +// +// private static long deInterleave(long x, int rounds) +// { +// while (--rounds >= 0) +// { +// x = deInterleave32(x & DEINTERLEAVE_MASK) | (deInterleave32((x >>> 1) & DEINTERLEAVE_MASK) << 32); +// } +// return x; +// } +// +// private static long deInterleave32(long x) +// { +// x = (x | (x >>> 1)) & 0x3333333333333333L; +// x = (x | (x >>> 2)) & 0x0F0F0F0F0F0F0F0FL; +// x = (x | (x >>> 4)) & 0x00FF00FF00FF00FFL; +// x = (x | (x >>> 8)) & 0x0000FFFF0000FFFFL; +// x = (x | (x >>> 16)) & 0x00000000FFFFFFFFL; +// return x; +// } + + private static int reduceInPlace(long[] buf, int off, int len, int m, int[] ks) + { + int mLen = (m + 63) >>> 6; + if (len < mLen) + { + return len; + } + + int numBits = Math.min(len << 6, (m << 1) - 1); // TODO use actual degree? + int excessBits = (len << 6) - numBits; + while (excessBits >= 64) + { + --len; + excessBits -= 64; + } + + int kLen = ks.length, kMax = ks[kLen - 1], kNext = kLen > 1 ? ks[kLen - 2] : 0; + int wordWiseLimit = Math.max(m, kMax + 64); + int vectorableWords = (excessBits + Math.min(numBits - wordWiseLimit, m - kNext)) >> 6; + if (vectorableWords > 1) + { + int vectorWiseWords = len - vectorableWords; + reduceVectorWise(buf, off, len, vectorWiseWords, m, ks); + while (len > vectorWiseWords) + { + buf[off + --len] = 0L; + } + numBits = vectorWiseWords << 6; + } + + if (numBits > wordWiseLimit) + { + reduceWordWise(buf, off, len, wordWiseLimit, m, ks); + numBits = wordWiseLimit; + } + + if (numBits > m) + { + reduceBitWise(buf, off, numBits, m, ks); + } + + return mLen; + } + + private static void reduceBitWise(long[] buf, int off, int bitlength, int m, int[] ks) + { + while (--bitlength >= m) + { + if (testBit(buf, off, bitlength)) + { + reduceBit(buf, off, bitlength, m, ks); + } + } + } + + private static void reduceBit(long[] buf, int off, int bit, int m, int[] ks) + { + flipBit(buf, off, bit); + int base = bit - m; + int j = ks.length; + while (--j >= 0) + { + flipBit(buf, off, ks[j] + base); + } + flipBit(buf, off, base); + } + + private static void reduceWordWise(long[] buf, int off, int len, int toBit, int m, int[] ks) + { + int toPos = toBit >>> 6; + + while (--len > toPos) + { + long word = buf[off + len]; + if (word != 0) + { + buf[off + len] = 0; + reduceWord(buf, off, (len << 6), word, m, ks); + } + } + + int partial = toBit & 0x3F; + long word = buf[off + toPos] >>> partial; + if (word != 0) + { + buf[off + toPos] ^= word << partial; + reduceWord(buf, off, toBit, word, m, ks); + } + } + + private static void reduceWord(long[] buf, int off, int bit, long word, int m, int[] ks) + { + int offset = bit - m; + int j = ks.length; + while (--j >= 0) + { + flipWord(buf, off, offset + ks[j], word); + } + flipWord(buf, off, offset, word); + } + + private static void reduceVectorWise(long[] buf, int off, int len, int words, int m, int[] ks) + { + /* + * NOTE: It's important we go from highest coefficient to lowest, because for the highest + * one (only) we allow the ranges to partially overlap, and therefore any changes must take + * effect for the subsequent lower coefficients. + */ + int baseBit = (words << 6) - m; + int j = ks.length; + while (--j >= 0) + { + flipVector(buf, off, buf, off + words, len - words, baseBit + ks[j]); + } + flipVector(buf, off, buf, off + words, len - words, baseBit); + } + + private static void flipVector(long[] x, int xOff, long[] y, int yOff, int yLen, int bits) + { + xOff += bits >>> 6; + bits &= 0x3F; + + if (bits == 0) + { + add(x, xOff, y, yOff, yLen); + } + else + { + long carry = addShiftedDown(x, xOff + 1, y, yOff, yLen, 64 - bits); + x[xOff] ^= carry; + } + } + + public LongArray modSquare(int m, int[] ks) + { + int len = getUsedLength(); + if (len == 0) + { + return this; + } + + int _2len = len << 1; + long[] r = new long[_2len]; + + int pos = 0; + while (pos < _2len) + { + long mi = m_ints[pos >>> 1]; + r[pos++] = interleave2_32to64((int)mi); + r[pos++] = interleave2_32to64((int)(mi >>> 32)); + } + + return new LongArray(r, 0, reduceInPlace(r, 0, r.length, m, ks)); + } + +// private LongArray modSquareN(int n, int m, int[] ks) +// { +// int len = getUsedLength(); +// if (len == 0) +// { +// return this; +// } +// +// int mLen = (m + 63) >>> 6; +// long[] r = new long[mLen << 1]; +// System.arraycopy(m_ints, 0, r, 0, len); +// +// while (--n >= 0) +// { +// squareInPlace(r, len, m, ks); +// len = reduceInPlace(r, 0, r.length, m, ks); +// } +// +// return new LongArray(r, 0, len); +// } +// +// private static void squareInPlace(long[] x, int xLen, int m, int[] ks) +// { +// int pos = xLen << 1; +// while (--xLen >= 0) +// { +// long xVal = x[xLen]; +// x[--pos] = interleave2_32to64((int)(xVal >>> 32)); +// x[--pos] = interleave2_32to64((int)xVal); +// } +// } + + private static void interleave(long[] x, int xOff, long[] z, int zOff, int count, int width) + { + switch (width) + { + case 3: + interleave3(x, xOff, z, zOff, count); + break; + case 5: + interleave5(x, xOff, z, zOff, count); + break; + case 7: + interleave7(x, xOff, z, zOff, count); + break; + default: + interleave2_n(x, xOff, z, zOff, count, bitLengths[width] - 1); + break; + } + } + + private static void interleave3(long[] x, int xOff, long[] z, int zOff, int count) + { + for (int i = 0; i < count; ++i) + { + z[zOff + i] = interleave3(x[xOff + i]); + } + } + + private static long interleave3(long x) + { + long z = x & (1L << 63); + return z + | interleave3_21to63((int)x & 0x1FFFFF) + | interleave3_21to63((int)(x >>> 21) & 0x1FFFFF) << 1 + | interleave3_21to63((int)(x >>> 42) & 0x1FFFFF) << 2; + +// int zPos = 0, wPos = 0, xPos = 0; +// for (;;) +// { +// z |= ((x >>> xPos) & 1L) << zPos; +// if (++zPos == 63) +// { +// String sz2 = Long.toBinaryString(z); +// return z; +// } +// if ((xPos += 21) >= 63) +// { +// xPos = ++wPos; +// } +// } + } + + private static long interleave3_21to63(int x) + { + int r00 = INTERLEAVE3_TABLE[x & 0x7F]; + int r21 = INTERLEAVE3_TABLE[(x >>> 7) & 0x7F]; + int r42 = INTERLEAVE3_TABLE[x >>> 14]; + return (r42 & 0xFFFFFFFFL) << 42 | (r21 & 0xFFFFFFFFL) << 21 | (r00 & 0xFFFFFFFFL); + } + + private static void interleave5(long[] x, int xOff, long[] z, int zOff, int count) + { + for (int i = 0; i < count; ++i) + { + z[zOff + i] = interleave5(x[xOff + i]); + } + } + + private static long interleave5(long x) + { + return interleave3_13to65((int)x & 0x1FFF) + | interleave3_13to65((int)(x >>> 13) & 0x1FFF) << 1 + | interleave3_13to65((int)(x >>> 26) & 0x1FFF) << 2 + | interleave3_13to65((int)(x >>> 39) & 0x1FFF) << 3 + | interleave3_13to65((int)(x >>> 52) & 0x1FFF) << 4; + +// long z = 0; +// int zPos = 0, wPos = 0, xPos = 0; +// for (;;) +// { +// z |= ((x >>> xPos) & 1L) << zPos; +// if (++zPos == 64) +// { +// return z; +// } +// if ((xPos += 13) >= 64) +// { +// xPos = ++wPos; +// } +// } + } + + private static long interleave3_13to65(int x) + { + int r00 = INTERLEAVE5_TABLE[x & 0x7F]; + int r35 = INTERLEAVE5_TABLE[x >>> 7]; + return (r35 & 0xFFFFFFFFL) << 35 | (r00 & 0xFFFFFFFFL); + } + + private static void interleave7(long[] x, int xOff, long[] z, int zOff, int count) + { + for (int i = 0; i < count; ++i) + { + z[zOff + i] = interleave7(x[xOff + i]); + } + } + + private static long interleave7(long x) + { + long z = x & (1L << 63); + return z + | INTERLEAVE7_TABLE[(int)x & 0x1FF] + | INTERLEAVE7_TABLE[(int)(x >>> 9) & 0x1FF] << 1 + | INTERLEAVE7_TABLE[(int)(x >>> 18) & 0x1FF] << 2 + | INTERLEAVE7_TABLE[(int)(x >>> 27) & 0x1FF] << 3 + | INTERLEAVE7_TABLE[(int)(x >>> 36) & 0x1FF] << 4 + | INTERLEAVE7_TABLE[(int)(x >>> 45) & 0x1FF] << 5 + | INTERLEAVE7_TABLE[(int)(x >>> 54) & 0x1FF] << 6; + +// int zPos = 0, wPos = 0, xPos = 0; +// for (;;) +// { +// z |= ((x >>> xPos) & 1L) << zPos; +// if (++zPos == 63) +// { +// return z; +// } +// if ((xPos += 9) >= 63) +// { +// xPos = ++wPos; +// } +// } + } + + private static void interleave2_n(long[] x, int xOff, long[] z, int zOff, int count, int rounds) + { + for (int i = 0; i < count; ++i) + { + z[zOff + i] = interleave2_n(x[xOff + i], rounds); + } + } + + private static long interleave2_n(long x, int rounds) + { + while (rounds > 1) + { + rounds -= 2; + x = interleave4_16to64((int)x & 0xFFFF) + | interleave4_16to64((int)(x >>> 16) & 0xFFFF) << 1 + | interleave4_16to64((int)(x >>> 32) & 0xFFFF) << 2 + | interleave4_16to64((int)(x >>> 48) & 0xFFFF) << 3; + } + if (rounds > 0) + { + x = interleave2_32to64((int)x) | interleave2_32to64((int)(x >>> 32)) << 1; + } + return x; + } + + private static long interleave4_16to64(int x) + { + int r00 = INTERLEAVE4_TABLE[x & 0xFF]; + int r32 = INTERLEAVE4_TABLE[x >>> 8]; + return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL); + } + + private static long interleave2_32to64(int x) + { + int r00 = INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >>> 8) & 0xFF] << 16; + int r32 = INTERLEAVE2_TABLE[(x >>> 16) & 0xFF] | INTERLEAVE2_TABLE[x >>> 24] << 16; + return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL); + } + +// private static LongArray expItohTsujii2(LongArray B, int n, int m, int[] ks) +// { +// LongArray t1 = B, t3 = new LongArray(new long[]{ 1L }); +// int scale = 1; +// +// int numTerms = n; +// while (numTerms > 1) +// { +// if ((numTerms & 1) != 0) +// { +// t3 = t3.modMultiply(t1, m, ks); +// t1 = t1.modSquareN(scale, m, ks); +// } +// +// LongArray t2 = t1.modSquareN(scale, m, ks); +// t1 = t1.modMultiply(t2, m, ks); +// numTerms >>>= 1; scale <<= 1; +// } +// +// return t3.modMultiply(t1, m, ks); +// } +// +// private static LongArray expItohTsujii23(LongArray B, int n, int m, int[] ks) +// { +// LongArray t1 = B, t3 = new LongArray(new long[]{ 1L }); +// int scale = 1; +// +// int numTerms = n; +// while (numTerms > 1) +// { +// boolean m03 = numTerms % 3 == 0; +// boolean m14 = !m03 && (numTerms & 1) != 0; +// +// if (m14) +// { +// t3 = t3.modMultiply(t1, m, ks); +// t1 = t1.modSquareN(scale, m, ks); +// } +// +// LongArray t2 = t1.modSquareN(scale, m, ks); +// t1 = t1.modMultiply(t2, m, ks); +// +// if (m03) +// { +// t2 = t2.modSquareN(scale, m, ks); +// t1 = t1.modMultiply(t2, m, ks); +// numTerms /= 3; scale *= 3; +// } +// else +// { +// numTerms >>>= 1; scale <<= 1; +// } +// } +// +// return t3.modMultiply(t1, m, ks); +// } +// +// private static LongArray expItohTsujii235(LongArray B, int n, int m, int[] ks) +// { +// LongArray t1 = B, t4 = new LongArray(new long[]{ 1L }); +// int scale = 1; +// +// int numTerms = n; +// while (numTerms > 1) +// { +// if (numTerms % 5 == 0) +// { +//// t1 = expItohTsujii23(t1, 5, m, ks); +// +// LongArray t3 = t1; +// t1 = t1.modSquareN(scale, m, ks); +// +// LongArray t2 = t1.modSquareN(scale, m, ks); +// t1 = t1.modMultiply(t2, m, ks); +// t2 = t1.modSquareN(scale << 1, m, ks); +// t1 = t1.modMultiply(t2, m, ks); +// +// t1 = t1.modMultiply(t3, m, ks); +// +// numTerms /= 5; scale *= 5; +// continue; +// } +// +// boolean m03 = numTerms % 3 == 0; +// boolean m14 = !m03 && (numTerms & 1) != 0; +// +// if (m14) +// { +// t4 = t4.modMultiply(t1, m, ks); +// t1 = t1.modSquareN(scale, m, ks); +// } +// +// LongArray t2 = t1.modSquareN(scale, m, ks); +// t1 = t1.modMultiply(t2, m, ks); +// +// if (m03) +// { +// t2 = t2.modSquareN(scale, m, ks); +// t1 = t1.modMultiply(t2, m, ks); +// numTerms /= 3; scale *= 3; +// } +// else +// { +// numTerms >>>= 1; scale <<= 1; +// } +// } +// +// return t4.modMultiply(t1, m, ks); +// } + + public LongArray modInverse(int m, int[] ks) + { + /* + * Fermat's Little Theorem + */ +// LongArray A = this; +// LongArray B = A.modSquare(m, ks); +// LongArray R0 = B, R1 = B; +// for (int i = 2; i < m; ++i) +// { +// R1 = R1.modSquare(m, ks); +// R0 = R0.modMultiply(R1, m, ks); +// } +// +// return R0; + + /* + * Itoh-Tsujii + */ +// LongArray B = modSquare(m, ks); +// switch (m) +// { +// case 409: +// return expItohTsujii23(B, m - 1, m, ks); +// case 571: +// return expItohTsujii235(B, m - 1, m, ks); +// case 163: +// case 233: +// case 283: +// default: +// return expItohTsujii2(B, m - 1, m, ks); +// } + + /* + * Inversion in F2m using the extended Euclidean algorithm + * + * Input: A nonzero polynomial a(z) of degree at most m-1 + * Output: a(z)^(-1) mod f(z) + */ + int uzDegree = degree(); + if (uzDegree == 1) + { + return this; + } + + // u(z) := a(z) + LongArray uz = (LongArray)clone(); + + int t = (m + 63) >>> 6; + + // v(z) := f(z) + LongArray vz = new LongArray(t); + reduceBit(vz.m_ints, 0, m, m, ks); + + // g1(z) := 1, g2(z) := 0 + LongArray g1z = new LongArray(t); + g1z.m_ints[0] = 1L; + LongArray g2z = new LongArray(t); + + int[] uvDeg = new int[]{ uzDegree, m + 1 }; + LongArray[] uv = new LongArray[]{ uz, vz }; + + int[] ggDeg = new int[]{ 1, 0 }; + LongArray[] gg = new LongArray[]{ g1z, g2z }; + + int b = 1; + int duv1 = uvDeg[b]; + int dgg1 = ggDeg[b]; + int j = duv1 - uvDeg[1 - b]; + + for (;;) + { + if (j < 0) + { + j = -j; + uvDeg[b] = duv1; + ggDeg[b] = dgg1; + b = 1 - b; + duv1 = uvDeg[b]; + dgg1 = ggDeg[b]; + } + + uv[b].addShiftedByBitsSafe(uv[1 - b], uvDeg[1 - b], j); + + int duv2 = uv[b].degreeFrom(duv1); + if (duv2 == 0) + { + return gg[1 - b]; + } + + { + int dgg2 = ggDeg[1 - b]; + gg[b].addShiftedByBitsSafe(gg[1 - b], dgg2, j); + dgg2 += j; + + if (dgg2 > dgg1) + { + dgg1 = dgg2; + } + else if (dgg2 == dgg1) + { + dgg1 = gg[b].degreeFrom(dgg1); + } + } + + j += (duv2 - duv1); + duv1 = duv2; + } + } + + public boolean equals(Object o) + { + if (!(o instanceof LongArray)) + { + return false; + } + LongArray other = (LongArray) o; + int usedLen = getUsedLength(); + if (other.getUsedLength() != usedLen) + { + return false; + } + for (int i = 0; i < usedLen; i++) + { + if (m_ints[i] != other.m_ints[i]) + { + return false; + } + } + return true; + } + + public int hashCode() + { + int usedLen = getUsedLength(); + int hash = 1; + for (int i = 0; i < usedLen; i++) + { + long mi = m_ints[i]; + hash *= 31; + hash ^= (int)mi; + hash *= 31; + hash ^= (int)(mi >>> 32); + } + return hash; + } + + public Object clone() + { + return new LongArray(Arrays.clone(m_ints)); + } + + public String toString() + { + int i = getUsedLength(); + if (i == 0) + { + return "0"; + } + + StringBuffer sb = new StringBuffer(Long.toBinaryString(m_ints[--i])); + while (--i >= 0) + { + String s = Long.toBinaryString(m_ints[i]); + + // Add leading zeroes, except for highest significant word + int len = s.length(); + if (len < 64) + { + sb.append(ZEROES.substring(len)); + } + + sb.append(s); + } + return sb.toString(); + } +}
\ No newline at end of file diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java b/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java index 804dcf7..3849858 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java @@ -2,9 +2,9 @@ package org.bouncycastle.math.ec; /** * Interface for classes storing precomputation data for multiplication - * algorithms. Used as a Memento (see GOF patterns) for - * <code>WNafMultiplier</code>. + * algorithms. Used as a Memento (see GOF patterns) by e.g. + * <code>WNafL2RMultiplier</code>. */ -interface PreCompInfo +public interface PreCompInfo { } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java b/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java index af4355f..42d6738 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java @@ -392,15 +392,7 @@ class Tnaf */ public static ECPoint.F2m tau(ECPoint.F2m p) { - if (p.isInfinity()) - { - return p; - } - - ECFieldElement x = p.getX(); - ECFieldElement y = p.getY(); - - return new ECPoint.F2m(p.getCurve(), x.square(), y.square(), p.isCompressed()); + return p.tau(); } /** @@ -415,23 +407,17 @@ class Tnaf */ public static byte getMu(ECCurve.F2m curve) { - BigInteger a = curve.getA().toBigInteger(); - byte mu; - - if (a.equals(ECConstants.ZERO)) - { - mu = -1; - } - else if (a.equals(ECConstants.ONE)) + if (!curve.isKoblitz()) { - mu = 1; + throw new IllegalArgumentException("No Koblitz curve (ABC), TNAF multiplication not possible"); } - else + + if (curve.getA().isZero()) { - throw new IllegalArgumentException("No Koblitz curve (ABC), " + - "TNAF multiplication not possible"); + return -1; } - return mu; + + return 1; } /** @@ -838,7 +824,9 @@ class Tnaf { pu[i] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]); } - + + p.getCurve().normalizeAll(pu); + return pu; } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafL2RMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafL2RMultiplier.java new file mode 100644 index 0000000..59a9313 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafL2RMultiplier.java @@ -0,0 +1,101 @@ +package org.bouncycastle.math.ec; + +import java.math.BigInteger; + +/** + * Class implementing the WNAF (Window Non-Adjacent Form) multiplication + * algorithm. + */ +public class WNafL2RMultiplier extends AbstractECMultiplier +{ + /** + * Multiplies <code>this</code> by an integer <code>k</code> using the + * Window NAF method. + * @param k The integer by which <code>this</code> is multiplied. + * @return A new <code>ECPoint</code> which equals <code>this</code> + * multiplied by <code>k</code>. + */ + 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()))); + + WNafPreCompInfo wnafPreCompInfo = WNafUtil.precompute(p, width, true); + ECPoint[] preComp = wnafPreCompInfo.getPreComp(); + ECPoint[] preCompNeg = wnafPreCompInfo.getPreCompNeg(); + + int[] wnaf = WNafUtil.generateCompactWindowNaf(width, k); + + ECPoint R = p.getCurve().getInfinity(); + + int i = wnaf.length; + + /* + * NOTE This code optimizes the first window using the precomputed points to substitute an + * addition for 2 or more doublings. + */ + if (i > 1) + { + int wi = wnaf[--i]; + int digit = wi >> 16, zeroes = wi & 0xFFFF; + + int n = Math.abs(digit); + ECPoint[] table = digit < 0 ? preCompNeg : preComp; + + /* + * NOTE: We use this optimization conservatively, since some coordinate systems have + * significantly cheaper doubling relative to addition. + * + * (n << 2) selects precomputed values in the lower half of the table + * (n << 3) selects precomputed values in the lower quarter of the table + */ + //if ((n << 2) < (1 << width)) + if ((n << 3) < (1 << width)) + { + int highest = LongArray.bitLengths[n]; + int lowBits = n ^ (1 << (highest - 1)); + int scale = width - highest; + + int i1 = ((1 << (width - 1)) - 1); + int i2 = (lowBits << scale) + 1; + R = table[i1 >>> 1].add(table[i2 >>> 1]); + + zeroes -= scale; + +// System.out.println("Optimized: 2^" + scale + " * " + n + " = " + i1 + " + " + i2); + } + else + { + R = table[n >>> 1]; + } + + R = R.timesPow2(zeroes); + } + + while (i > 0) + { + int wi = wnaf[--i]; + int digit = wi >> 16, zeroes = wi & 0xFFFF; + + int n = Math.abs(digit); + ECPoint[] table = digit < 0 ? preCompNeg : preComp; + ECPoint r = table[n >>> 1]; + + R = R.twicePlus(r); + R = R.timesPow2(zeroes); + } + + 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/bcprov/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java deleted file mode 100644 index 10c8ed2..0000000 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java +++ /dev/null @@ -1,240 +0,0 @@ -package org.bouncycastle.math.ec; - -import java.math.BigInteger; - -/** - * Class implementing the WNAF (Window Non-Adjacent Form) multiplication - * algorithm. - */ -class WNafMultiplier implements ECMultiplier -{ - /** - * Computes the Window NAF (non-adjacent Form) of an integer. - * @param width The width <code>w</code> of the Window NAF. The width is - * defined as the minimal number <code>w</code>, such that for any - * <code>w</code> consecutive digits in the resulting representation, at - * most one is non-zero. - * @param k The integer of which the Window NAF is computed. - * @return The Window NAF of the given width, such that the following holds: - * <code>k = ∑<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup> - * </code>, where the <code>k<sub>i</sub></code> denote the elements of the - * returned <code>byte[]</code>. - */ - public byte[] windowNaf(byte width, BigInteger k) - { - // The window NAF is at most 1 element longer than the binary - // representation of the integer k. byte can be used instead of short or - // int unless the window width is larger than 8. For larger width use - // short or int. However, a width of more than 8 is not efficient for - // m = log2(q) smaller than 2305 Bits. Note: Values for m larger than - // 1000 Bits are currently not used in practice. - byte[] wnaf = new byte[k.bitLength() + 1]; - - // 2^width as short and BigInteger - short pow2wB = (short)(1 << width); - BigInteger pow2wBI = BigInteger.valueOf(pow2wB); - - int i = 0; - - // The actual length of the WNAF - int length = 0; - - // while k >= 1 - while (k.signum() > 0) - { - // if k is odd - if (k.testBit(0)) - { - // k mod 2^width - BigInteger remainder = k.mod(pow2wBI); - - // if remainder > 2^(width - 1) - 1 - if (remainder.testBit(width - 1)) - { - wnaf[i] = (byte)(remainder.intValue() - pow2wB); - } - else - { - wnaf[i] = (byte)remainder.intValue(); - } - // wnaf[i] is now in [-2^(width-1), 2^(width-1)-1] - - k = k.subtract(BigInteger.valueOf(wnaf[i])); - length = i; - } - else - { - wnaf[i] = 0; - } - - // k = k/2 - k = k.shiftRight(1); - i++; - } - - length++; - - // Reduce the WNAF array to its actual length - byte[] wnafShort = new byte[length]; - System.arraycopy(wnaf, 0, wnafShort, 0, length); - return wnafShort; - } - - /** - * Multiplies <code>this</code> by an integer <code>k</code> using the - * Window NAF method. - * @param k The integer by which <code>this</code> is multiplied. - * @return A new <code>ECPoint</code> which equals <code>this</code> - * multiplied by <code>k</code>. - */ - public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo) - { - WNafPreCompInfo wnafPreCompInfo; - - if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo)) - { - wnafPreCompInfo = (WNafPreCompInfo)preCompInfo; - } - else - { - // Ignore empty PreCompInfo or PreCompInfo of incorrect type - wnafPreCompInfo = new WNafPreCompInfo(); - } - - // floor(log2(k)) - int m = k.bitLength(); - - // width of the Window NAF - byte width; - - // Required length of precomputation array - int reqPreCompLen; - - // Determine optimal width and corresponding length of precomputation - // array based on literature values - if (m < 13) - { - width = 2; - reqPreCompLen = 1; - } - else - { - if (m < 41) - { - width = 3; - reqPreCompLen = 2; - } - else - { - if (m < 121) - { - width = 4; - reqPreCompLen = 4; - } - else - { - if (m < 337) - { - width = 5; - reqPreCompLen = 8; - } - else - { - if (m < 897) - { - width = 6; - reqPreCompLen = 16; - } - else - { - if (m < 2305) - { - width = 7; - reqPreCompLen = 32; - } - else - { - width = 8; - reqPreCompLen = 127; - } - } - } - } - } - } - - // The length of the precomputation array - int preCompLen = 1; - - ECPoint[] preComp = wnafPreCompInfo.getPreComp(); - ECPoint twiceP = wnafPreCompInfo.getTwiceP(); - - // Check if the precomputed ECPoints already exist - if (preComp == null) - { - // Precomputation must be performed from scratch, create an empty - // precomputation array of desired length - preComp = new ECPoint[]{ p }; - } - else - { - // Take the already precomputed ECPoints to start with - preCompLen = preComp.length; - } - - if (twiceP == null) - { - // Compute twice(p) - twiceP = p.twice(); - } - - if (preCompLen < reqPreCompLen) - { - // Precomputation array must be made bigger, copy existing preComp - // array into the larger new preComp array - ECPoint[] oldPreComp = preComp; - preComp = new ECPoint[reqPreCompLen]; - System.arraycopy(oldPreComp, 0, preComp, 0, preCompLen); - - for (int i = preCompLen; i < reqPreCompLen; i++) - { - // Compute the new ECPoints for the precomputation array. - // The values 1, 3, 5, ..., 2^(width-1)-1 times p are - // computed - preComp[i] = twiceP.add(preComp[i - 1]); - } - } - - // Compute the Window NAF of the desired width - byte[] wnaf = windowNaf(width, k); - int l = wnaf.length; - - // Apply the Window NAF to p using the precomputed ECPoint values. - ECPoint q = p.getCurve().getInfinity(); - for (int i = l - 1; i >= 0; i--) - { - q = q.twice(); - - if (wnaf[i] != 0) - { - if (wnaf[i] > 0) - { - q = q.add(preComp[(wnaf[i] - 1)/2]); - } - else - { - // wnaf[i] < 0 - q = q.subtract(preComp[(-wnaf[i] - 1)/2]); - } - } - } - - // Set PreCompInfo in ECPoint, such that it is available for next - // multiplication. - wnafPreCompInfo.setPreComp(preComp); - wnafPreCompInfo.setTwiceP(twiceP); - p.setPreCompInfo(wnafPreCompInfo); - return q; - } - -} diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java index fc0d5fe..d142ab7 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java @@ -4,21 +4,23 @@ package org.bouncycastle.math.ec; * Class holding precomputation data for the WNAF (Window Non-Adjacent Form) * algorithm. */ -class WNafPreCompInfo implements PreCompInfo +public class WNafPreCompInfo implements PreCompInfo { /** - * Array holding the precomputed <code>ECPoint</code>s used for the Window - * NAF multiplication in <code> - * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply() - * WNafMultiplier.multiply()}</code>. + * Array holding the precomputed <code>ECPoint</code>s used for a Window + * NAF multiplication. */ private ECPoint[] preComp = null; /** + * Array holding the negations of the precomputed <code>ECPoint</code>s used + * for a Window NAF multiplication. + */ + private ECPoint[] preCompNeg = null; + + /** * Holds an <code>ECPoint</code> representing twice(this). Used for the - * Window NAF multiplication in <code> - * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply() - * WNafMultiplier.multiply()}</code>. + * Window NAF multiplication to create or extend the precomputed values. */ private ECPoint twiceP = null; @@ -27,18 +29,28 @@ class WNafPreCompInfo implements PreCompInfo return preComp; } + protected ECPoint[] getPreCompNeg() + { + return preCompNeg; + } + protected void setPreComp(ECPoint[] preComp) { this.preComp = preComp; } + protected void setPreCompNeg(ECPoint[] preCompNeg) + { + this.preCompNeg = preCompNeg; + } + protected ECPoint getTwiceP() { return twiceP; } - protected void setTwiceP(ECPoint twiceThis) + protected void setTwiceP(ECPoint twiceP) { - this.twiceP = twiceThis; + this.twiceP = twiceP; } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java new file mode 100644 index 0000000..6465d66 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java @@ -0,0 +1,393 @@ +package org.bouncycastle.math.ec; + +import java.math.BigInteger; + +public abstract class WNafUtil +{ + private static int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 }; + + public static int[] generateCompactNaf(BigInteger k) + { + if ((k.bitLength() >>> 16) != 0) + { + throw new IllegalArgumentException("'k' must have bitlength < 2^16"); + } + + BigInteger _3k = k.shiftLeft(1).add(k); + + int digits = _3k.bitLength() - 1; + int[] naf = new int[(digits + 1) >> 1]; + + int length = 0, zeroes = 0; + for (int i = 1; i <= digits; ++i) + { + boolean _3kBit = _3k.testBit(i); + boolean kBit = k.testBit(i); + + if (_3kBit == kBit) + { + ++zeroes; + } + else + { + int digit = kBit ? -1 : 1; + naf[length++] = (digit << 16) | zeroes; + zeroes = 0; + } + } + + if (naf.length > length) + { + naf = trim(naf, length); + } + + return naf; + } + + public static int[] generateCompactWindowNaf(int width, BigInteger k) + { + if (width == 2) + { + return generateCompactNaf(k); + } + + if (width < 2 || width > 16) + { + throw new IllegalArgumentException("'width' must be in the range [2, 16]"); + } + if ((k.bitLength() >>> 16) != 0) + { + throw new IllegalArgumentException("'k' must have bitlength < 2^16"); + } + + int[] wnaf = new int[k.bitLength() / width + 1]; + + // 2^width and a mask and sign bit set accordingly + int pow2 = 1 << width; + int mask = pow2 - 1; + int sign = pow2 >>> 1; + + boolean carry = false; + int length = 0, pos = 0; + + while (pos <= k.bitLength()) + { + if (k.testBit(pos) == carry) + { + ++pos; + continue; + } + + k = k.shiftRight(pos); + + int digit = k.intValue() & mask; + if (carry) + { + ++digit; + } + + carry = (digit & sign) != 0; + if (carry) + { + digit -= pow2; + } + + int zeroes = length > 0 ? pos - 1 : pos; + wnaf[length++] = (digit << 16) | zeroes; + pos = width; + } + + // Reduce the WNAF array to its actual length + if (wnaf.length > length) + { + wnaf = trim(wnaf, length); + } + + return wnaf; + } + + public static byte[] generateJSF(BigInteger g, BigInteger h) + { + int digits = Math.max(g.bitLength(), h.bitLength()) + 1; + byte[] jsf = new byte[digits]; + + BigInteger k0 = g, k1 = h; + int j = 0, d0 = 0, d1 = 0; + + while (k0.signum() > 0 || k1.signum() > 0 || d0 > 0 || d1 > 0) + { + int n0 = (k0.intValue() + d0) & 7, n1 = (k1.intValue() + d1) & 7; + + int u0 = n0 & 1; + if (u0 != 0) + { + u0 -= (n0 & 2); + if ((n0 + u0) == 4 && (n1 & 3) == 2) + { + u0 = -u0; + } + } + + int u1 = n1 & 1; + if (u1 != 0) + { + u1 -= (n1 & 2); + if ((n1 + u1) == 4 && (n0 & 3) == 2) + { + u1 = -u1; + } + } + + if ((d0 << 1) == 1 + u0) + { + d0 = 1 - d0; + } + if ((d1 << 1) == 1 + u1) + { + d1 = 1 - d1; + } + + k0 = k0.shiftRight(1); + k1 = k1.shiftRight(1); + + jsf[j++] = (byte)((u0 << 4) | (u1 & 0xF)); + } + + // Reduce the JSF array to its actual length + if (jsf.length > j) + { + jsf = trim(jsf, j); + } + + return jsf; + } + + public static byte[] generateNaf(BigInteger k) + { + BigInteger _3k = k.shiftLeft(1).add(k); + + int digits = _3k.bitLength() - 1; + byte[] naf = new byte[digits]; + + for (int i = 1; i <= digits; ++i) + { + boolean _3kBit = _3k.testBit(i); + boolean kBit = k.testBit(i); + + naf[i - 1] = (byte)(_3kBit == kBit ? 0 : kBit ? -1 : 1); + } + + return naf; + } + + /** + * Computes the Window NAF (non-adjacent Form) of an integer. + * @param width The width <code>w</code> of the Window NAF. The width is + * defined as the minimal number <code>w</code>, such that for any + * <code>w</code> consecutive digits in the resulting representation, at + * most one is non-zero. + * @param k The integer of which the Window NAF is computed. + * @return The Window NAF of the given width, such that the following holds: + * <code>k = ∑<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup> + * </code>, where the <code>k<sub>i</sub></code> denote the elements of the + * returned <code>byte[]</code>. + */ + public static byte[] generateWindowNaf(int width, BigInteger k) + { + if (width == 2) + { + return generateNaf(k); + } + + if (width < 2 || width > 8) + { + throw new IllegalArgumentException("'width' must be in the range [2, 8]"); + } + + byte[] wnaf = new byte[k.bitLength() + 1]; + + // 2^width and a mask and sign bit set accordingly + int pow2 = 1 << width; + int mask = pow2 - 1; + int sign = pow2 >>> 1; + + boolean carry = false; + int length = 0, pos = 0; + + while (pos <= k.bitLength()) + { + if (k.testBit(pos) == carry) + { + ++pos; + continue; + } + + k = k.shiftRight(pos); + + int digit = k.intValue() & mask; + if (carry) + { + ++digit; + } + + carry = (digit & sign) != 0; + if (carry) + { + digit -= pow2; + } + + length += (length > 0) ? pos - 1 : pos; + wnaf[length++] = (byte)digit; + pos = width; + } + + // Reduce the WNAF array to its actual length + if (wnaf.length > length) + { + wnaf = trim(wnaf, length); + } + + return wnaf; + } + + public static WNafPreCompInfo getWNafPreCompInfo(PreCompInfo preCompInfo) + { + if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo)) + { + return (WNafPreCompInfo)preCompInfo; + } + + return new WNafPreCompInfo(); + } + + /** + * 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 + */ + public static int getWindowSize(int bits) + { + return getWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS); + } + + /** + * 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 + * @return the window size to use + */ + public static int getWindowSize(int bits, int[] windowSizeCutoffs) + { + int w = 0; + for (; w < windowSizeCutoffs.length; ++w) + { + if (bits < windowSizeCutoffs[w]) + { + break; + } + } + return w + 2; + } + + public static WNafPreCompInfo precompute(ECPoint p, int width, boolean includeNegated) + { + ECCurve c = p.getCurve(); + WNafPreCompInfo wnafPreCompInfo = getWNafPreCompInfo(c.getPreCompInfo(p)); + + ECPoint[] preComp = wnafPreCompInfo.getPreComp(); + if (preComp == null) + { + preComp = new ECPoint[]{ p }; + } + + int preCompLen = preComp.length; + int reqPreCompLen = 1 << Math.max(0, width - 2); + + if (preCompLen < reqPreCompLen) + { + ECPoint twiceP = wnafPreCompInfo.getTwiceP(); + if (twiceP == null) + { + twiceP = preComp[0].twice().normalize(); + wnafPreCompInfo.setTwiceP(twiceP); + } + + preComp = resizeTable(preComp, reqPreCompLen); + + /* + * TODO Okeya/Sakurai paper has precomputation trick and "Montgomery's Trick" to speed this up. + * Also, co-Z arithmetic could avoid the subsequent normalization too. + */ + for (int i = preCompLen; i < reqPreCompLen; i++) + { + /* + * Compute the new ECPoints for the precomputation array. The values 1, 3, 5, ..., + * 2^(width-1)-1 times p are computed + */ + preComp[i] = twiceP.add(preComp[i - 1]); + } + + /* + * Having oft-used operands in affine form makes operations faster. + */ + c.normalizeAll(preComp); + } + + wnafPreCompInfo.setPreComp(preComp); + + if (includeNegated) + { + ECPoint[] preCompNeg = wnafPreCompInfo.getPreCompNeg(); + + int pos; + if (preCompNeg == null) + { + pos = 0; + preCompNeg = new ECPoint[reqPreCompLen]; + } + else + { + pos = preCompNeg.length; + if (pos < reqPreCompLen) + { + preCompNeg = resizeTable(preCompNeg, reqPreCompLen); + } + } + + while (pos < reqPreCompLen) + { + preCompNeg[pos] = preComp[pos].negate(); + ++pos; + } + + wnafPreCompInfo.setPreCompNeg(preCompNeg); + } + + c.setPreCompInfo(p, wnafPreCompInfo); + + return wnafPreCompInfo; + } + + private static byte[] trim(byte[] a, int length) + { + byte[] result = new byte[length]; + System.arraycopy(a, 0, result, 0, result.length); + return result; + } + + private static int[] trim(int[] a, int length) + { + int[] result = new int[length]; + System.arraycopy(a, 0, result, 0, result.length); + return result; + } + + private static ECPoint[] resizeTable(ECPoint[] a, int length) + { + ECPoint[] result = new ECPoint[length]; + System.arraycopy(a, 0, result, 0, a.length); + return result; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java index 2353979..7bd30ec 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java @@ -6,7 +6,7 @@ import java.math.BigInteger; * Class implementing the WTNAF (Window * <code>τ</code>-adic Non-Adjacent Form) algorithm. */ -class WTauNafMultiplier implements ECMultiplier +public class WTauNafMultiplier extends AbstractECMultiplier { /** * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m} @@ -16,7 +16,7 @@ class WTauNafMultiplier implements ECMultiplier * @param k The integer by which to multiply <code>k</code>. * @return <code>p</code> multiplied by <code>k</code>. */ - public ECPoint multiply(ECPoint point, BigInteger k, PreCompInfo preCompInfo) + protected ECPoint multiplyPositive(ECPoint point, BigInteger k) { if (!(point instanceof ECPoint.F2m)) { @@ -25,8 +25,7 @@ class WTauNafMultiplier implements ECMultiplier } ECPoint.F2m p = (ECPoint.F2m)point; - - ECCurve.F2m curve = (ECCurve.F2m) p.getCurve(); + ECCurve.F2m curve = (ECCurve.F2m)p.getCurve(); int m = curve.getM(); byte a = curve.getA().toBigInteger().byteValue(); byte mu = curve.getMu(); @@ -34,7 +33,7 @@ class WTauNafMultiplier implements ECMultiplier ZTauElement rho = Tnaf.partModReduction(k, m, a, s, mu, (byte)10); - return multiplyWTnaf(p, rho, preCompInfo, a, mu); + return multiplyWTnaf(p, rho, curve.getPreCompInfo(p), a, mu); } /** @@ -88,7 +87,7 @@ class WTauNafMultiplier implements ECMultiplier if ((preCompInfo == null) || !(preCompInfo instanceof WTauNafPreCompInfo)) { pu = Tnaf.getPreComp(p, a); - p.setPreCompInfo(new WTauNafPreCompInfo(pu)); + curve.setPreCompInfo(p, new WTauNafPreCompInfo(pu)); } else { diff --git a/bcprov/src/main/java/org/bouncycastle/util/Arrays.java b/bcprov/src/main/java/org/bouncycastle/util/Arrays.java index 457320e..3f7677c 100644 --- a/bcprov/src/main/java/org/bouncycastle/util/Arrays.java +++ b/bcprov/src/main/java/org/bouncycastle/util/Arrays.java @@ -11,7 +11,7 @@ public final class Arrays { // static class, hide constructor } - + public static boolean areEqual( boolean[] a, boolean[] b) @@ -199,36 +199,62 @@ public final class Arrays return true; } - public static boolean areEqual( - BigInteger[] a, - BigInteger[] b) + public static boolean areEqual(Object[] a, Object[] 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].equals(b[i])) + Object objA = a[i], objB = b[i]; + if (objA == null) + { + if (objB != null) + { + return false; + } + } + else if (!objA.equals(objB)) { return false; } } - return true; } + public static boolean contains(short[] a, short n) + { + for (int i = 0; i < a.length; ++i) + { + if (a[i] == n) + { + return true; + } + } + return false; + } + + public static boolean contains(int[] a, int n) + { + for (int i = 0; i < a.length; ++i) + { + if (a[i] == n) + { + return true; + } + } + return false; + } + public static void fill( byte[] array, byte value) @@ -391,7 +417,7 @@ public final class Arrays return hc; } - public static int hashCode(BigInteger[] data) + public static int hashCode(Object[] data) { if (data == null) { @@ -423,6 +449,20 @@ public final class Arrays return copy; } + public static byte[] clone(byte[] data, byte[] existing) + { + 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; + } + public static byte[][] clone(byte[][] data) { if (data == null) @@ -470,6 +510,33 @@ public final class Arrays return copy; } + public static long[] clone(long[] data) + { + if (data == null) + { + return null; + } + long[] copy = new long[data.length]; + + System.arraycopy(data, 0, copy, 0, data.length); + + return copy; + } + + public static long[] clone(long[] data, long[] existing) + { + 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; + } + public static short[] clone(short[] data) { if (data == null) @@ -576,6 +643,17 @@ public final class Arrays return tmp; } + /** + * 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. + * + * @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). + * + * @return a new byte array containing the range given. + */ public static byte[] copyOfRange(byte[] data, int from, int to) { int newLength = getLength(from, to); @@ -660,6 +738,34 @@ public final class Arrays return newLength; } + public static byte[] append(byte[] a, byte b) + { + if (a == null) + { + return new byte[]{ b }; + } + + int length = a.length; + byte[] result = new byte[length + 1]; + System.arraycopy(a, 0, result, 0, length); + result[length] = b; + return result; + } + + public static int[] append(int[] a, int b) + { + if (a == null) + { + return new int[]{ b }; + } + + int length = a.length; + int[] result = new int[length + 1]; + System.arraycopy(a, 0, result, 0, length); + result[length] = b; + return result; + } + public static byte[] concatenate(byte[] a, byte[] b) { if (a != null && b != null) @@ -733,4 +839,18 @@ public final class Arrays return concatenate(b, c, d); } } + + public static byte[] prepend(byte[] a, byte b) + { + if (a == null) + { + return new byte[]{ b }; + } + + int length = a.length; + byte[] result = new byte[length + 1]; + System.arraycopy(a, 0, result, 1, length); + result[0] = b; + return result; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java b/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java index e2fe590..f7f7e68 100644 --- a/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java +++ b/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java @@ -40,43 +40,25 @@ public final class BigIntegers * @param value value to be converted. * @return a byte array without a leading zero byte if present in the signed encoding. */ - public static byte[] asUnsignedByteArray( - int length, - BigInteger value) + public static byte[] asUnsignedByteArray(int length, BigInteger value) { byte[] bytes = value.toByteArray(); - - if (bytes[0] == 0) + if (bytes.length == length) { - if (bytes.length - 1 > length) - { - throw new IllegalArgumentException("standard length exceeded for value"); - } - - byte[] tmp = new byte[length]; - - System.arraycopy(bytes, 1, tmp, tmp.length - (bytes.length - 1), bytes.length - 1); - - return tmp; + return bytes; } - else - { - if (bytes.length == length) - { - return bytes; - } - - if (bytes.length > length) - { - throw new IllegalArgumentException("standard length exceeded for value"); - } - byte[] tmp = new byte[length]; + int start = bytes[0] == 0 ? 1 : 0; + int count = bytes.length - start; - System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length); - - return tmp; + if (count > length) + { + throw new IllegalArgumentException("standard length exceeded for value"); } + + byte[] tmp = new byte[length]; + System.arraycopy(bytes, start, tmp, tmp.length - count, count); + return tmp; } /** @@ -120,4 +102,20 @@ public final class BigIntegers // fall back to a faster (restricted) method return new BigInteger(max.subtract(min).bitLength() - 1, random).add(min); } + + public static BigInteger fromUnsignedByteArray(byte[] buf) + { + return new BigInteger(1, buf); + } + + public static BigInteger fromUnsignedByteArray(byte[] buf, int off, int length) + { + byte[] mag = buf; + if (off != 0 || length != buf.length) + { + mag = new byte[length]; + System.arraycopy(buf, off, mag, 0, length); + } + return new BigInteger(1, mag); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509Store.java b/bcprov/src/main/java/org/bouncycastle/x509/X509Store.java deleted file mode 100644 index 1bfc00f..0000000 --- a/bcprov/src/main/java/org/bouncycastle/x509/X509Store.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.bouncycastle.x509; - -import org.bouncycastle.util.Selector; -import org.bouncycastle.util.Store; - -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Provider; -import java.util.Collection; - -public class X509Store - implements Store -{ - public static X509Store getInstance(String type, X509StoreParameters parameters) - throws NoSuchStoreException - { - try - { - X509Util.Implementation impl = X509Util.getImplementation("X509Store", type); - - return createStore(impl, parameters); - } - catch (NoSuchAlgorithmException e) - { - throw new NoSuchStoreException(e.getMessage()); - } - } - - public static X509Store getInstance(String type, X509StoreParameters parameters, String provider) - throws NoSuchStoreException, NoSuchProviderException - { - return getInstance(type, parameters, X509Util.getProvider(provider)); - } - - public static X509Store getInstance(String type, X509StoreParameters parameters, Provider provider) - throws NoSuchStoreException - { - try - { - X509Util.Implementation impl = X509Util.getImplementation("X509Store", type, provider); - - return createStore(impl, parameters); - } - catch (NoSuchAlgorithmException e) - { - throw new NoSuchStoreException(e.getMessage()); - } - } - - private static X509Store createStore(X509Util.Implementation impl, X509StoreParameters parameters) - { - X509StoreSpi spi = (X509StoreSpi)impl.getEngine(); - - spi.engineInit(parameters); - - return new X509Store(impl.getProvider(), spi); - } - - private Provider _provider; - private X509StoreSpi _spi; - - private X509Store( - Provider provider, - X509StoreSpi spi) - { - _provider = provider; - _spi = spi; - } - - public Provider getProvider() - { - return _provider; - } - - public Collection getMatches(Selector selector) - { - return _spi.engineGetMatches(selector); - } -} |