diff options
Diffstat (limited to 'bcprov')
267 files changed, 9358 insertions, 2887 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java index c67e42f3..770af15c 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java @@ -3,9 +3,10 @@ package org.bouncycastle.asn1; import java.io.IOException; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; /** - * Base class for an application specific object + * Base class for an ASN.1 ApplicationSpecific object */ public abstract class ASN1ApplicationSpecific extends ASN1Primitive @@ -194,25 +195,19 @@ public abstract class ASN1ApplicationSpecific // if (tagNo == 0x1f) { - tagNo = 0; - int b = input[index++] & 0xff; // X.690-0207 8.1.2.4.2 // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." if ((b & 0x7f) == 0) // Note: -1 will pass { - throw new ASN1ParsingException("corrupted stream - invalid high tag number found"); + throw new IOException("corrupted stream - invalid high tag number found"); } - while ((b >= 0) && ((b & 0x80) != 0)) + while ((b & 0x80) != 0) { - tagNo |= (b & 0x7f); - tagNo <<= 7; b = input[index++] & 0xff; } - -// tagNo |= (b & 0x7f); } byte[] tmp = new byte[input.length - index + 1]; @@ -223,4 +218,29 @@ public abstract class ASN1ApplicationSpecific return tmp; } + + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("["); + if (isConstructed()) + { + sb.append("CONSTRUCTED "); + } + sb.append("APPLICATION "); + sb.append(Integer.toString(getApplicationTag())); + sb.append("]"); + // @todo content encoding somehow? + if (this.octets != null) + { + sb.append(" #"); + sb.append(Hex.toHexString(this.octets)); + } + else + { + sb.append(" #null"); + } + sb.append(" "); + return sb.toString(); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java index 8816b2b5..422bccf7 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java @@ -3,7 +3,7 @@ package org.bouncycastle.asn1; import java.io.IOException; /** - * Interface to parse ASN.1 application specific objects. + * Interface to parse ASN.1 ApplicationSpecific objects. */ public interface ASN1ApplicationSpecificParser extends ASN1Encodable, InMemoryRepresentable diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1BitString.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1BitString.java index 513d4e5b..e1aba657 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1BitString.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1BitString.java @@ -58,6 +58,7 @@ public abstract class ASN1BitString return 0; } + int bits = 1; while (((val <<= 1) & 0xFF) != 0) @@ -135,7 +136,7 @@ public abstract class ASN1BitString { StringBuffer buf = new StringBuffer("#"); ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); try { @@ -216,7 +217,7 @@ public abstract class ASN1BitString } protected boolean asn1Equals( - ASN1Primitive o) + ASN1Primitive o) { if (!(o instanceof ASN1BitString)) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java index 0225e6e9..e968660f 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java @@ -14,7 +14,6 @@ import org.bouncycastle.util.Arrays; * <li> {@link ASN1Boolean#getInstance(boolean) ASN1Boolean.getInstance(boolean)}</li> * <li> {@link ASN1Boolean#getInstance(int) ASN1Boolean.getInstance(int)}</li> * </ul> - * </p> */ public class ASN1Boolean extends ASN1Primitive @@ -28,7 +27,7 @@ public class ASN1Boolean public static final ASN1Boolean TRUE = new ASN1Boolean(true); /** - * return a boolean from the passed in object. + * Return a boolean from the passed in object. * * @param obj an ASN1Boolean or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. @@ -59,7 +58,7 @@ public class ASN1Boolean } /** - * return an ASN1Boolean from the passed in boolean. + * Return an ASN1Boolean from the passed in boolean. * @param value true or false depending on the ASN1Boolean wanted. * @return an ASN1Boolean instance. */ @@ -70,7 +69,7 @@ public class ASN1Boolean } /** - * return an ASN1Boolean from the passed in value. + * Return an ASN1Boolean from the passed in value. * @param value non-zero (true) or zero (false) depending on the ASN1Boolean wanted. * @return an ASN1Boolean instance. */ @@ -92,7 +91,7 @@ public class ASN1Boolean // END Android-added: Unknown reason /** - * return a Boolean from a tagged object. + * Return a Boolean from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java index 3ca88905..4d92dd82 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java @@ -8,7 +8,6 @@ package org.bouncycastle.asn1; * If you use this interface your class should also implement the getInstance() * pattern which takes a tag object and the tagging mode used. * </p> - * <hr> * <p><b>X.690</b></p> * <p><b>8: Basic encoding rules</b></p> * <p><b>8.13 Encoding of a choice value </b></p> @@ -16,11 +15,11 @@ package org.bouncycastle.asn1; * The encoding of a choice value shall be the same as the encoding of a value of the chosen type. * <blockquote> * NOTE 1 — The encoding may be primitive or constructed depending on the chosen type. - * <br /> + * </blockquote> + * <blockquote> * NOTE 2 — The tag used in the identifier octets is the tag of the chosen type, * as specified in the ASN.1 definition of the choice type. * </blockquote> - * </p> */ public interface ASN1Choice { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java index 2828541e..0971748a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java @@ -4,7 +4,7 @@ import java.util.Enumeration; import java.util.Vector; /** - * Mutable class for building ASN.1 constructed objects. + * Mutable class for building ASN.1 constructed objects such as SETs or SEQUENCEs. */ public class ASN1EncodableVector { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java index ca192f31..aa89eb5d 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.math.BigInteger; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Properties; /** * Class representing the ASN.1 ENUMERATED type. @@ -99,13 +100,9 @@ public class ASN1Enumerated public ASN1Enumerated( byte[] bytes) { - if (bytes.length > 1) + if (!Properties.isOverrideSet("org.bouncycastle.asn1.allow_unsafe_integer")) { - if (bytes[0] == 0 && (bytes[1] & 0x80) == 0) - { - throw new IllegalArgumentException("malformed enumerated"); - } - if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0) + if (ASN1Integer.isMalformed(bytes)) { throw new IllegalArgumentException("malformed enumerated"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1External.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1External.java new file mode 100644 index 00000000..7db80fff --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1External.java @@ -0,0 +1,292 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +/** + * Class representing the DER-type External + */ +public abstract class ASN1External + extends ASN1Primitive +{ + protected ASN1ObjectIdentifier directReference; + protected ASN1Integer indirectReference; + protected ASN1Primitive dataValueDescriptor; + protected int encoding; + protected ASN1Primitive externalContent; + + /** + * Construct an EXTERNAL object, the input encoding vector must have exactly two elements on it. + * <p> + * Acceptable input formats are: + * <ul> + * <li> {@link ASN1ObjectIdentifier} + data {@link DERTaggedObject} (direct reference form)</li> + * <li> {@link ASN1Integer} + data {@link DERTaggedObject} (indirect reference form)</li> + * <li> Anything but {@link DERTaggedObject} + data {@link DERTaggedObject} (data value form)</li> + * </ul> + * + * @throws IllegalArgumentException if input size is wrong, or + */ + public ASN1External(ASN1EncodableVector vector) + { + int offset = 0; + + ASN1Primitive enc = getObjFromVector(vector, offset); + if (enc instanceof ASN1ObjectIdentifier) + { + directReference = (ASN1ObjectIdentifier)enc; + offset++; + enc = getObjFromVector(vector, offset); + } + if (enc instanceof ASN1Integer) + { + indirectReference = (ASN1Integer) enc; + offset++; + enc = getObjFromVector(vector, offset); + } + if (!(enc instanceof ASN1TaggedObject)) + { + dataValueDescriptor = (ASN1Primitive) enc; + offset++; + enc = getObjFromVector(vector, offset); + } + + if (vector.size() != offset + 1) + { + throw new IllegalArgumentException("input vector too large"); + } + + if (!(enc instanceof ASN1TaggedObject)) + { + throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External"); + } + ASN1TaggedObject obj = (ASN1TaggedObject)enc; + setEncoding(obj.getTagNo()); + externalContent = obj.getObject(); + } + + private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index) + { + if (v.size() <= index) + { + throw new IllegalArgumentException("too few objects in input vector"); + } + + return v.get(index).toASN1Primitive(); + } + + /** + * Creates a new instance of External + * See X.690 for more informations about the meaning of these parameters + * @param directReference The direct reference or <code>null</code> if not set. + * @param indirectReference The indirect reference or <code>null</code> if not set. + * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set. + * @param externalData The external data in its encoded form. + */ + public ASN1External(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData) + { + this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive()); + } + + /** + * Creates a new instance of External. + * See X.690 for more informations about the meaning of these parameters + * @param directReference The direct reference or <code>null</code> if not set. + * @param indirectReference The indirect reference or <code>null</code> if not set. + * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set. + * @param encoding The encoding to be used for the external data + * @param externalData The external data + */ + public ASN1External(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData) + { + setDirectReference(directReference); + setIndirectReference(indirectReference); + setDataValueDescriptor(dataValueDescriptor); + setEncoding(encoding); + setExternalContent(externalData.toASN1Primitive()); + } + + ASN1Primitive toDERObject() + { + if (this instanceof DERExternal) + { + return this; + } + + return new DERExternal(directReference, indirectReference, dataValueDescriptor, encoding, externalContent); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() + { + int ret = 0; + if (directReference != null) + { + ret = directReference.hashCode(); + } + if (indirectReference != null) + { + ret ^= indirectReference.hashCode(); + } + if (dataValueDescriptor != null) + { + ret ^= dataValueDescriptor.hashCode(); + } + ret ^= externalContent.hashCode(); + return ret; + } + + boolean isConstructed() + { + return true; + } + + int encodedLength() + throws IOException + { + return this.getEncoded().length; + } + + /* (non-Javadoc) + * @see org.bouncycastle.asn1.ASN1Primitive#asn1Equals(org.bouncycastle.asn1.ASN1Primitive) + */ + boolean asn1Equals(ASN1Primitive o) + { + if (!(o instanceof ASN1External)) + { + return false; + } + if (this == o) + { + return true; + } + ASN1External other = (ASN1External)o; + if (directReference != null) + { + if (other.directReference == null || !other.directReference.equals(directReference)) + { + return false; + } + } + if (indirectReference != null) + { + if (other.indirectReference == null || !other.indirectReference.equals(indirectReference)) + { + return false; + } + } + if (dataValueDescriptor != null) + { + if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor)) + { + return false; + } + } + return externalContent.equals(other.externalContent); + } + + /** + * Returns the data value descriptor + * @return The descriptor + */ + public ASN1Primitive getDataValueDescriptor() + { + return dataValueDescriptor; + } + + /** + * Returns the direct reference of the external element + * @return The reference + */ + public ASN1ObjectIdentifier getDirectReference() + { + return directReference; + } + + /** + * Returns the encoding of the content. Valid values are + * <ul> + * <li><code>0</code> single-ASN1-type</li> + * <li><code>1</code> OCTET STRING</li> + * <li><code>2</code> BIT STRING</li> + * </ul> + * @return The encoding + */ + public int getEncoding() + { + return encoding; + } + + /** + * Returns the content of this element + * @return The content + */ + public ASN1Primitive getExternalContent() + { + return externalContent; + } + + /** + * Returns the indirect reference of this element + * @return The reference + */ + public ASN1Integer getIndirectReference() + { + return indirectReference; + } + + /** + * Sets the data value descriptor + * @param dataValueDescriptor The descriptor + */ + private void setDataValueDescriptor(ASN1Primitive dataValueDescriptor) + { + this.dataValueDescriptor = dataValueDescriptor; + } + + /** + * Sets the direct reference of the external element + * @param directReferemce The reference + */ + private void setDirectReference(ASN1ObjectIdentifier directReferemce) + { + this.directReference = directReferemce; + } + + /** + * Sets the encoding of the content. Valid values are + * <ul> + * <li><code>0</code> single-ASN1-type</li> + * <li><code>1</code> OCTET STRING</li> + * <li><code>2</code> BIT STRING</li> + * </ul> + * @param encoding The encoding + */ + private void setEncoding(int encoding) + { + if (encoding < 0 || encoding > 2) + { + throw new IllegalArgumentException("invalid encoding value: " + encoding); + } + this.encoding = encoding; + } + + /** + * Sets the content of this element + * @param externalContent The content + */ + private void setExternalContent(ASN1Primitive externalContent) + { + this.externalContent = externalContent; + } + + /** + * Sets the indirect reference of this element + * @param indirectReference The reference + */ + private void setIndirectReference(ASN1Integer indirectReference) + { + this.indirectReference = indirectReference; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java index 6040676a..ba8de8da 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java @@ -18,11 +18,35 @@ import org.bouncycastle.util.Strings; * <p> * The main difference between these and UTC time is a 4 digit year. * </p> + * <p> + * One second resolution date+time on UTC timezone (Z) + * with 4 digit year (valid from 0001 to 9999). + * </p><p> + * Timestamp format is: yyyymmddHHMMSS'Z' + * </p><p> + * <h2>X.690</h2> + * This is what is called "restricted string", + * and it uses ASCII characters to encode digits and supplemental data. + * + * <h3>11: Restrictions on BER employed by both CER and DER</h3> + * <h4>11.7 GeneralizedTime </h4> + * <p> + * <b>11.7.1</b> The encoding shall terminate with a "Z", + * as described in the ITU-T Rec. X.680 | ISO/IEC 8824-1 clause on + * GeneralizedTime. + * </p><p> + * <b>11.7.2</b> The seconds element shall always be present. + * </p> + * <p> + * <b>11.7.3</b> The fractional-seconds elements, if present, + * shall omit all trailing zeros; if the elements correspond to 0, + * they shall be wholly omitted, and the decimal point element also + * shall be omitted. */ public class ASN1GeneralizedTime extends ASN1Primitive { - private byte[] time; + protected byte[] time; /** * return a generalized time from the passed in object @@ -112,7 +136,7 @@ public class ASN1GeneralizedTime Date time) { // Android-changed: Use localized version - // SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); + // SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", DateUtil.EN_Locale); SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US); dateF.setTimeZone(new SimpleTimeZone(0, "Z")); @@ -169,7 +193,6 @@ public class ASN1GeneralizedTime * </pre> * To read in the time and get a date which is compatible with our local * time zone. - * </p> * @return a String representation of the time. */ public String getTime() @@ -264,12 +287,24 @@ public class ASN1GeneralizedTime // dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'"); dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'", Locale.US); } - else + else if (hasSeconds()) { // Android-changed: Use localized version // dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US); } + else if (hasMinutes()) + { + // Android-changed: Use localized version + // dateF = new SimpleDateFormat("yyyyMMddHHmm'Z'"); + dateF = new SimpleDateFormat("yyyyMMddHHmm'Z'", Locale.US); + } + else + { + // Android-changed: Use localized version + // dateF = new SimpleDateFormat("yyyyMMddHH'Z'"); + dateF = new SimpleDateFormat("yyyyMMddHH'Z'", Locale.US); + } dateF.setTimeZone(new SimpleTimeZone(0, "Z")); } @@ -282,12 +317,24 @@ public class ASN1GeneralizedTime // dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz"); dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz", Locale.US); } - else + else if (hasSeconds()) { // Android-changed: Use localized version // dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); dateF = new SimpleDateFormat("yyyyMMddHHmmssz", Locale.US); } + else if (hasMinutes()) + { + // Android-changed: Use localized version + // dateF = new SimpleDateFormat("yyyyMMddHHmmz"); + dateF = new SimpleDateFormat("yyyyMMddHHmmz", Locale.US); + } + else + { + // Android-changed: Use localized version + // dateF = new SimpleDateFormat("yyyyMMddHHz"); + dateF = new SimpleDateFormat("yyyyMMddHHz", Locale.US); + } dateF.setTimeZone(new SimpleTimeZone(0, "Z")); } @@ -299,12 +346,24 @@ public class ASN1GeneralizedTime // dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS", Locale.US); } - else + else if (hasSeconds()) { // Android-changed: Use localized version // dateF = new SimpleDateFormat("yyyyMMddHHmmss"); dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); } + else if (hasMinutes()) + { + // Android-changed: Use localized version + // dateF = new SimpleDateFormat("yyyyMMddHHmm"); + dateF = new SimpleDateFormat("yyyyMMddHHmm", Locale.US); + } + else + { + // Android-changed: Use localized version + // dateF = new SimpleDateFormat("yyyyMMddHH"); + dateF = new SimpleDateFormat("yyyyMMddHH", Locale.US); + } dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID())); } @@ -340,10 +399,10 @@ public class ASN1GeneralizedTime } } - return dateF.parse(d); + return DateUtil.epochAdjust(dateF.parse(d)); } - private boolean hasFractionalSeconds() + protected boolean hasFractionalSeconds() { for (int i = 0; i != time.length; i++) { @@ -358,6 +417,21 @@ public class ASN1GeneralizedTime return false; } + protected boolean hasSeconds() + { + return isDigit(12) && isDigit(13); + } + + protected boolean hasMinutes() + { + return isDigit(10) && isDigit(11); + } + + private boolean isDigit(int pos) + { + return time.length > pos && time[pos] >= '0' && time[pos] <= '9'; + } + boolean isConstructed() { return false; @@ -377,6 +451,11 @@ public class ASN1GeneralizedTime out.writeEncoded(BERTags.GENERALIZED_TIME, time); } + ASN1Primitive toDERObject() + { + return new DERGeneralizedTime(time); + } + boolean asn1Equals( ASN1Primitive o) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java index 0c63a1a6..92d8cbb0 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java @@ -9,7 +9,7 @@ import java.io.InputStream; import org.bouncycastle.util.io.Streams; /** - * a general purpose ASN.1 decoder - note: this class differs from the + * A general purpose ASN.1 decoder - note: this class differs from the * others in that it returns null after it has read the last object in * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is * returned. @@ -143,7 +143,7 @@ public class ASN1InputStream if ((tag & APPLICATION) != 0) { - return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); + return new DLApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); } if ((tag & TAGGED) != 0) @@ -181,7 +181,7 @@ public class ASN1InputStream case SET: return DERFactory.createSet(buildDEREncodableVector(defIn)); case EXTERNAL: - return new DERExternal(buildDEREncodableVector(defIn)); + return new DLExternal(buildDEREncodableVector(defIn)); default: throw new IOException("unknown tag " + tagNo + " encountered"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java index ab6d2020..39ada8b5 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.math.BigInteger; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Properties; /** * Class representing the ASN.1 INTEGER type. @@ -14,11 +15,11 @@ public class ASN1Integer private final byte[] bytes; /** - * return an integer from the passed in object + * Return an integer from the passed in object. * * @param obj an ASN1Integer or an object that can be converted into one. - * @throws IllegalArgumentException if the object cannot be converted. * @return an ASN1Integer instance. + * @throws IllegalArgumentException if the object cannot be converted. */ public static ASN1Integer getInstance( Object obj) @@ -44,14 +45,14 @@ public class ASN1Integer } /** - * return an Integer from a tagged object. + * Return an Integer from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly * tagged false otherwise. + * @return an ASN1Integer instance. * @throws IllegalArgumentException if the tagged object cannot * be converted. - * @return an ASN1Integer instance. */ public static ASN1Integer getInstance( ASN1TaggedObject obj, @@ -65,22 +66,54 @@ public class ASN1Integer } else { - return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + return new ASN1Integer(ASN1OctetString.getInstance(o).getOctets()); } } + /** + * Construct an INTEGER from the passed in long value. + * + * @param value the long representing the value desired. + */ public ASN1Integer( long value) { bytes = BigInteger.valueOf(value).toByteArray(); } + /** + * Construct an INTEGER from the passed in BigInteger value. + * + * @param value the BigInteger representing the value desired. + */ public ASN1Integer( BigInteger value) { bytes = value.toByteArray(); } + /** + * Construct an INTEGER from the passed in byte array. + * + * <p> + * <b>NB: Strict Validation applied by default.</b> + * </p> + * <p> + * It has turned out that there are still a few applications that struggle with + * the ASN.1 BER encoding rules for an INTEGER as described in: + * + * https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + * Section 8.3.2. + * </p> + * <p> + * Users can set the 'org.bouncycastle.asn1.allow_unsafe_integer' to 'true' + * and a looser validation will be applied. Users must recognise that this is + * not ideal and may pave the way for an exploit based around a faulty encoding + * in the future. + * </p> + * + * @param bytes the byte array representing a 2's complement encoding of a BigInteger. + */ public ASN1Integer( byte[] bytes) { @@ -89,18 +122,38 @@ public class ASN1Integer ASN1Integer(byte[] bytes, boolean clone) { + // Apply loose validation, see note in public constructor ANS1Integer(byte[]) + if (!Properties.isOverrideSet("org.bouncycastle.asn1.allow_unsafe_integer")) + { + if (isMalformed(bytes)) + { + throw new IllegalArgumentException("malformed integer"); + } + } + this.bytes = (clone) ? Arrays.clone(bytes) : bytes; + } + + /** + * Apply the correct validation for an INTEGER primitive following the BER rules. + * + * @param bytes The raw encoding of the integer. + * @return true if the (in)put fails this validation. + */ + static boolean isMalformed(byte[] bytes) + { if (bytes.length > 1) { if (bytes[0] == 0 && (bytes[1] & 0x80) == 0) { - throw new IllegalArgumentException("malformed integer"); + return true; } if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0) { - throw new IllegalArgumentException("malformed integer"); + return true; } } - this.bytes = (clone) ? Arrays.clone(bytes) : bytes; + + return false; } public BigInteger getValue() @@ -111,6 +164,7 @@ public class ASN1Integer /** * in some cases positive values get crammed into a space, * that's not quite big enough... + * * @return the BigInteger that results from treating this ASN.1 INTEGER as unsigned. */ public BigInteger getPositiveValue() diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java index f39d1206..7cf07657 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java @@ -1,3 +1,6 @@ +/***************************************************************/ +/****** DO NOT EDIT THIS CLASS bc-java SOURCE FILE ******/ +/***************************************************************/ package org.bouncycastle.asn1; import java.io.IOException; @@ -8,6 +11,11 @@ import java.io.IOException; public abstract class ASN1Null extends ASN1Primitive { + ASN1Null() + { + + } + /** * Return an instance of ASN.1 NULL from the passed in object. * <p> diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java index bdfec4fd..b5288a2b 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java @@ -19,7 +19,7 @@ public class ASN1ObjectIdentifier private byte[] body; /** - * return an OID from the passed in object + * Return an OID from the passed in object * * @param obj an ASN1ObjectIdentifier or an object that can be converted into one. * @return an ASN1ObjectIdentifier instance, or null. @@ -33,9 +33,14 @@ public class ASN1ObjectIdentifier return (ASN1ObjectIdentifier)obj; } - if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) + if (obj instanceof ASN1Encodable) { - return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); + ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); + + if (primitive instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)primitive; + } } if (obj instanceof byte[]) @@ -55,7 +60,7 @@ public class ASN1ObjectIdentifier } /** - * return an Object Identifier from a tagged object. + * Return an OBJECT IDENTIFIER from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly @@ -76,7 +81,7 @@ public class ASN1ObjectIdentifier } else { - return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(o).getOctets()); } } @@ -219,7 +224,7 @@ public class ASN1ObjectIdentifier } /** - * Return true if this oid is an extension of the passed in branch, stem. + * Return true if this oid is an extension of the passed in branch - stem. * * @param stem the arc or branch that is a possible parent. * @return true if the branch is on the passed in stem, false otherwise. diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java index 07811d71..2df802bc 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java @@ -16,7 +16,6 @@ import org.bouncycastle.util.encoders.Hex; * DER form is always primitive single OCTET STRING, while * BER support includes the constructed forms. * </p> - * <hr> * <p><b>X.690</b></p> * <p><b>8: Basic encoding rules</b></p> * <p><b>8.7 Encoding of an octetstring value</b></p> @@ -38,20 +37,19 @@ import org.bouncycastle.util.encoders.Hex; * <p> * <b>8.7.3</b> The contents octets for the constructed encoding shall consist * of zero, one, or more encodings. + * </p> * <blockquote> * NOTE — Each such encoding includes identifier, length, and contents octets, * and may include end-of-contents octets if it is constructed. * </blockquote> - * </p> * <p> * <b>8.7.3.1</b> To encode an octetstring value in this way, * it is segmented. Each segment shall consist of a series of * consecutive octets of the value. There shall be no significance - * placed on the segment boundaries. + * placed on the segment boundaries.</p> * <blockquote> * NOTE — A segment may be of size zero, i.e. contain no octets. * </blockquote> - * </p> * <p> * <b>8.7.3.2</b> Each encoding in the contents octets shall represent * a segment of the overall octetstring, the encoding arising from @@ -59,15 +57,16 @@ import org.bouncycastle.util.encoders.Hex; * In this recursive application, each segment is treated as if it were * a octetstring value. The encodings of the segments shall appear in the contents * octets in the order in which their octets appear in the overall value. + * </p> * <blockquote> * NOTE 1 — As a consequence of this recursion, * each encoding in the contents octets may itself * be primitive or constructed. * However, such encodings will usually be primitive. - * <br /> + * </blockquote> + * <blockquote> * NOTE 2 — In particular, the tags in the contents octets are always universal class, number 4. * </blockquote> - * </p> * <p><b>9: Canonical encoding rules</b></p> * <p><b>9.1 Length forms</b></p> * <p> @@ -96,7 +95,6 @@ import org.bouncycastle.util.encoders.Hex; * For BIT STRING, OCTET STRING and restricted character string types, * the constructed form of encoding shall not be used. * (Contrast with 8.21.6.) - * </p> */ public abstract class ASN1OctetString extends ASN1Primitive @@ -249,6 +247,6 @@ public abstract class ASN1OctetString public String toString() { - return "#"+ Strings.fromByteArray(Hex.encode(string)); + return "#" + Strings.fromByteArray(Hex.encode(string)); } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java index db72d6ad..94b0b3d5 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java @@ -79,11 +79,23 @@ public abstract class ASN1Primitive public abstract int hashCode(); + /** + * Return true if this objected is a CONSTRUCTED one, false otherwise. + * @return true if CONSTRUCTED bit set on object's tag, false otherwise. + */ abstract boolean isConstructed(); + /** + * Return the length of the encoding this object will produce. + * @return the length of the object's encoding. + * @throws IOException if the encoding length cannot be calculated. + */ abstract int encodedLength() throws IOException; abstract void encode(ASN1OutputStream out) throws IOException; + /** + * Equality (similarity) comparison for two ASN1Primitive objects. + */ abstract boolean asn1Equals(ASN1Primitive o); }
\ No newline at end of file diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java index 0ca4d8f5..ea6f3d87 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java @@ -50,9 +50,11 @@ import org.bouncycastle.util.Arrays; * * <p><b>11: Restrictions on BER employed by both CER and DER</b></p> * <p><b>11.5 Set and sequence components with default value</b></p> + * <p> * 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. + * </p> */ public abstract class ASN1Sequence extends ASN1Primitive @@ -103,7 +105,7 @@ public abstract class ASN1Sequence } /** - * Return an ASN1 sequence from a tagged object. There is a special + * Return an ASN1 SEQUENCE from a tagged object. There is a special * case here, if an object appears to have been explicitly tagged on * reading but we were expecting it to be implicitly tagged in the * normal course of events it indicates that we lost the surrounding @@ -134,6 +136,8 @@ public abstract class ASN1Sequence } else { + ASN1Primitive o = obj.getObject(); + // // constructed object which appears to be explicitly tagged // when it should be implicit means we have to add the @@ -143,18 +147,18 @@ public abstract class ASN1Sequence { if (obj instanceof BERTaggedObject) { - return new BERSequence(obj.getObject()); + return new BERSequence(o); } else { - return new DLSequence(obj.getObject()); + return new DLSequence(o); } } else { - if (obj.getObject() instanceof ASN1Sequence) + if (o instanceof ASN1Sequence) { - return (ASN1Sequence)obj.getObject(); + return (ASN1Sequence)o; } } } @@ -163,14 +167,14 @@ public abstract class ASN1Sequence } /** - * Create an empty sequence + * Create an empty SEQUENCE */ protected ASN1Sequence() { } /** - * Create a sequence containing one object + * Create a SEQUENCE containing one object. * @param obj the object to be put in the SEQUENCE. */ protected ASN1Sequence( @@ -180,8 +184,8 @@ public abstract class ASN1Sequence } /** - * Create a sequence containing a vector of objects. - * @param v the vector of objects to be put in the SEQUENCE + * Create a SEQUENCE containing a vector of objects. + * @param v the vector of objects to be put in the SEQUENCE. */ protected ASN1Sequence( ASN1EncodableVector v) @@ -192,8 +196,9 @@ public abstract class ASN1Sequence } } - /* - * Create a sequence containing a vector of objects. + /** + * Create a SEQUENCE containing an array of objects. + * @param array the array of objects to be put in the SEQUENCE. */ protected ASN1Sequence( ASN1Encodable[] array) diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java index 1f6234f5..9865533c 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java @@ -12,13 +12,12 @@ import org.bouncycastle.util.Arrays; * <p> * Note: This does not know which syntax the set is! * (The difference: ordering of SET elements or not ordering.) - * <p> + * </p><p> * DER form is always definite form length fields, while * BER support uses indefinite form. - * <p> + * </p><p> * The CER form support does not exist. - * <p> - * <hr> + * </p><p> * <h2>X.690</h2> * <h3>8: Basic encoding rules</h3> * <h4>8.11 Encoding of a set value </h4> @@ -29,7 +28,7 @@ import org.bouncycastle.util.Arrays; * 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> + * </p><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>. @@ -38,13 +37,14 @@ import org.bouncycastle.util.Arrays; * and places no constraints on the order during transfer * </blockquote> * <h4>8.12 Encoding of a set-of value</h4> - * <b>8.12.1</b> The encoding of a set-of value shall be constructed. * <p> + * <b>8.12.1</b> The encoding of a set-of value shall be constructed. + * </p><p> * <b>8.12.2</b> The text of 8.10.2 applies: * <i>The contents octets shall consist of zero, * one or more complete encodings of data values from the type listed in * the ASN.1 definition.</i> - * <p> + * </p><p> * <b>8.12.3</b> The order of data values need not be preserved by * the encoding and subsequent decoding. * @@ -175,6 +175,8 @@ public abstract class ASN1Set } else { + ASN1Primitive o = obj.getObject(); + // // constructed object which appears to be explicitly tagged // and it's really implicit means we have to add the @@ -184,27 +186,27 @@ public abstract class ASN1Set { if (obj instanceof BERTaggedObject) { - return new BERSet(obj.getObject()); + return new BERSet(o); } else { - return new DLSet(obj.getObject()); + return new DLSet(o); } } else { - if (obj.getObject() instanceof ASN1Set) + if (o instanceof ASN1Set) { - return (ASN1Set)obj.getObject(); + return (ASN1Set)o; } // // in this case the parser returns a sequence, convert it // into a set. // - if (obj.getObject() instanceof ASN1Sequence) + if (o instanceof ASN1Sequence) { - ASN1Sequence s = (ASN1Sequence)obj.getObject(); + ASN1Sequence s = (ASN1Sequence)o; if (obj instanceof BERTaggedObject) { @@ -226,7 +228,7 @@ public abstract class ASN1Set } /** - * create a sequence containing one object + * Create a SET containing one object * @param obj object to be added to the SET. */ protected ASN1Set( @@ -236,7 +238,7 @@ public abstract class ASN1Set } /** - * create a sequence containing a vector of objects. + * Create a SET containing a vector of objects. * @param v a vector of objects to make up the SET. * @param doSort true if should be sorted DER style, false otherwise. */ @@ -255,8 +257,10 @@ public abstract class ASN1Set } } - /* - * create a sequence containing a vector of objects. + /** + * Create a SET containing an array of objects. + * @param array an array of objects to make up the SET. + * @param doSort true if should be sorted DER style, false otherwise. */ protected ASN1Set( ASN1Encodable[] array, diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java index a4bb370e..a1034292 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java @@ -172,7 +172,7 @@ public class ASN1StreamParser if ((tag & BERTags.APPLICATION) != 0) { - return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); + return new DLApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); } if ((tag & BERTags.TAGGED) != 0) diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java index 37544406..0c265bb0 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java @@ -1,7 +1,7 @@ package org.bouncycastle.asn1; /** - * General interface implemented by ASN.1 STRING objects. + * General interface implemented by ASN.1 STRING objects for extracting the content String. */ public interface ASN1String { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java index 808f478e..66ac4aaa 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java @@ -173,7 +173,7 @@ public abstract class ASN1TaggedObject } /** - * return whatever was following the tag. + * Return whatever was following the tag. * <p> * Note: tagged objects are generally context dependent if you're * trying to extract a tagged object you should be going via the diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java index a681dc94..660d9a28 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java @@ -2,11 +2,26 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * Interface for the parsing of a generic tagged ASN.1 object. + */ public interface ASN1TaggedObjectParser extends ASN1Encodable, InMemoryRepresentable { - public int getTagNo(); - - public ASN1Encodable getObjectParser(int tag, boolean isExplicit) + /** + * Return the tag number associated with the underlying tagged object. + * @return the object's tag number. + */ + int getTagNo(); + + /** + * Return a parser for the actual object tagged. + * + * @param tag the primitive tag value for the object tagged originally. + * @param isExplicit true if the tagging was done explicitly. + * @return a parser for the tagged object. + * @throws IOException if a parser cannot be constructed. + */ + ASN1Encodable getObjectParser(int tag, boolean isExplicit) throws IOException; } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java index 446af77f..d2909370 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java @@ -17,7 +17,7 @@ import org.bouncycastle.util.Strings; * Internal facade of {@link ASN1UTCTime}. * <p> * This datatype is valid only from 1950-01-01 00:00:00 UTC until 2049-12-31 23:59:59 UTC. - * <p> + * </p> * <hr> * <p><b>X.690</b></p> * <p><b>11: Restrictions on BER employed by both CER and DER</b></p> @@ -39,7 +39,7 @@ public class ASN1UTCTime private byte[] time; /** - * return an UTC Time from the passed in object. + * Return an UTC Time from the passed in object. * * @param obj an ASN1UTCTime or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. @@ -69,7 +69,7 @@ public class ASN1UTCTime } /** - * return an UTC Time from a tagged object. + * Return an UTC Time from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly @@ -119,14 +119,14 @@ public class ASN1UTCTime } /** - * base constructor from a java.util.date object + * Base constructor from a java.util.date object * @param time the Date to build the time from. */ public ASN1UTCTime( Date time) { // Android-changed: Use localized version - // SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'"); + // SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", DateUtil.EN_Locale); SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", Locale.US); dateF.setTimeZone(new SimpleTimeZone(0,"Z")); @@ -163,7 +163,7 @@ public class ASN1UTCTime } /** - * return the time as a date based on whatever a 2 digit year will return. For + * Return the time as a date based on whatever a 2 digit year will return. For * standardised processing use getAdjustedDate(). * * @return the resulting date @@ -176,11 +176,11 @@ public class ASN1UTCTime // SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz"); SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz", Locale.US); - return dateF.parse(getTime()); + return DateUtil.epochAdjust(dateF.parse(getTime())); } /** - * return the time as an adjusted date + * Return the time as an adjusted date * in the range of 1950 - 2049. * * @return a date in the range of 1950 to 2049. @@ -193,13 +193,13 @@ public class ASN1UTCTime // SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz", Locale.US); - dateF.setTimeZone(new SimpleTimeZone(0, "Z")); - - return dateF.parse(getAdjustedTime()); + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + return DateUtil.epochAdjust(dateF.parse(getAdjustedTime())); } /** - * return the time - always in the form of + * Return the time - always in the form of * YYMMDDhhmmssGMT(+hh:mm|-hh:mm). * <p> * Normally in a certificate we would expect "Z" rather than "GMT", @@ -258,7 +258,7 @@ public class ASN1UTCTime } /** - * return a time string as an adjusted date with a 4 digit year. This goes + * Return a time string as an adjusted date with a 4 digit year. This goes * in the range of 1950 - 2049. */ public String getAdjustedTime() diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java index f8d6aa22..3608668d 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java @@ -4,7 +4,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; /** - * An indefinite-length encoding version of an application specific object. + * An indefinite-length encoding version of an ASN.1 ApplicationSpecific object. */ public class BERApplicationSpecific extends ASN1ApplicationSpecific diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java index e4904e05..c915415a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java @@ -3,7 +3,7 @@ package org.bouncycastle.asn1; import java.io.IOException; /** - * A parser for indefinite-length application specific objects. + * A parser for indefinite-length ASN.1 ApplicationSpecific objects. */ public class BERApplicationSpecificParser implements ASN1ApplicationSpecificParser diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetString.java b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetString.java index bc1ed448..63349340 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetString.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetString.java @@ -5,15 +5,30 @@ import java.io.IOException; import java.util.Enumeration; import java.util.Vector; +/** + * ASN.1 OctetStrings, with indefinite length rules, and <i>constructed form</i> support. + * <p> + * The Basic Encoding Rules (BER) format allows encoding using so called "<i>constructed form</i>", + * which DER and CER formats forbid allowing only "primitive form". + * </p><p> + * This class <b>always</b> produces the constructed form with underlying segments + * in an indefinite length array. If the input wasn't the same, then this output + * is not faithful reproduction. + * </p> + * <p> + * See {@link ASN1OctetString} for X.690 encoding rules of OCTET-STRING objects. + * </p> + */ public class BEROctetString extends ASN1OctetString { - private static final int MAX_LENGTH = 1000; + private static final int DEFAULT_LENGTH = 1000; - private ASN1OctetString[] octs; + private final int chunkSize; + private final ASN1OctetString[] octs; /** - * convert a vector of octet strings into a single byte string + * Convert a vector of octet strings into a single byte string */ static private byte[] toBytes( ASN1OctetString[] octs) @@ -42,29 +57,73 @@ public class BEROctetString } /** + * Create an OCTET-STRING object from a byte[] * @param string the octets making up the octet string. */ public BEROctetString( byte[] string) { - super(string); + this(string, DEFAULT_LENGTH); } + /** + * Multiple {@link ASN1OctetString} data blocks are input, + * the result is <i>constructed form</i>. + * + * @param octs an array of OCTET STRING to construct the BER OCTET STRING from. + */ public BEROctetString( ASN1OctetString[] octs) { - super(toBytes(octs)); + this(octs, DEFAULT_LENGTH); + } + + /** + * Create an OCTET-STRING object from a byte[] + * @param string the octets making up the octet string. + * @param chunkSize the number of octets stored in each DER encoded component OCTET STRING. + */ + public BEROctetString( + byte[] string, + int chunkSize) + { + this(string, null, chunkSize); + } + /** + * Multiple {@link ASN1OctetString} data blocks are input, + * the result is <i>constructed form</i>. + * + * @param octs an array of OCTET STRING to construct the BER OCTET STRING from. + * @param chunkSize the number of octets stored in each DER encoded component OCTET STRING. + */ + public BEROctetString( + ASN1OctetString[] octs, + int chunkSize) + { + this(toBytes(octs), octs, chunkSize); + } + + private BEROctetString(byte[] string, ASN1OctetString[] octs, int chunkSize) + { + super(string); this.octs = octs; + this.chunkSize = chunkSize; } + /** + * Return a concatenated byte array of all the octets making up the constructed OCTET STRING + * @return the full OCTET STRING. + */ public byte[] getOctets() { return string; } /** - * return the DER octets that make up this string. + * Return the OCTET STRINGs that make up this string. + * + * @return an Enumeration of the component OCTET STRINGs. */ public Enumeration getObjects() { @@ -92,17 +151,17 @@ public class BEROctetString private Vector generateOcts() { Vector vec = new Vector(); - for (int i = 0; i < string.length; i += MAX_LENGTH) + for (int i = 0; i < string.length; i += chunkSize) { int end; - if (i + MAX_LENGTH > string.length) + if (i + chunkSize > string.length) { end = string.length; } else { - end = i + MAX_LENGTH; + end = i + chunkSize; } byte[] nStr = new byte[end - i]; diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java index f6459b2e..22a37ed4 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java @@ -4,7 +4,8 @@ import java.io.IOException; import java.io.OutputStream; /** - * A class which writes indefinite and definite length objects, + * A class which writes indefinite and definite length objects. Objects which specify DER will be encoded accordingly, but DL or BER + * objects will be encoded as defined. */ public class BEROutputStream extends DEROutputStream diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java index d4bfa061..3ecb1461 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java @@ -4,7 +4,12 @@ import java.io.IOException; import java.util.Enumeration; /** - * Carrier class for an indefinite-length SEQUENCE. + * Indefinite length SEQUENCE of objects. + * <p> + * Length field has value 0x80, and the sequence ends with two bytes of: 0x00, 0x00. + * </p><p> + * For X.690 syntax rules, see {@link ASN1Sequence}. + * </p> */ public class BERSequence extends ASN1Sequence diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java index 63a276bb..29ae7fd7 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java @@ -4,7 +4,18 @@ import java.io.IOException; import java.util.Enumeration; /** - * Carrier class for an indefinite-length SET. + * Indefinite length <code>SET</code> and <code>SET OF</code> constructs. + * <p> + * Note: This does not know which syntax the set is! + * </p><p> + * Length field has value 0x80, and the set ends with two bytes of: 0x00, 0x00. + * </p><p> + * For X.690 syntax rules, see {@link ASN1Set}. + * </p><p> + * In brief: Constructing this form does not sort the supplied elements, + * nor does the sorting happen before serialization. This is different + * from the way {@link DERSet} does things. + * </p> */ public class BERSet extends ASN1Set diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java index 98ab0d68..39b517e6 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java @@ -9,28 +9,28 @@ public interface BERTags public static final int NULL = 0x05; public static final int OBJECT_IDENTIFIER = 0x06; public static final int EXTERNAL = 0x08; - public static final int ENUMERATED = 0x0a; - public static final int SEQUENCE = 0x10; + public static final int ENUMERATED = 0x0a; // decimal 10 + public static final int SEQUENCE = 0x10; // decimal 16 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 = 0x11; // decimal 17 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; - public static final int PRINTABLE_STRING = 0x13; - public static final int T61_STRING = 0x14; - public static final int VIDEOTEX_STRING = 0x15; - public static final int IA5_STRING = 0x16; - public static final int UTC_TIME = 0x17; - public static final int GENERALIZED_TIME = 0x18; - public static final int GRAPHIC_STRING = 0x19; - public static final int VISIBLE_STRING = 0x1a; - public static final int GENERAL_STRING = 0x1b; - public static final int UNIVERSAL_STRING = 0x1c; - public static final int BMP_STRING = 0x1e; - public static final int UTF8_STRING = 0x0c; + public static final int NUMERIC_STRING = 0x12; // decimal 18 + public static final int PRINTABLE_STRING = 0x13; // decimal 19 + public static final int T61_STRING = 0x14; // decimal 20 + public static final int VIDEOTEX_STRING = 0x15; // decimal 21 + public static final int IA5_STRING = 0x16; // decimal 22 + public static final int UTC_TIME = 0x17; // decimal 23 + public static final int GENERALIZED_TIME = 0x18; // decimal 24 + public static final int GRAPHIC_STRING = 0x19; // decimal 25 + public static final int VISIBLE_STRING = 0x1a; // decimal 26 + public static final int GENERAL_STRING = 0x1b; // decimal 27 + public static final int UNIVERSAL_STRING = 0x1c; // decimal 28 + public static final int BMP_STRING = 0x1e; // decimal 30 + public static final int UTF8_STRING = 0x0c; // decimal 12 - public static final int CONSTRUCTED = 0x20; - public static final int APPLICATION = 0x40; - public static final int TAGGED = 0x80; + public static final int CONSTRUCTED = 0x20; // decimal 32 + public static final int APPLICATION = 0x40; // decimal 64 + public static final int TAGGED = 0x80; // decimal 128 } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java index e689985c..c64802c9 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java @@ -5,7 +5,12 @@ import java.io.IOException; import org.bouncycastle.util.Arrays; /** - * Carrier class for DER encoding BMPString object. + * DER BMPString object encodes BMP (<i>Basic Multilingual Plane</i>) subset + * (aka UCS-2) of UNICODE (ISO 10646) characters in codepoints 0 to 65535. + * <p> + * At ISO-10646:2011 the term "BMP" has been withdrawn, and replaced by + * term "UCS-2". + * </p> */ public class DERBMPString extends ASN1Primitive @@ -14,7 +19,7 @@ public class DERBMPString private final char[] string; /** - * return a BMP String from the given object. + * Return a BMP String from the given object. * * @param obj the object we want converted. * @exception IllegalArgumentException if the object cannot be converted. @@ -44,7 +49,7 @@ public class DERBMPString } /** - * return a BMP String from a tagged object. + * Return a BMP String from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly @@ -70,7 +75,7 @@ public class DERBMPString } /** - * basic constructor - byte encoded string. + * Basic constructor - byte encoded string. * @param string the encoded BMP STRING to wrap. */ DERBMPString( @@ -92,7 +97,7 @@ public class DERBMPString } /** - * basic constructor + * Basic constructor * @param string a String to wrap as a BMP STRING. */ public DERBMPString( diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java index c789d7cd..8efcaf7a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java @@ -3,7 +3,7 @@ package org.bouncycastle.asn1; import java.io.IOException; /** - * A BIT STRING with DER encoding. + * A BIT STRING with DER encoding - the first byte contains the count of padding bits included in the byte array's last byte. */ public class DERBitString extends ASN1BitString @@ -124,7 +124,7 @@ public class DERBitString } void encode( - ASN1OutputStream out) + ASN1OutputStream out) throws IOException { byte[] string = derForm(data, padBits); diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java index f6c45d31..480a3942 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java @@ -7,61 +7,25 @@ import java.io.IOException; * Class representing the DER-type External */ public class DERExternal - extends ASN1Primitive + extends ASN1External { - private ASN1ObjectIdentifier directReference; - private ASN1Integer indirectReference; - private ASN1Primitive dataValueDescriptor; - private int encoding; - private ASN1Primitive externalContent; - + /** + * Construct a DER EXTERNAL object, the input encoding vector must have exactly two elements on it. + * <p> + * Acceptable input formats are: + * <ul> + * <li> {@link ASN1ObjectIdentifier} + data {@link DERTaggedObject} (direct reference form)</li> + * <li> {@link ASN1Integer} + data {@link DERTaggedObject} (indirect reference form)</li> + * <li> Anything but {@link DERTaggedObject} + data {@link DERTaggedObject} (data value form)</li> + * </ul> + * + * @throws IllegalArgumentException if input size is wrong, or + */ public DERExternal(ASN1EncodableVector vector) { - int offset = 0; - - ASN1Primitive enc = getObjFromVector(vector, offset); - if (enc instanceof ASN1ObjectIdentifier) - { - directReference = (ASN1ObjectIdentifier)enc; - offset++; - enc = getObjFromVector(vector, offset); - } - if (enc instanceof ASN1Integer) - { - indirectReference = (ASN1Integer) enc; - offset++; - enc = getObjFromVector(vector, offset); - } - if (!(enc instanceof ASN1TaggedObject)) - { - dataValueDescriptor = (ASN1Primitive) enc; - offset++; - enc = getObjFromVector(vector, offset); - } - - if (vector.size() != offset + 1) - { - throw new IllegalArgumentException("input vector too large"); - } - - if (!(enc instanceof ASN1TaggedObject)) - { - throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External"); - } - ASN1TaggedObject obj = (ASN1TaggedObject)enc; - setEncoding(obj.getTagNo()); - externalContent = obj.getObject(); + super(vector); } - private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index) - { - if (v.size() <= index) - { - throw new IllegalArgumentException("too few objects in input vector"); - } - - return v.get(index).toASN1Primitive(); - } /** * Creates a new instance of DERExternal * See X.690 for more informations about the meaning of these parameters @@ -86,38 +50,7 @@ public class DERExternal */ public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData) { - setDirectReference(directReference); - setIndirectReference(indirectReference); - setDataValueDescriptor(dataValueDescriptor); - setEncoding(encoding); - setExternalContent(externalData.toASN1Primitive()); - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - public int hashCode() - { - int ret = 0; - if (directReference != null) - { - ret = directReference.hashCode(); - } - if (indirectReference != null) - { - ret ^= indirectReference.hashCode(); - } - if (dataValueDescriptor != null) - { - ret ^= dataValueDescriptor.hashCode(); - } - ret ^= externalContent.hashCode(); - return ret; - } - - boolean isConstructed() - { - return true; + super(directReference, indirectReference, dataValueDescriptor, encoding, externalData); } int encodedLength() @@ -149,146 +82,4 @@ public class DERExternal baos.write(obj.getEncoded(ASN1Encoding.DER)); out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray()); } - - /* (non-Javadoc) - * @see org.bouncycastle.asn1.ASN1Primitive#asn1Equals(org.bouncycastle.asn1.ASN1Primitive) - */ - boolean asn1Equals(ASN1Primitive o) - { - if (!(o instanceof DERExternal)) - { - return false; - } - if (this == o) - { - return true; - } - DERExternal other = (DERExternal)o; - if (directReference != null) - { - if (other.directReference == null || !other.directReference.equals(directReference)) - { - return false; - } - } - if (indirectReference != null) - { - if (other.indirectReference == null || !other.indirectReference.equals(indirectReference)) - { - return false; - } - } - if (dataValueDescriptor != null) - { - if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor)) - { - return false; - } - } - return externalContent.equals(other.externalContent); - } - - /** - * Returns the data value descriptor - * @return The descriptor - */ - public ASN1Primitive getDataValueDescriptor() - { - return dataValueDescriptor; - } - - /** - * Returns the direct reference of the external element - * @return The reference - */ - public ASN1ObjectIdentifier getDirectReference() - { - return directReference; - } - - /** - * Returns the encoding of the content. Valid values are - * <ul> - * <li><code>0</code> single-ASN1-type</li> - * <li><code>1</code> OCTET STRING</li> - * <li><code>2</code> BIT STRING</li> - * </ul> - * @return The encoding - */ - public int getEncoding() - { - return encoding; - } - - /** - * Returns the content of this element - * @return The content - */ - public ASN1Primitive getExternalContent() - { - return externalContent; - } - - /** - * Returns the indirect reference of this element - * @return The reference - */ - public ASN1Integer getIndirectReference() - { - return indirectReference; - } - - /** - * Sets the data value descriptor - * @param dataValueDescriptor The descriptor - */ - private void setDataValueDescriptor(ASN1Primitive dataValueDescriptor) - { - this.dataValueDescriptor = dataValueDescriptor; - } - - /** - * Sets the direct reference of the external element - * @param directReferemce The reference - */ - private void setDirectReference(ASN1ObjectIdentifier directReferemce) - { - this.directReference = directReferemce; - } - - /** - * Sets the encoding of the content. Valid values are - * <ul> - * <li><code>0</code> single-ASN1-type</li> - * <li><code>1</code> OCTET STRING</li> - * <li><code>2</code> BIT STRING</li> - * </ul> - * @param encoding The encoding - */ - private void setEncoding(int encoding) - { - if (encoding < 0 || encoding > 2) - { - throw new IllegalArgumentException("invalid encoding value: " + encoding); - } - this.encoding = encoding; - } - - /** - * Sets the content of this element - * @param externalContent The content - */ - private void setExternalContent(ASN1Primitive externalContent) - { - this.externalContent = externalContent; - } - - /** - * Sets the indirect reference of this element - * @param indirectReference The reference - */ - private void setIndirectReference(ASN1Integer indirectReference) - { - this.indirectReference = indirectReference; - } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java index 98d02e73..afdf510c 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java @@ -37,7 +37,7 @@ public class DERExternalParser { try { - return new DERExternal(_parser.readVector()); + return new DLExternal(_parser.readVector()); } catch (IllegalArgumentException e) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java index 9addf700..52a580fa 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java @@ -6,7 +6,11 @@ import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; /** - * Carrier class for a DER encoding GeneralString + * ASN.1 GENERAL-STRING data type. + * <p> + * This is an 8-bit encoded ISO 646 (ASCII) character set + * with optional escapes to other character sets. + * </p> */ public class DERGeneralString extends ASN1Primitive @@ -15,7 +19,7 @@ public class DERGeneralString private final byte[] string; /** - * return a GeneralString from the given object. + * Return a GeneralString from the given object. * * @param obj the object we want converted. * @exception IllegalArgumentException if the object cannot be converted. @@ -46,7 +50,7 @@ public class DERGeneralString } /** - * return a GeneralString from a tagged object. + * Return a GeneralString from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java index adee74ec..1270e85c 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java @@ -1,17 +1,33 @@ package org.bouncycastle.asn1; +import java.io.IOException; import java.util.Date; +import org.bouncycastle.util.Strings; + /** * DER Generalized time object. + * <h3>11: Restrictions on BER employed by both CER and DER</h3> + * <h4>11.7 GeneralizedTime </h4> + * <p> + * <b>11.7.1</b> The encoding shall terminate with a "Z", + * as described in the ITU-T Rec. X.680 | ISO/IEC 8824-1 clause on + * GeneralizedTime. + * </p><p> + * <b>11.7.2</b> The seconds element shall always be present. + * </p> + * <p> + * <b>11.7.3</b> The fractional-seconds elements, if present, + * shall omit all trailing zeros; if the elements correspond to 0, + * they shall be wholly omitted, and the decimal point element also + * shall be omitted. */ public class DERGeneralizedTime extends ASN1GeneralizedTime { - - DERGeneralizedTime(byte[] bytes) + public DERGeneralizedTime(byte[] time) { - super(bytes); + super(time); } public DERGeneralizedTime(Date time) @@ -24,5 +40,77 @@ public class DERGeneralizedTime super(time); } - // TODO: create proper DER encoding. + private byte[] getDERTime() + { + if (time[time.length - 1] == 'Z') + { + if (!hasMinutes()) + { + byte[] derTime = new byte[time.length + 4]; + + System.arraycopy(time, 0, derTime, 0, time.length - 1); + System.arraycopy(Strings.toByteArray("0000Z"), 0, derTime, time.length - 1, 5); + + return derTime; + } + else if (!hasSeconds()) + { + byte[] derTime = new byte[time.length + 2]; + + System.arraycopy(time, 0, derTime, 0, time.length - 1); + System.arraycopy(Strings.toByteArray("00Z"), 0, derTime, time.length - 1, 3); + + return derTime; + } + else if (hasFractionalSeconds()) + { + int ind = time.length - 2; + while (ind > 0 && time[ind] == '0') + { + ind--; + } + + if (time[ind] == '.') + { + byte[] derTime = new byte[ind + 1]; + + System.arraycopy(time, 0, derTime, 0, ind); + derTime[ind] = (byte)'Z'; + + return derTime; + } + else + { + byte[] derTime = new byte[ind + 2]; + + System.arraycopy(time, 0, derTime, 0, ind + 1); + derTime[ind + 1] = (byte)'Z'; + + return derTime; + } + } + else + { + return time; + } + } + else + { + return time; // TODO: is there a better way? + } + } + + int encodedLength() + { + int length = getDERTime().length; + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.GENERALIZED_TIME, getDERTime()); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java index 0336e6b7..d2f7a8d1 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java @@ -6,7 +6,10 @@ import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; /** - * DER IA5String object - this is an ascii string. + * DER IA5String object - this is a ISO 646 (ASCII) string encoding code points 0 to 127. + * <p> + * Explicit character set escape sequences are not allowed. + * </p> */ public class DERIA5String extends ASN1Primitive @@ -15,7 +18,7 @@ public class DERIA5String private final byte[] string; /** - * return a IA5 string from the passed in object + * Return an IA5 string from the passed in object * * @param obj a DERIA5String or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. @@ -45,7 +48,7 @@ public class DERIA5String } /** - * return an IA5 String from a tagged object. + * Return an IA5 String from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly @@ -71,7 +74,7 @@ public class DERIA5String } /** - * basic constructor - with bytes. + * Basic constructor - with bytes. * @param string the byte encoding of the characters making up the string. */ DERIA5String( @@ -81,7 +84,7 @@ public class DERIA5String } /** - * basic constructor - without validation. + * Basic constructor - without validation. * @param string the base string to use.. */ public DERIA5String( diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERNull.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERNull.java index 3a86b1d6..1981fef7 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERNull.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERNull.java @@ -3,7 +3,9 @@ package org.bouncycastle.asn1; import java.io.IOException; /** - * A NULL object. + * An ASN.1 DER NULL object. + * <p> + * Preferably use the constant: DERNull.INSTANCE. */ public class DERNull extends ASN1Null diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java index ed287e56..1f82be17 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java @@ -7,6 +7,13 @@ import org.bouncycastle.util.Strings; /** * DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }. + * ASN.1 NUMERIC-STRING object. + * <p> + * This is an ASCII string of characters {0,1,2,3,4,5,6,7,8,9} + space. + * <p> + * See X.680 section 37.2. + * <p> + * Explicit character set escape sequences are not allowed. */ public class DERNumericString extends ASN1Primitive @@ -15,7 +22,7 @@ public class DERNumericString private final byte[] string; /** - * return a Numeric string from the passed in object + * Return a Numeric string from the passed in object * * @param obj a DERNumericString or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. @@ -45,7 +52,7 @@ public class DERNumericString } /** - * return an Numeric String from a tagged object. + * Return an Numeric String from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly @@ -71,7 +78,7 @@ public class DERNumericString } /** - * basic constructor - with bytes. + * Basic constructor - with bytes. */ DERNumericString( byte[] string) @@ -80,7 +87,7 @@ public class DERNumericString } /** - * basic constructor - without validation.. + * Basic constructor - without validation.. */ public DERNumericString( String string) diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java index 58be862d..1c9c1598 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java @@ -4,7 +4,7 @@ import java.io.IOException; import java.io.InputStream; /** - * Parse for DER encoded OCTET STRINGS + * Parser for DER encoded OCTET STRINGS */ public class DEROctetStringParser implements ASN1OctetStringParser diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java index 805ad30e..a234eea4 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java @@ -7,6 +7,29 @@ import org.bouncycastle.util.Strings; /** * DER PrintableString object. + * <p> + * X.680 section 37.4 defines PrintableString character codes as ASCII subset of following characters: + * </p> + * <ul> + * <li>Latin capital letters: 'A' .. 'Z'</li> + * <li>Latin small letters: 'a' .. 'z'</li> + * <li>Digits: '0'..'9'</li> + * <li>Space</li> + * <li>Apostrophe: '\''</li> + * <li>Left parenthesis: '('</li> + * <li>Right parenthesis: ')'</li> + * <li>Plus sign: '+'</li> + * <li>Comma: ','</li> + * <li>Hyphen-minus: '-'</li> + * <li>Full stop: '.'</li> + * <li>Solidus: '/'</li> + * <li>Colon: ':'</li> + * <li>Equals sign: '='</li> + * <li>Question mark: '?'</li> + * </ul> + * <p> + * Explicit character set escape sequences are not allowed. + * </p> */ public class DERPrintableString extends ASN1Primitive @@ -15,7 +38,7 @@ public class DERPrintableString private final byte[] string; /** - * return a printable string from the passed in object. + * Return a printable string from the passed in object. * * @param obj a DERPrintableString or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. @@ -45,7 +68,7 @@ public class DERPrintableString } /** - * return a Printable String from a tagged object. + * Return a Printable String from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly @@ -71,7 +94,7 @@ public class DERPrintableString } /** - * basic constructor - byte encoded string. + * Basic constructor - byte encoded string. */ DERPrintableString( byte[] string) @@ -80,7 +103,7 @@ public class DERPrintableString } /** - * basic constructor - this does not validate the string + * Basic constructor - this does not validate the string */ public DERPrintableString( String string) diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java index b631064d..8efbbab5 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java @@ -3,20 +3,26 @@ package org.bouncycastle.asn1; import java.io.IOException; import java.util.Enumeration; +/** + * Definite length SEQUENCE, encoding tells explicit number of bytes + * that the content of this sequence occupies. + * <p> + * For X.690 syntax rules, see {@link ASN1Sequence}. + */ public class DERSequence extends ASN1Sequence { private int bodyLength = -1; /** - * create an empty sequence + * Create an empty sequence */ public DERSequence() { } /** - * create a sequence containing one object + * Create a sequence containing one object * @param obj the object to go in the sequence. */ public DERSequence( @@ -26,7 +32,7 @@ public class DERSequence } /** - * create a sequence containing a vector of objects. + * Create a sequence containing a vector of objects. * @param v the vector of objects to make up the sequence. */ public DERSequence( @@ -36,7 +42,7 @@ public class DERSequence } /** - * create a sequence containing an array of objects. + * Create a sequence containing an array of objects. * @param array the array of objects to make up the sequence. */ public DERSequence( diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java index 1a72a0b1..99d10d8e 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java @@ -5,6 +5,13 @@ import java.util.Enumeration; /** * A DER encoded SET object + * <p> + * For X.690 syntax rules, see {@link ASN1Set}. + * </p><p> + * For short: Constructing this form does sort the supplied elements, + * and the sorting happens also before serialization (if necesssary). + * This is different from the way {@link BERSet},{@link DLSet} does things. + * </p> */ public class DERSet extends ASN1Set diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java index c5c29137..289bfc8c 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java @@ -16,7 +16,7 @@ public class DERT61String private byte[] string; /** - * return a T61 string from the passed in object. + * Return a T61 string from the passed in object. * * @param obj a DERT61String or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. @@ -46,7 +46,7 @@ public class DERT61String } /** - * return an T61 String from a tagged object. + * Return an T61 String from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly @@ -72,7 +72,7 @@ public class DERT61String } /** - * basic constructor - string encoded as a sequence of bytes. + * Basic constructor - string encoded as a sequence of bytes. * * @param string the byte encoding of the string to be wrapped. */ @@ -83,7 +83,7 @@ public class DERT61String } /** - * basic constructor - with string 8 bit assumed. + * Basic constructor - with string 8 bit assumed. * * @param string the string to be wrapped. */ diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java index 6b70faab..487f86d9 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java @@ -6,7 +6,8 @@ import java.io.IOException; import org.bouncycastle.util.Arrays; /** - * DER UniversalString object. + * DER UniversalString object - encodes UNICODE (ISO 10646) characters using 32-bit format. In Java we + * have no way of representing this directly so we rely on byte arrays to carry these. */ public class DERUniversalString extends ASN1Primitive @@ -16,7 +17,7 @@ public class DERUniversalString private final byte[] string; /** - * return a Universal String from the passed in object. + * Return a Universal String from the passed in object. * * @param obj a DERUniversalString or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. @@ -46,7 +47,7 @@ public class DERUniversalString } /** - * return a Universal String from a tagged object. + * Return a Universal String from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly @@ -72,7 +73,7 @@ public class DERUniversalString } /** - * basic constructor - byte encoded string. + * Basic constructor - byte encoded string. * * @param string the byte encoding of the string to be carried in the UniversalString object, */ @@ -94,7 +95,7 @@ public class DERUniversalString } catch (IOException e) { - throw new ASN1ParsingException("internal error encoding BitString"); + throw new ASN1ParsingException("internal error encoding UniversalString"); } byte[] string = bOut.toByteArray(); diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLApplicationSpecific.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLApplicationSpecific.java new file mode 100644 index 00000000..8369492a --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLApplicationSpecific.java @@ -0,0 +1,124 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * A DER encoding version of an application specific object. + */ +public class DLApplicationSpecific + extends ASN1ApplicationSpecific +{ + DLApplicationSpecific( + boolean isConstructed, + int tag, + byte[] octets) + { + super(isConstructed, tag, octets); + } + + /** + * Create an application specific object from the passed in data. This will assume + * the data does not represent a constructed object. + * + * @param tag the tag number for this object. + * @param octets the encoding of the object's body. + */ + public DLApplicationSpecific( + int tag, + byte[] octets) + { + this(false, tag, octets); + } + + /** + * Create an application specific object with a tagging of explicit/constructed. + * + * @param tag the tag number for this object. + * @param object the object to be contained. + */ + public DLApplicationSpecific( + int tag, + ASN1Encodable object) + throws IOException + { + this(true, tag, object); + } + + /** + * Create an application specific object with the tagging style given by the value of constructed. + * + * @param constructed true if the object is constructed. + * @param tag the tag number for this object. + * @param object the object to be contained. + */ + public DLApplicationSpecific( + boolean constructed, + int tag, + ASN1Encodable object) + throws IOException + { + super(constructed || object.toASN1Primitive().isConstructed(), tag, getEncoding(constructed, object)); + } + + private static byte[] getEncoding(boolean explicit, ASN1Encodable object) + throws IOException + { + byte[] data = object.toASN1Primitive().getEncoded(ASN1Encoding.DL); + + if (explicit) + { + return data; + } + else + { + int lenBytes = getLengthOfHeader(data); + byte[] tmp = new byte[data.length - lenBytes]; + System.arraycopy(data, lenBytes, tmp, 0, tmp.length); + return tmp; + } + } + + /** + * Create an application specific object which is marked as constructed + * + * @param tagNo the tag number for this object. + * @param vec the objects making up the application specific object. + */ + public DLApplicationSpecific(int tagNo, ASN1EncodableVector vec) + { + super(true, tagNo, getEncodedVector(vec)); + } + + private static byte[] getEncodedVector(ASN1EncodableVector vec) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + for (int i = 0; i != vec.size(); i++) + { + try + { + bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DL)); + } + catch (IOException e) + { + throw new ASN1ParsingException("malformed object: " + e, e); + } + } + return bOut.toByteArray(); + } + + /* (non-Javadoc) + * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream) + */ + void encode(ASN1OutputStream out) throws IOException + { + int classBits = BERTags.APPLICATION; + if (isConstructed) + { + classBits |= BERTags.CONSTRUCTED; + } + + out.writeEncoded(classBits, tag, octets); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java index f6cb49bd..a5d9cbb6 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java @@ -124,7 +124,7 @@ public class DLBitString } void encode( - ASN1OutputStream out) + ASN1OutputStream out) throws IOException { byte[] string = data; diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLExternal.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLExternal.java new file mode 100644 index 00000000..e3df2506 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLExternal.java @@ -0,0 +1,85 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Class representing the Definite-Length-type External + */ +public class DLExternal + extends ASN1External +{ + /** + * Construct a Definite-Length EXTERNAL object, the input encoding vector must have exactly two elements on it. + * <p> + * Acceptable input formats are: + * <ul> + * <li> {@link ASN1ObjectIdentifier} + data {@link DERTaggedObject} (direct reference form)</li> + * <li> {@link ASN1Integer} + data {@link DERTaggedObject} (indirect reference form)</li> + * <li> Anything but {@link DERTaggedObject} + data {@link DERTaggedObject} (data value form)</li> + * </ul> + * + * @throws IllegalArgumentException if input size is wrong, or + */ + public DLExternal(ASN1EncodableVector vector) + { + super(vector); + } + + /** + * Creates a new instance of DERExternal + * See X.690 for more informations about the meaning of these parameters + * @param directReference The direct reference or <code>null</code> if not set. + * @param indirectReference The indirect reference or <code>null</code> if not set. + * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set. + * @param externalData The external data in its encoded form. + */ + public DLExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData) + { + this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive()); + } + + /** + * Creates a new instance of Definite-Length External. + * See X.690 for more informations about the meaning of these parameters + * @param directReference The direct reference or <code>null</code> if not set. + * @param indirectReference The indirect reference or <code>null</code> if not set. + * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set. + * @param encoding The encoding to be used for the external data + * @param externalData The external data + */ + public DLExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData) + { + super(directReference, indirectReference, dataValueDescriptor, encoding, externalData); + } + + int encodedLength() + throws IOException + { + return this.getEncoded().length; + } + + /* (non-Javadoc) + * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream) + */ + void encode(ASN1OutputStream out) + throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + if (directReference != null) + { + baos.write(directReference.getEncoded(ASN1Encoding.DL)); + } + if (indirectReference != null) + { + baos.write(indirectReference.getEncoded(ASN1Encoding.DL)); + } + if (dataValueDescriptor != null) + { + baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DL)); + } + DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent); + baos.write(obj.getEncoded(ASN1Encoding.DL)); + out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray()); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DateUtil.java b/bcprov/src/main/java/org/bouncycastle/asn1/DateUtil.java new file mode 100644 index 00000000..83d8bb2d --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DateUtil.java @@ -0,0 +1,80 @@ +package org.bouncycastle.asn1; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +class DateUtil +{ + private static Long ZERO = longValueOf(0); + + private static final Map localeCache = new HashMap(); + + static Locale EN_Locale = forEN(); + + private static Locale forEN() + { + if ("en".equalsIgnoreCase(Locale.getDefault().getLanguage())) + { + return Locale.getDefault(); + } + + Locale[] locales = Locale.getAvailableLocales(); + for (int i = 0; i != locales.length; i++) + { + if ("en".equalsIgnoreCase(locales[i].getLanguage())) + { + return locales[i]; + } + } + + return Locale.getDefault(); + } + + static Date epochAdjust(Date date) + throws ParseException + { + Locale locale = Locale.getDefault(); + if (locale == null) + { + return date; + } + + synchronized (localeCache) + { + Long adj = (Long)localeCache.get(locale); + + if (adj == null) + { + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); + long v = dateF.parse("19700101000000GMT+00:00").getTime(); + + if (v == 0) + { + adj = ZERO; + } + else + { + adj = longValueOf(v); + } + + localeCache.put(locale, adj); + } + + if (adj != ZERO) + { + return new Date(date.getTime() - adj.longValue()); + } + + return date; + } + } + + private static Long longValueOf(long v) + { + return Long.valueOf(v); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java index 37851748..d7b51ded 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java @@ -6,6 +6,9 @@ import java.io.InputStream; import org.bouncycastle.util.io.Streams; +/** + * Parse data stream of expected ASN.1 data expecting definite-length encoding.. + */ class DefiniteLengthInputStream extends LimitedInputStream { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java index d94b0bd8..ab8470f8 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java @@ -2,6 +2,9 @@ package org.bouncycastle.asn1; import java.io.InputStream; +/** + * Internal use stream that allows reading of a limited number of bytes from a wrapped stream. + */ abstract class LimitedInputStream extends InputStream { 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 f43f9fb7..dae0dacc 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java @@ -83,6 +83,77 @@ public interface BCObjectIdentifiers public static final ASN1ObjectIdentifier sphincs256_with_SHA3_512 = sphincs256.branch("3"); /** + * XMSS + */ + public static final ASN1ObjectIdentifier xmss = bc_sig.branch("2"); + public static final ASN1ObjectIdentifier xmss_SHA256ph = xmss.branch("1"); + public static final ASN1ObjectIdentifier xmss_SHA512ph = xmss.branch("2"); + public static final ASN1ObjectIdentifier xmss_SHAKE128ph = xmss.branch("3"); + public static final ASN1ObjectIdentifier xmss_SHAKE256ph = xmss.branch("4"); + public static final ASN1ObjectIdentifier xmss_SHA256 = xmss.branch("5"); + public static final ASN1ObjectIdentifier xmss_SHA512 = xmss.branch("6"); + public static final ASN1ObjectIdentifier xmss_SHAKE128 = xmss.branch("7"); + public static final ASN1ObjectIdentifier xmss_SHAKE256 = xmss.branch("8"); + + /** + * XMSS^MT + */ + public static final ASN1ObjectIdentifier xmss_mt = bc_sig.branch("3"); + public static final ASN1ObjectIdentifier xmss_mt_SHA256ph = xmss_mt.branch("1"); + public static final ASN1ObjectIdentifier xmss_mt_SHA512ph = xmss_mt.branch("2"); + public static final ASN1ObjectIdentifier xmss_mt_SHAKE128ph = xmss_mt.branch("3"); + public static final ASN1ObjectIdentifier xmss_mt_SHAKE256ph = xmss_mt.branch("4"); + public static final ASN1ObjectIdentifier xmss_mt_SHA256 = xmss_mt.branch("5"); + public static final ASN1ObjectIdentifier xmss_mt_SHA512 = xmss_mt.branch("6"); + public static final ASN1ObjectIdentifier xmss_mt_SHAKE128 = xmss_mt.branch("7"); + public static final ASN1ObjectIdentifier xmss_mt_SHAKE256 = xmss_mt.branch("8"); + + // old OIDs. + /** + * @deprecated use xmss_SHA256ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHA256 = xmss_SHA256ph; + /** + * @deprecated use xmss_SHA512ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHA512 = xmss_SHA512ph; + /** + * @deprecated use xmss_SHAKE128ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHAKE128 = xmss_SHAKE128ph; + /** + * @deprecated use xmss_SHAKE256ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHAKE256 = xmss_SHAKE256ph; + + /** + * @deprecated use xmss_mt_SHA256ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHA256 = xmss_mt_SHA256ph; + /** + * @deprecated use xmss_mt_SHA512ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHA512 = xmss_mt_SHA512ph; + /** + * @deprecated use xmss_mt_SHAKE128ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE128 = xmss_mt_SHAKE128; + /** + * @deprecated use xmss_mt_SHAKE256ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE256 = xmss_mt_SHAKE256; + + /** + * qTESLA + */ + public static final ASN1ObjectIdentifier qTESLA = bc_sig.branch("4"); + public static final ASN1ObjectIdentifier qTESLA_I = qTESLA.branch("1"); + public static final ASN1ObjectIdentifier qTESLA_III_size = qTESLA.branch("2"); + public static final ASN1ObjectIdentifier qTESLA_III_speed = qTESLA.branch("3"); + public static final ASN1ObjectIdentifier qTESLA_p_I = qTESLA.branch("4"); + public static final ASN1ObjectIdentifier qTESLA_p_III = qTESLA.branch("5"); + + /** * key_exchange(3) algorithms * public static final ASN1ObjectIdentifier bc_exch = bc.branch("3"); 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 e21c8a7b..4ffe5ea5 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java @@ -4,6 +4,7 @@ import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DLSet; /** @@ -63,6 +64,13 @@ public class Attributes return null; } + public static Attributes getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Set.getInstance(obj, explicit)); + } + public Attribute[] getAttributes() { Attribute[] rv = new Attribute[attributes.size()]; diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java index 71c85fbe..d452ef8a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java @@ -3,6 +3,7 @@ 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. * and <a href="http://tools.ietf.org/html/rfc6211">RFC 6211</a> Algorithm Identifier Protection Attribute. @@ -20,16 +21,16 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; public interface CMSAttributes { /** PKCS#9: 1.2.840.113549.1.9.3 */ - public static final ASN1ObjectIdentifier contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType; + ASN1ObjectIdentifier contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType; /** PKCS#9: 1.2.840.113549.1.9.4 */ - public static final ASN1ObjectIdentifier messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest; + ASN1ObjectIdentifier messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest; /** PKCS#9: 1.2.840.113549.1.9.5 */ - public static final ASN1ObjectIdentifier signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime; + ASN1ObjectIdentifier signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime; /** PKCS#9: 1.2.840.113549.1.9.6 */ - public static final ASN1ObjectIdentifier counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature; + ASN1ObjectIdentifier counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature; /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */ - public static final ASN1ObjectIdentifier contentHint = PKCSObjectIdentifiers.id_aa_contentHint; + ASN1ObjectIdentifier contentHint = PKCSObjectIdentifiers.id_aa_contentHint; - public static final ASN1ObjectIdentifier cmsAlgorithmProtect = PKCSObjectIdentifiers.id_aa_cmsAlgorithmProtect; + ASN1ObjectIdentifier cmsAlgorithmProtect = PKCSObjectIdentifiers.id_aa_cmsAlgorithmProtect; } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/gm/package.html b/bcprov/src/main/java/org/bouncycastle/asn1/gm/package.html new file mode 100644 index 00000000..54a633d6 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/asn1/gm/package.html @@ -0,0 +1,5 @@ +<html> +<body bgcolor="#ffffff"> +Support classes for Chinese Standard (GM) standard curves and algorithms. +</body> +</html> 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 284751eb..0f0b10d5 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java @@ -8,64 +8,98 @@ public interface MiscObjectIdentifiers // Netscape // iso/itu(2) joint-assign(16) us(840) uscompany(1) netscape(113730) cert-extensions(1) } // - /** Netscape cert extensions OID base: 2.16.840.1.113730.1 */ - static final ASN1ObjectIdentifier netscape = new ASN1ObjectIdentifier("2.16.840.1.113730.1"); - /** Netscape cert CertType OID: 2.16.840.1.113730.1.1 */ - static final ASN1ObjectIdentifier netscapeCertType = netscape.branch("1"); - /** Netscape cert BaseURL OID: 2.16.840.1.113730.1.2 */ - static final ASN1ObjectIdentifier netscapeBaseURL = netscape.branch("2"); - /** Netscape cert RevocationURL OID: 2.16.840.1.113730.1.3 */ - static final ASN1ObjectIdentifier netscapeRevocationURL = netscape.branch("3"); - /** Netscape cert CARevocationURL OID: 2.16.840.1.113730.1.4 */ - static final ASN1ObjectIdentifier netscapeCARevocationURL = netscape.branch("4"); - /** Netscape cert RenewalURL OID: 2.16.840.1.113730.1.7 */ - static final ASN1ObjectIdentifier netscapeRenewalURL = netscape.branch("7"); - /** Netscape cert CApolicyURL OID: 2.16.840.1.113730.1.8 */ - static final ASN1ObjectIdentifier netscapeCApolicyURL = netscape.branch("8"); - /** Netscape cert SSLServerName OID: 2.16.840.1.113730.1.12 */ - static final ASN1ObjectIdentifier netscapeSSLServerName = netscape.branch("12"); - /** Netscape cert CertComment OID: 2.16.840.1.113730.1.13 */ - static final ASN1ObjectIdentifier netscapeCertComment = netscape.branch("13"); - + /** + * Netscape cert extensions OID base: 2.16.840.1.113730.1 + */ + ASN1ObjectIdentifier netscape = new ASN1ObjectIdentifier("2.16.840.1.113730.1"); + /** + * Netscape cert CertType OID: 2.16.840.1.113730.1.1 + */ + ASN1ObjectIdentifier netscapeCertType = netscape.branch("1"); + /** + * Netscape cert BaseURL OID: 2.16.840.1.113730.1.2 + */ + ASN1ObjectIdentifier netscapeBaseURL = netscape.branch("2"); + /** + * Netscape cert RevocationURL OID: 2.16.840.1.113730.1.3 + */ + ASN1ObjectIdentifier netscapeRevocationURL = netscape.branch("3"); + /** + * Netscape cert CARevocationURL OID: 2.16.840.1.113730.1.4 + */ + ASN1ObjectIdentifier netscapeCARevocationURL = netscape.branch("4"); + /** + * Netscape cert RenewalURL OID: 2.16.840.1.113730.1.7 + */ + ASN1ObjectIdentifier netscapeRenewalURL = netscape.branch("7"); + /** + * Netscape cert CApolicyURL OID: 2.16.840.1.113730.1.8 + */ + ASN1ObjectIdentifier netscapeCApolicyURL = netscape.branch("8"); + /** + * Netscape cert SSLServerName OID: 2.16.840.1.113730.1.12 + */ + ASN1ObjectIdentifier netscapeSSLServerName = netscape.branch("12"); + /** + * Netscape cert CertComment OID: 2.16.840.1.113730.1.13 + */ + ASN1ObjectIdentifier netscapeCertComment = netscape.branch("13"); + // // Verisign // iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) } // - /** Verisign OID base: 2.16.840.1.113733.1 */ - static final ASN1ObjectIdentifier verisign = new ASN1ObjectIdentifier("2.16.840.1.113733.1"); + /** + * Verisign OID base: 2.16.840.1.113733.1 + */ + ASN1ObjectIdentifier verisign = new ASN1ObjectIdentifier("2.16.840.1.113733.1"); - /** Verisign CZAG (Country,Zip,Age,Gender) Extension OID: 2.16.840.1.113733.1.6.3 */ - static final ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3"); + /** + * Verisign CZAG (Country,Zip,Age,Gender) Extension OID: 2.16.840.1.113733.1.6.3 + */ + ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3"); - static final ASN1ObjectIdentifier verisignPrivate_6_9 = verisign.branch("6.9"); - static final ASN1ObjectIdentifier verisignOnSiteJurisdictionHash = verisign.branch("6.11"); - static final ASN1ObjectIdentifier verisignBitString_6_13 = verisign.branch("6.13"); + ASN1ObjectIdentifier verisignPrivate_6_9 = verisign.branch("6.9"); + ASN1ObjectIdentifier verisignOnSiteJurisdictionHash = verisign.branch("6.11"); + ASN1ObjectIdentifier verisignBitString_6_13 = verisign.branch("6.13"); - /** Verisign D&B D-U-N-S number Extension OID: 2.16.840.1.113733.1.6.15 */ - static final ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15"); + /** + * Verisign D&B D-U-N-S number Extension OID: 2.16.840.1.113733.1.6.15 + */ + ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15"); - static final ASN1ObjectIdentifier verisignIssStrongCrypto = verisign.branch("8.1"); + ASN1ObjectIdentifier verisignIssStrongCrypto = verisign.branch("8.1"); // // Novell // iso/itu(2) country(16) us(840) organization(1) novell(113719) // - /** Novell OID base: 2.16.840.1.113719 */ - static final ASN1ObjectIdentifier novell = new ASN1ObjectIdentifier("2.16.840.1.113719"); - /** Novell SecurityAttribs OID: 2.16.840.1.113719.1.9.4.1 */ - static final ASN1ObjectIdentifier novellSecurityAttribs = novell.branch("1.9.4.1"); + /** + * Novell OID base: 2.16.840.1.113719 + */ + ASN1ObjectIdentifier novell = new ASN1ObjectIdentifier("2.16.840.1.113719"); + /** + * Novell SecurityAttribs OID: 2.16.840.1.113719.1.9.4.1 + */ + ASN1ObjectIdentifier novellSecurityAttribs = novell.branch("1.9.4.1"); // // Entrust // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7) // - /** NortelNetworks Entrust OID base: 1.2.840.113533.7 */ - static final ASN1ObjectIdentifier entrust = new ASN1ObjectIdentifier("1.2.840.113533.7"); - /** NortelNetworks Entrust VersionExtension OID: 1.2.840.113533.7.65.0 */ - static final ASN1ObjectIdentifier entrustVersionExtension = entrust.branch("65.0"); + /** + * NortelNetworks Entrust OID base: 1.2.840.113533.7 + */ + ASN1ObjectIdentifier entrust = new ASN1ObjectIdentifier("1.2.840.113533.7"); + /** + * NortelNetworks Entrust VersionExtension OID: 1.2.840.113533.7.65.0 + */ + ASN1ObjectIdentifier entrustVersionExtension = entrust.branch("65.0"); - /** cast5CBC OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) nt(113533) nsn(7) algorithms(66) 10} SEE RFC 2984 */ - ASN1ObjectIdentifier cast5CBC = entrust.branch("66.10"); + /** + * cast5CBC OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) nt(113533) nsn(7) algorithms(66) 10} SEE RFC 2984 + */ + ASN1ObjectIdentifier cast5CBC = entrust.branch("66.10"); // // Ascom @@ -92,4 +126,13 @@ public interface MiscObjectIdentifiers ASN1ObjectIdentifier id_blake2b256 = blake2.branch("1.8"); ASN1ObjectIdentifier id_blake2b384 = blake2.branch("1.12"); ASN1ObjectIdentifier id_blake2b512 = blake2.branch("1.16"); + + ASN1ObjectIdentifier id_blake2s128 = blake2.branch("2.4"); + ASN1ObjectIdentifier id_blake2s160 = blake2.branch("2.5"); + ASN1ObjectIdentifier id_blake2s224 = blake2.branch("2.7"); + ASN1ObjectIdentifier id_blake2s256 = blake2.branch("2.8"); + + // + // Scrypt + ASN1ObjectIdentifier id_scrypt = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.4.11"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java index 4ef8148a..c687f3c5 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java @@ -4,55 +4,55 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; public interface NSRIObjectIdentifiers { - static final ASN1ObjectIdentifier nsri = new ASN1ObjectIdentifier("1.2.410.200046"); + ASN1ObjectIdentifier nsri = new ASN1ObjectIdentifier("1.2.410.200046"); - static final ASN1ObjectIdentifier id_algorithm = nsri.branch("1"); + ASN1ObjectIdentifier id_algorithm = nsri.branch("1"); - static final ASN1ObjectIdentifier id_sea = id_algorithm.branch("1"); - static final ASN1ObjectIdentifier id_pad = id_algorithm.branch("2"); + ASN1ObjectIdentifier id_sea = id_algorithm.branch("1"); + ASN1ObjectIdentifier id_pad = id_algorithm.branch("2"); - static final ASN1ObjectIdentifier id_pad_null = id_algorithm.branch("0"); - static final ASN1ObjectIdentifier id_pad_1 = id_algorithm.branch("1"); + ASN1ObjectIdentifier id_pad_null = id_algorithm.branch("0"); + ASN1ObjectIdentifier id_pad_1 = id_algorithm.branch("1"); - static final ASN1ObjectIdentifier id_aria128_ecb = id_sea.branch("1"); - static final ASN1ObjectIdentifier id_aria128_cbc = id_sea.branch("2"); - static final ASN1ObjectIdentifier id_aria128_cfb = id_sea.branch("3"); - static final ASN1ObjectIdentifier id_aria128_ofb = id_sea.branch("4"); - static final ASN1ObjectIdentifier id_aria128_ctr = id_sea.branch("5"); + ASN1ObjectIdentifier id_aria128_ecb = id_sea.branch("1"); + ASN1ObjectIdentifier id_aria128_cbc = id_sea.branch("2"); + ASN1ObjectIdentifier id_aria128_cfb = id_sea.branch("3"); + ASN1ObjectIdentifier id_aria128_ofb = id_sea.branch("4"); + ASN1ObjectIdentifier id_aria128_ctr = id_sea.branch("5"); - static final ASN1ObjectIdentifier id_aria192_ecb = id_sea.branch("6"); - static final ASN1ObjectIdentifier id_aria192_cbc = id_sea.branch("7"); - static final ASN1ObjectIdentifier id_aria192_cfb = id_sea.branch("8"); - static final ASN1ObjectIdentifier id_aria192_ofb = id_sea.branch("9"); - static final ASN1ObjectIdentifier id_aria192_ctr = id_sea.branch("10"); + ASN1ObjectIdentifier id_aria192_ecb = id_sea.branch("6"); + ASN1ObjectIdentifier id_aria192_cbc = id_sea.branch("7"); + ASN1ObjectIdentifier id_aria192_cfb = id_sea.branch("8"); + ASN1ObjectIdentifier id_aria192_ofb = id_sea.branch("9"); + ASN1ObjectIdentifier id_aria192_ctr = id_sea.branch("10"); - static final ASN1ObjectIdentifier id_aria256_ecb = id_sea.branch("11"); - static final ASN1ObjectIdentifier id_aria256_cbc = id_sea.branch("12"); - static final ASN1ObjectIdentifier id_aria256_cfb = id_sea.branch("13"); - static final ASN1ObjectIdentifier id_aria256_ofb = id_sea.branch("14"); - static final ASN1ObjectIdentifier id_aria256_ctr = id_sea.branch("15"); + ASN1ObjectIdentifier id_aria256_ecb = id_sea.branch("11"); + ASN1ObjectIdentifier id_aria256_cbc = id_sea.branch("12"); + ASN1ObjectIdentifier id_aria256_cfb = id_sea.branch("13"); + ASN1ObjectIdentifier id_aria256_ofb = id_sea.branch("14"); + ASN1ObjectIdentifier id_aria256_ctr = id_sea.branch("15"); - static final ASN1ObjectIdentifier id_aria128_cmac = id_sea.branch("21"); - static final ASN1ObjectIdentifier id_aria192_cmac = id_sea.branch("22"); - static final ASN1ObjectIdentifier id_aria256_cmac = id_sea.branch("23"); + ASN1ObjectIdentifier id_aria128_cmac = id_sea.branch("21"); + ASN1ObjectIdentifier id_aria192_cmac = id_sea.branch("22"); + ASN1ObjectIdentifier id_aria256_cmac = id_sea.branch("23"); - static final ASN1ObjectIdentifier id_aria128_ocb2 = id_sea.branch("31"); - static final ASN1ObjectIdentifier id_aria192_ocb2 = id_sea.branch("32"); - static final ASN1ObjectIdentifier id_aria256_ocb2 = id_sea.branch("33"); + ASN1ObjectIdentifier id_aria128_ocb2 = id_sea.branch("31"); + ASN1ObjectIdentifier id_aria192_ocb2 = id_sea.branch("32"); + ASN1ObjectIdentifier id_aria256_ocb2 = id_sea.branch("33"); - static final ASN1ObjectIdentifier id_aria128_gcm = id_sea.branch("34"); - static final ASN1ObjectIdentifier id_aria192_gcm = id_sea.branch("35"); - static final ASN1ObjectIdentifier id_aria256_gcm = id_sea.branch("36"); + ASN1ObjectIdentifier id_aria128_gcm = id_sea.branch("34"); + ASN1ObjectIdentifier id_aria192_gcm = id_sea.branch("35"); + ASN1ObjectIdentifier id_aria256_gcm = id_sea.branch("36"); - static final ASN1ObjectIdentifier id_aria128_ccm = id_sea.branch("37"); - static final ASN1ObjectIdentifier id_aria192_ccm = id_sea.branch("38"); - static final ASN1ObjectIdentifier id_aria256_ccm = id_sea.branch("39"); + ASN1ObjectIdentifier id_aria128_ccm = id_sea.branch("37"); + ASN1ObjectIdentifier id_aria192_ccm = id_sea.branch("38"); + ASN1ObjectIdentifier id_aria256_ccm = id_sea.branch("39"); - static final ASN1ObjectIdentifier id_aria128_kw = id_sea.branch("40"); - static final ASN1ObjectIdentifier id_aria192_kw = id_sea.branch("41"); - static final ASN1ObjectIdentifier id_aria256_kw = id_sea.branch("42"); + ASN1ObjectIdentifier id_aria128_kw = id_sea.branch("40"); + ASN1ObjectIdentifier id_aria192_kw = id_sea.branch("41"); + ASN1ObjectIdentifier id_aria256_kw = id_sea.branch("42"); - static final ASN1ObjectIdentifier id_aria128_kwp = id_sea.branch("43"); - static final ASN1ObjectIdentifier id_aria192_kwp = id_sea.branch("44"); - static final ASN1ObjectIdentifier id_aria256_kwp = id_sea.branch("45"); + ASN1ObjectIdentifier id_aria128_kwp = id_sea.branch("43"); + ASN1ObjectIdentifier id_aria192_kwp = id_sea.branch("44"); + ASN1ObjectIdentifier id_aria256_kwp = id_sea.branch("45"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/nsri/package.html b/bcprov/src/main/java/org/bouncycastle/asn1/nsri/package.html new file mode 100644 index 00000000..bd43ca00 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/asn1/nsri/package.html @@ -0,0 +1,5 @@ +<html> +<body bgcolor="#ffffff"> +Support classes algorithms from the Korean National Security Research Institute. +</body> +</html> diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java b/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java index 0b1db325..e471149a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java @@ -13,7 +13,7 @@ public class CertStatus implements ASN1Choice { private int tagNo; - private ASN1Encodable value; + private ASN1Encodable value; /** * create a CertStatus object with a tag of zero. diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java index ea4779bb..b7cae332 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java @@ -45,12 +45,21 @@ public class AuthenticatedSafe public AuthenticatedSafe( ContentInfo[] info) { - this.info = info; + this.info = copy(info); } public ContentInfo[] getContentInfo() { - return info; + return copy(info); + } + + private ContentInfo[] copy(ContentInfo[] infos) + { + ContentInfo[] tmp = new ContentInfo[infos.length]; + + System.arraycopy(infos, 0, tmp, 0, tmp.length); + + return tmp; } public ASN1Primitive toASN1Primitive() diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java index e0f5efdf..7a250eaa 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java @@ -35,8 +35,6 @@ public class EncryptedData extends ASN1Object { ASN1Sequence data; - ASN1ObjectIdentifier bagId; - ASN1Primitive bagValue; public static EncryptedData getInstance( Object obj) diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java index 848f4fcf..eeaa48d9 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java @@ -13,6 +13,12 @@ public class EncryptionScheme private AlgorithmIdentifier algId; public EncryptionScheme( + ASN1ObjectIdentifier objectId) + { + this.algId = new AlgorithmIdentifier(objectId); + } + + public EncryptionScheme( ASN1ObjectIdentifier objectId, ASN1Encodable parameters) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java index 63fa2e4e..593373f5 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java @@ -42,11 +42,11 @@ public class MacData { this.digInfo = DigestInfo.getInstance(seq.getObjectAt(0)); - this.salt = Arrays.clone(((ASN1OctetString)seq.getObjectAt(1)).getOctets()); + this.salt = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets()); if (seq.size() == 3) { - this.iterationCount = ((ASN1Integer)seq.getObjectAt(2)).getValue(); + this.iterationCount = ASN1Integer.getInstance(seq.getObjectAt(2)).getValue(); } else { 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 48d03209..d245b9bb 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java @@ -10,39 +10,39 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; public interface PKCSObjectIdentifiers { /** PKCS#1: 1.2.840.113549.1.1 */ - static final ASN1ObjectIdentifier pkcs_1 = new ASN1ObjectIdentifier("1.2.840.113549.1.1"); + ASN1ObjectIdentifier pkcs_1 = new ASN1ObjectIdentifier("1.2.840.113549.1.1"); /** PKCS#1: 1.2.840.113549.1.1.1 */ - static final ASN1ObjectIdentifier rsaEncryption = pkcs_1.branch("1"); + ASN1ObjectIdentifier rsaEncryption = pkcs_1.branch("1"); // BEGIN Android-removed: MD2 and MD4 are unsupported /* /** PKCS#1: 1.2.840.113549.1.1.2 * - static final ASN1ObjectIdentifier md2WithRSAEncryption = pkcs_1.branch("2"); + ASN1ObjectIdentifier md2WithRSAEncryption = pkcs_1.branch("2"); /** PKCS#1: 1.2.840.113549.1.1.3 * - static final ASN1ObjectIdentifier md4WithRSAEncryption = pkcs_1.branch("3"); + ASN1ObjectIdentifier md4WithRSAEncryption = pkcs_1.branch("3"); */ // END Android-removed: MD2 and MD4 are unsupported /** PKCS#1: 1.2.840.113549.1.1.4 */ - static final ASN1ObjectIdentifier md5WithRSAEncryption = pkcs_1.branch("4"); + ASN1ObjectIdentifier md5WithRSAEncryption = pkcs_1.branch("4"); /** PKCS#1: 1.2.840.113549.1.1.5 */ - static final ASN1ObjectIdentifier sha1WithRSAEncryption = pkcs_1.branch("5"); + ASN1ObjectIdentifier sha1WithRSAEncryption = pkcs_1.branch("5"); /** PKCS#1: 1.2.840.113549.1.1.6 */ - static final ASN1ObjectIdentifier srsaOAEPEncryptionSET = pkcs_1.branch("6"); + ASN1ObjectIdentifier srsaOAEPEncryptionSET = pkcs_1.branch("6"); /** PKCS#1: 1.2.840.113549.1.1.7 */ - static final ASN1ObjectIdentifier id_RSAES_OAEP = pkcs_1.branch("7"); + ASN1ObjectIdentifier id_RSAES_OAEP = pkcs_1.branch("7"); /** PKCS#1: 1.2.840.113549.1.1.8 */ - static final ASN1ObjectIdentifier id_mgf1 = pkcs_1.branch("8"); + ASN1ObjectIdentifier id_mgf1 = pkcs_1.branch("8"); /** PKCS#1: 1.2.840.113549.1.1.9 */ - static final ASN1ObjectIdentifier id_pSpecified = pkcs_1.branch("9"); + ASN1ObjectIdentifier id_pSpecified = pkcs_1.branch("9"); /** PKCS#1: 1.2.840.113549.1.1.10 */ - static final ASN1ObjectIdentifier id_RSASSA_PSS = pkcs_1.branch("10"); + ASN1ObjectIdentifier id_RSASSA_PSS = pkcs_1.branch("10"); /** PKCS#1: 1.2.840.113549.1.1.11 */ - static final ASN1ObjectIdentifier sha256WithRSAEncryption = pkcs_1.branch("11"); + ASN1ObjectIdentifier sha256WithRSAEncryption = pkcs_1.branch("11"); /** PKCS#1: 1.2.840.113549.1.1.12 */ - static final ASN1ObjectIdentifier sha384WithRSAEncryption = pkcs_1.branch("12"); + ASN1ObjectIdentifier sha384WithRSAEncryption = pkcs_1.branch("12"); /** PKCS#1: 1.2.840.113549.1.1.13 */ - static final ASN1ObjectIdentifier sha512WithRSAEncryption = pkcs_1.branch("13"); + ASN1ObjectIdentifier sha512WithRSAEncryption = pkcs_1.branch("13"); /** PKCS#1: 1.2.840.113549.1.1.14 */ - static final ASN1ObjectIdentifier sha224WithRSAEncryption = pkcs_1.branch("14"); + ASN1ObjectIdentifier sha224WithRSAEncryption = pkcs_1.branch("14"); /** PKCS#1: 1.2.840.113549.1.1.15 */ ASN1ObjectIdentifier sha512_224WithRSAEncryption = pkcs_1.branch("15"); /** PKCS#1: 1.2.840.113549.1.1.16 */ @@ -53,60 +53,60 @@ public interface PKCSObjectIdentifiers // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 } // /** PKCS#3: 1.2.840.113549.1.3 */ - static final ASN1ObjectIdentifier pkcs_3 = new ASN1ObjectIdentifier("1.2.840.113549.1.3"); + ASN1ObjectIdentifier pkcs_3 = new ASN1ObjectIdentifier("1.2.840.113549.1.3"); /** PKCS#3: 1.2.840.113549.1.3.1 */ - static final ASN1ObjectIdentifier dhKeyAgreement = pkcs_3.branch("1"); + ASN1ObjectIdentifier dhKeyAgreement = pkcs_3.branch("1"); // // pkcs-5 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } // /** PKCS#5: 1.2.840.113549.1.5 */ - static final ASN1ObjectIdentifier pkcs_5 = new ASN1ObjectIdentifier("1.2.840.113549.1.5"); + ASN1ObjectIdentifier pkcs_5 = new ASN1ObjectIdentifier("1.2.840.113549.1.5"); /** PKCS#5: 1.2.840.113549.1.5.1 */ - static final ASN1ObjectIdentifier pbeWithMD2AndDES_CBC = pkcs_5.branch("1"); + ASN1ObjectIdentifier pbeWithMD2AndDES_CBC = pkcs_5.branch("1"); /** PKCS#5: 1.2.840.113549.1.5.4 */ - static final ASN1ObjectIdentifier pbeWithMD2AndRC2_CBC = pkcs_5.branch("4"); + ASN1ObjectIdentifier pbeWithMD2AndRC2_CBC = pkcs_5.branch("4"); /** PKCS#5: 1.2.840.113549.1.5.3 */ - static final ASN1ObjectIdentifier pbeWithMD5AndDES_CBC = pkcs_5.branch("3"); + ASN1ObjectIdentifier pbeWithMD5AndDES_CBC = pkcs_5.branch("3"); /** PKCS#5: 1.2.840.113549.1.5.6 */ - static final ASN1ObjectIdentifier pbeWithMD5AndRC2_CBC = pkcs_5.branch("6"); + ASN1ObjectIdentifier pbeWithMD5AndRC2_CBC = pkcs_5.branch("6"); /** PKCS#5: 1.2.840.113549.1.5.10 */ - static final ASN1ObjectIdentifier pbeWithSHA1AndDES_CBC = pkcs_5.branch("10"); + ASN1ObjectIdentifier pbeWithSHA1AndDES_CBC = pkcs_5.branch("10"); /** PKCS#5: 1.2.840.113549.1.5.11 */ - static final ASN1ObjectIdentifier pbeWithSHA1AndRC2_CBC = pkcs_5.branch("11"); + ASN1ObjectIdentifier pbeWithSHA1AndRC2_CBC = pkcs_5.branch("11"); /** PKCS#5: 1.2.840.113549.1.5.13 */ - static final ASN1ObjectIdentifier id_PBES2 = pkcs_5.branch("13"); + ASN1ObjectIdentifier id_PBES2 = pkcs_5.branch("13"); /** PKCS#5: 1.2.840.113549.1.5.12 */ - static final ASN1ObjectIdentifier id_PBKDF2 = pkcs_5.branch("12"); + ASN1ObjectIdentifier id_PBKDF2 = pkcs_5.branch("12"); // // encryptionAlgorithm OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) 3 } // /** 1.2.840.113549.3 */ - static final ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.3"); + ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.3"); /** 1.2.840.113549.3.7 */ - static final ASN1ObjectIdentifier des_EDE3_CBC = encryptionAlgorithm.branch("7"); + ASN1ObjectIdentifier des_EDE3_CBC = encryptionAlgorithm.branch("7"); /** 1.2.840.113549.3.2 */ - static final ASN1ObjectIdentifier RC2_CBC = encryptionAlgorithm.branch("2"); + ASN1ObjectIdentifier RC2_CBC = encryptionAlgorithm.branch("2"); /** 1.2.840.113549.3.4 */ - static final ASN1ObjectIdentifier rc4 = encryptionAlgorithm.branch("4"); + ASN1ObjectIdentifier rc4 = encryptionAlgorithm.branch("4"); // // object identifiers for digests // /** 1.2.840.113549.2 */ - static final ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.2"); + ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.2"); // // md2 OBJECT IDENTIFIER ::= // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2} // // BEGIN android-removed // /** 1.2.840.113549.2.2 */ - // static final ASN1ObjectIdentifier md2 = digestAlgorithm.branch("2"); + // ASN1ObjectIdentifier md2 = digestAlgorithm.branch("2"); // END android-removed // @@ -115,7 +115,7 @@ public interface PKCSObjectIdentifiers // // BEGIN android-removed // /** 1.2.840.113549.2.4 */ - // static final ASN1ObjectIdentifier md4 = digestAlgorithm.branch("4"); + // ASN1ObjectIdentifier md4 = digestAlgorithm.branch("4"); // END android-removed // @@ -123,93 +123,93 @@ public interface PKCSObjectIdentifiers // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5} // /** 1.2.840.113549.2.5 */ - static final ASN1ObjectIdentifier md5 = digestAlgorithm.branch("5"); + ASN1ObjectIdentifier md5 = digestAlgorithm.branch("5"); /** 1.2.840.113549.2.7 */ - static final ASN1ObjectIdentifier id_hmacWithSHA1 = digestAlgorithm.branch("7").intern(); + ASN1ObjectIdentifier id_hmacWithSHA1 = digestAlgorithm.branch("7").intern(); /** 1.2.840.113549.2.8 */ - static final ASN1ObjectIdentifier id_hmacWithSHA224 = digestAlgorithm.branch("8").intern(); + ASN1ObjectIdentifier id_hmacWithSHA224 = digestAlgorithm.branch("8").intern(); /** 1.2.840.113549.2.9 */ - static final ASN1ObjectIdentifier id_hmacWithSHA256 = digestAlgorithm.branch("9").intern(); + ASN1ObjectIdentifier id_hmacWithSHA256 = digestAlgorithm.branch("9").intern(); /** 1.2.840.113549.2.10 */ - static final ASN1ObjectIdentifier id_hmacWithSHA384 = digestAlgorithm.branch("10").intern(); + ASN1ObjectIdentifier id_hmacWithSHA384 = digestAlgorithm.branch("10").intern(); /** 1.2.840.113549.2.11 */ - static final ASN1ObjectIdentifier id_hmacWithSHA512 = digestAlgorithm.branch("11").intern(); + ASN1ObjectIdentifier id_hmacWithSHA512 = digestAlgorithm.branch("11").intern(); // // pkcs-7 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 } // /** pkcs#7: 1.2.840.113549.1.7 */ - static final ASN1ObjectIdentifier pkcs_7 = new ASN1ObjectIdentifier("1.2.840.113549.1.7").intern(); + ASN1ObjectIdentifier pkcs_7 = new ASN1ObjectIdentifier("1.2.840.113549.1.7").intern(); /** PKCS#7: 1.2.840.113549.1.7.1 */ - static final ASN1ObjectIdentifier data = new ASN1ObjectIdentifier("1.2.840.113549.1.7.1").intern(); + ASN1ObjectIdentifier data = new ASN1ObjectIdentifier("1.2.840.113549.1.7.1").intern(); /** PKCS#7: 1.2.840.113549.1.7.2 */ - static final ASN1ObjectIdentifier signedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.2").intern(); + ASN1ObjectIdentifier signedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.2").intern(); /** PKCS#7: 1.2.840.113549.1.7.3 */ - static final ASN1ObjectIdentifier envelopedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.3").intern(); + ASN1ObjectIdentifier envelopedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.3").intern(); /** PKCS#7: 1.2.840.113549.1.7.4 */ - static final ASN1ObjectIdentifier signedAndEnvelopedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.4").intern(); + ASN1ObjectIdentifier signedAndEnvelopedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.4").intern(); /** PKCS#7: 1.2.840.113549.1.7.5 */ - static final ASN1ObjectIdentifier digestedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.5").intern(); + ASN1ObjectIdentifier digestedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.5").intern(); /** PKCS#7: 1.2.840.113549.1.7.76 */ - static final ASN1ObjectIdentifier encryptedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.6").intern(); + ASN1ObjectIdentifier encryptedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.6").intern(); // // pkcs-9 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } // /** PKCS#9: 1.2.840.113549.1.9 */ - static final ASN1ObjectIdentifier pkcs_9 = new ASN1ObjectIdentifier("1.2.840.113549.1.9"); + ASN1ObjectIdentifier pkcs_9 = new ASN1ObjectIdentifier("1.2.840.113549.1.9"); /** PKCS#9: 1.2.840.113549.1.9.1 */ - static final ASN1ObjectIdentifier pkcs_9_at_emailAddress = pkcs_9.branch("1").intern(); + ASN1ObjectIdentifier pkcs_9_at_emailAddress = pkcs_9.branch("1").intern(); /** PKCS#9: 1.2.840.113549.1.9.2 */ - static final ASN1ObjectIdentifier pkcs_9_at_unstructuredName = pkcs_9.branch("2").intern(); + ASN1ObjectIdentifier pkcs_9_at_unstructuredName = pkcs_9.branch("2").intern(); /** PKCS#9: 1.2.840.113549.1.9.3 */ - static final ASN1ObjectIdentifier pkcs_9_at_contentType = pkcs_9.branch("3").intern(); + ASN1ObjectIdentifier pkcs_9_at_contentType = pkcs_9.branch("3").intern(); /** PKCS#9: 1.2.840.113549.1.9.4 */ - static final ASN1ObjectIdentifier pkcs_9_at_messageDigest = pkcs_9.branch("4").intern(); + ASN1ObjectIdentifier pkcs_9_at_messageDigest = pkcs_9.branch("4").intern(); /** PKCS#9: 1.2.840.113549.1.9.5 */ - static final ASN1ObjectIdentifier pkcs_9_at_signingTime = pkcs_9.branch("5").intern(); + ASN1ObjectIdentifier pkcs_9_at_signingTime = pkcs_9.branch("5").intern(); /** PKCS#9: 1.2.840.113549.1.9.6 */ - static final ASN1ObjectIdentifier pkcs_9_at_counterSignature = pkcs_9.branch("6").intern(); + ASN1ObjectIdentifier pkcs_9_at_counterSignature = pkcs_9.branch("6").intern(); /** PKCS#9: 1.2.840.113549.1.9.7 */ - static final ASN1ObjectIdentifier pkcs_9_at_challengePassword = pkcs_9.branch("7").intern(); + ASN1ObjectIdentifier pkcs_9_at_challengePassword = pkcs_9.branch("7").intern(); /** PKCS#9: 1.2.840.113549.1.9.8 */ - static final ASN1ObjectIdentifier pkcs_9_at_unstructuredAddress = pkcs_9.branch("8").intern(); + ASN1ObjectIdentifier pkcs_9_at_unstructuredAddress = pkcs_9.branch("8").intern(); /** PKCS#9: 1.2.840.113549.1.9.9 */ - static final ASN1ObjectIdentifier pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9").intern(); + ASN1ObjectIdentifier pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9").intern(); /** PKCS#9: 1.2.840.113549.1.9.13 */ - static final ASN1ObjectIdentifier pkcs_9_at_signingDescription = pkcs_9.branch("13").intern(); + ASN1ObjectIdentifier pkcs_9_at_signingDescription = pkcs_9.branch("13").intern(); /** PKCS#9: 1.2.840.113549.1.9.14 */ - static final ASN1ObjectIdentifier pkcs_9_at_extensionRequest = pkcs_9.branch("14").intern(); + ASN1ObjectIdentifier pkcs_9_at_extensionRequest = pkcs_9.branch("14").intern(); /** PKCS#9: 1.2.840.113549.1.9.15 */ - static final ASN1ObjectIdentifier pkcs_9_at_smimeCapabilities = pkcs_9.branch("15").intern(); + ASN1ObjectIdentifier pkcs_9_at_smimeCapabilities = pkcs_9.branch("15").intern(); /** PKCS#9: 1.2.840.113549.1.9.16 */ - static final ASN1ObjectIdentifier id_smime = pkcs_9.branch("16").intern(); + ASN1ObjectIdentifier id_smime = pkcs_9.branch("16").intern(); /** PKCS#9: 1.2.840.113549.1.9.20 */ - static final ASN1ObjectIdentifier pkcs_9_at_friendlyName = pkcs_9.branch("20").intern(); + ASN1ObjectIdentifier pkcs_9_at_friendlyName = pkcs_9.branch("20").intern(); /** PKCS#9: 1.2.840.113549.1.9.21 */ - static final ASN1ObjectIdentifier pkcs_9_at_localKeyId = pkcs_9.branch("21").intern(); + ASN1ObjectIdentifier pkcs_9_at_localKeyId = pkcs_9.branch("21").intern(); /** PKCS#9: 1.2.840.113549.1.9.22.1 * @deprecated use x509Certificate instead */ - static final ASN1ObjectIdentifier x509certType = pkcs_9.branch("22.1"); + ASN1ObjectIdentifier x509certType = pkcs_9.branch("22.1"); /** PKCS#9: 1.2.840.113549.1.9.22 */ - static final ASN1ObjectIdentifier certTypes = pkcs_9.branch("22"); + ASN1ObjectIdentifier certTypes = pkcs_9.branch("22"); /** PKCS#9: 1.2.840.113549.1.9.22.1 */ - static final ASN1ObjectIdentifier x509Certificate = certTypes.branch("1").intern(); + ASN1ObjectIdentifier x509Certificate = certTypes.branch("1").intern(); /** PKCS#9: 1.2.840.113549.1.9.22.2 */ - static final ASN1ObjectIdentifier sdsiCertificate = certTypes.branch("2").intern(); + ASN1ObjectIdentifier sdsiCertificate = certTypes.branch("2").intern(); /** PKCS#9: 1.2.840.113549.1.9.23 */ - static final ASN1ObjectIdentifier crlTypes = pkcs_9.branch("23"); + ASN1ObjectIdentifier crlTypes = pkcs_9.branch("23"); /** PKCS#9: 1.2.840.113549.1.9.23.1 */ - static final ASN1ObjectIdentifier x509Crl = crlTypes.branch("1").intern(); + ASN1ObjectIdentifier x509Crl = crlTypes.branch("1").intern(); /** RFC 6211 - id-aa-cmsAlgorithmProtect OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) @@ -220,38 +220,38 @@ public interface PKCSObjectIdentifiers // SMIME capability sub oids. // /** PKCS#9: 1.2.840.113549.1.9.15.1 -- smime capability */ - static final ASN1ObjectIdentifier preferSignedData = pkcs_9.branch("15.1"); + ASN1ObjectIdentifier preferSignedData = pkcs_9.branch("15.1"); /** PKCS#9: 1.2.840.113549.1.9.15.2 -- smime capability */ - static final ASN1ObjectIdentifier canNotDecryptAny = pkcs_9.branch("15.2"); + ASN1ObjectIdentifier canNotDecryptAny = pkcs_9.branch("15.2"); /** PKCS#9: 1.2.840.113549.1.9.15.3 -- smime capability */ - static final ASN1ObjectIdentifier sMIMECapabilitiesVersions = pkcs_9.branch("15.3"); + ASN1ObjectIdentifier sMIMECapabilitiesVersions = pkcs_9.branch("15.3"); // // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)} // /** PKCS#9: 1.2.840.113549.1.9.16.1 -- smime ct */ - static final ASN1ObjectIdentifier id_ct = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1"); + ASN1ObjectIdentifier id_ct = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1"); /** PKCS#9: 1.2.840.113549.1.9.16.1.2 -- smime ct authData */ - static final ASN1ObjectIdentifier id_ct_authData = id_ct.branch("2"); + ASN1ObjectIdentifier id_ct_authData = id_ct.branch("2"); /** PKCS#9: 1.2.840.113549.1.9.16.1.4 -- smime ct TSTInfo*/ - static final ASN1ObjectIdentifier id_ct_TSTInfo = id_ct.branch("4"); + ASN1ObjectIdentifier id_ct_TSTInfo = id_ct.branch("4"); /** PKCS#9: 1.2.840.113549.1.9.16.1.9 -- smime ct compressedData */ - static final ASN1ObjectIdentifier id_ct_compressedData = id_ct.branch("9"); + ASN1ObjectIdentifier id_ct_compressedData = id_ct.branch("9"); /** PKCS#9: 1.2.840.113549.1.9.16.1.23 -- smime ct authEnvelopedData */ - static final ASN1ObjectIdentifier id_ct_authEnvelopedData = id_ct.branch("23"); + ASN1ObjectIdentifier id_ct_authEnvelopedData = id_ct.branch("23"); /** PKCS#9: 1.2.840.113549.1.9.16.1.31 -- smime ct timestampedData*/ - static final ASN1ObjectIdentifier id_ct_timestampedData = id_ct.branch("31"); + ASN1ObjectIdentifier id_ct_timestampedData = id_ct.branch("31"); /** S/MIME: Algorithm Identifiers ; 1.2.840.113549.1.9.16.3 */ - static final ASN1ObjectIdentifier id_alg = id_smime.branch("3"); + ASN1ObjectIdentifier id_alg = id_smime.branch("3"); /** PKCS#9: 1.2.840.113549.1.9.16.3.9 */ - static final ASN1ObjectIdentifier id_alg_PWRI_KEK = id_alg.branch("9"); + ASN1ObjectIdentifier id_alg_PWRI_KEK = id_alg.branch("9"); /** * <pre> - * -- RSA-KEM Key Transport Algorithm + * -- RSA-KEM Key Transport Algorithm RFC 5990 * * id-rsa-kem OID ::= { * iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) @@ -259,114 +259,114 @@ public interface PKCSObjectIdentifiers * } * </pre> */ - static final ASN1ObjectIdentifier id_rsa_KEM = id_alg.branch("14"); + ASN1ObjectIdentifier id_rsa_KEM = id_alg.branch("14"); // // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)} // /** PKCS#9: 1.2.840.113549.1.9.16.6 -- smime cti */ - static final ASN1ObjectIdentifier id_cti = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.6"); + ASN1ObjectIdentifier id_cti = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.6"); /** PKCS#9: 1.2.840.113549.1.9.16.6.1 -- smime cti proofOfOrigin */ - static final ASN1ObjectIdentifier id_cti_ets_proofOfOrigin = id_cti.branch("1"); + ASN1ObjectIdentifier id_cti_ets_proofOfOrigin = id_cti.branch("1"); /** PKCS#9: 1.2.840.113549.1.9.16.6.2 -- smime cti proofOfReceipt*/ - static final ASN1ObjectIdentifier id_cti_ets_proofOfReceipt = id_cti.branch("2"); + ASN1ObjectIdentifier id_cti_ets_proofOfReceipt = id_cti.branch("2"); /** PKCS#9: 1.2.840.113549.1.9.16.6.3 -- smime cti proofOfDelivery */ - static final ASN1ObjectIdentifier id_cti_ets_proofOfDelivery = id_cti.branch("3"); + ASN1ObjectIdentifier id_cti_ets_proofOfDelivery = id_cti.branch("3"); /** PKCS#9: 1.2.840.113549.1.9.16.6.4 -- smime cti proofOfSender */ - static final ASN1ObjectIdentifier id_cti_ets_proofOfSender = id_cti.branch("4"); + ASN1ObjectIdentifier id_cti_ets_proofOfSender = id_cti.branch("4"); /** PKCS#9: 1.2.840.113549.1.9.16.6.5 -- smime cti proofOfApproval */ - static final ASN1ObjectIdentifier id_cti_ets_proofOfApproval = id_cti.branch("5"); + ASN1ObjectIdentifier id_cti_ets_proofOfApproval = id_cti.branch("5"); /** PKCS#9: 1.2.840.113549.1.9.16.6.6 -- smime cti proofOfCreation */ - static final ASN1ObjectIdentifier id_cti_ets_proofOfCreation = id_cti.branch("6"); + ASN1ObjectIdentifier id_cti_ets_proofOfCreation = id_cti.branch("6"); // // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)} // - /** PKCS#9: 1.2.840.113549.1.9.16.6.2 - smime attributes */ - static final ASN1ObjectIdentifier id_aa = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.2"); + /** PKCS#9: 1.2.840.113549.1.9.16.2 - smime attributes */ + ASN1ObjectIdentifier id_aa = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.2"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.1 -- smime attribute receiptRequest */ - static final ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.1 -- smime attribute receiptRequest */ + ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See <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"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.4 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */ + ASN1ObjectIdentifier id_aa_contentHint = id_aa.branch("4"); // See RFC 2634 + /** PKCS#9: 1.2.840.113549.1.9.16.2.5 */ + ASN1ObjectIdentifier id_aa_msgSigDigest = id_aa.branch("5"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.10 */ + ASN1ObjectIdentifier id_aa_contentReference = id_aa.branch("10"); /* * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11} * */ - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.11 */ - static final ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch("11"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.12 */ - static final ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch("12"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.47 */ - static final ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch("47"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.11 */ + ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch("11"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.12 */ + ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch("12"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.47 */ + ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch("47"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.7 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */ - static final ASN1ObjectIdentifier id_aa_contentIdentifier = id_aa.branch("7"); // See RFC 2634 + /** PKCS#9: 1.2.840.113549.1.9.16.2.7 - See <a href="http://tools.ietf.org/html/rfc2634">RFC 2634</a> */ + 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.2.14 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + 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.2.15 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch("15"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.16 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch("16"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.17 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch("17"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.18 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + 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"); - - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.37 - <a href="https://tools.ietf.org/html/rfc4108#section-2.2.5">RFC 4108</a> */ - static final ASN1ObjectIdentifier id_aa_decryptKeyID = id_aa.branch("37"); - - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.38 - <a href="https://tools.ietf.org/html/rfc4108#section-2.2.6">RFC 4108</a> */ - static final ASN1ObjectIdentifier id_aa_implCryptoAlgs = id_aa.branch("38"); + ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch("19"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.20 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch("20"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.21 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch("21"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.22 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch("22"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.23 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch("23"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.24 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch("24"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.25 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch("25"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.26 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch("26"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.27 - <a href="http://tools.ietf.org/html/rfc3126">RFC 3126</a> */ + ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch("27"); + + /** PKCS#9: 1.2.840.113549.1.9.16.2.37 - <a href="https://tools.ietf.org/html/rfc4108#section-2.2.5">RFC 4108</a> */ + ASN1ObjectIdentifier id_aa_decryptKeyID = id_aa.branch("37"); + + /** PKCS#9: 1.2.840.113549.1.9.16.2.38 - <a href="https://tools.ietf.org/html/rfc4108#section-2.2.6">RFC 4108</a> */ + ASN1ObjectIdentifier id_aa_implCryptoAlgs = id_aa.branch("38"); /** PKCS#9: 1.2.840.113549.1.9.16.2.54 <a href="https://tools.ietf.org/html/rfc7030">RFC7030</a>*/ - static final ASN1ObjectIdentifier id_aa_asymmDecryptKeyID = id_aa.branch("54"); + ASN1ObjectIdentifier id_aa_asymmDecryptKeyID = id_aa.branch("54"); /** PKCS#9: 1.2.840.113549.1.9.16.2.43 <a href="https://tools.ietf.org/html/rfc7030">RFC7030</a>*/ - static final ASN1ObjectIdentifier id_aa_implCompressAlgs = id_aa.branch("43"); + ASN1ObjectIdentifier id_aa_implCompressAlgs = id_aa.branch("43"); /** PKCS#9: 1.2.840.113549.1.9.16.2.40 <a href="https://tools.ietf.org/html/rfc7030">RFC7030</a>*/ - static final ASN1ObjectIdentifier id_aa_communityIdentifiers = id_aa.branch("40"); + ASN1ObjectIdentifier id_aa_communityIdentifiers = id_aa.branch("40"); /** @deprecated use id_aa_ets_sigPolicyId instead */ - static final ASN1ObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId; + ASN1ObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId; /** @deprecated use id_aa_ets_commitmentType instead */ - static final ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType; + ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType; /** @deprecated use id_aa_ets_signerLocation instead */ - static final ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation; + ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation; /** @deprecated use id_aa_ets_otherSigCert instead */ - static final ASN1ObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert; + ASN1ObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert; /** * id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) @@ -376,61 +376,61 @@ public interface PKCSObjectIdentifiers final String id_spq = "1.2.840.113549.1.9.16.5"; /** SMIME SPQ URI: 1.2.840.113549.1.9.16.5.1 */ - static final ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + ".1"); + ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + ".1"); /** SMIME SPQ UNOTICE: 1.2.840.113549.1.9.16.5.2 */ - static final ASN1ObjectIdentifier id_spq_ets_unotice = new ASN1ObjectIdentifier(id_spq + ".2"); + ASN1ObjectIdentifier id_spq_ets_unotice = new ASN1ObjectIdentifier(id_spq + ".2"); // // pkcs-12 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } // /** PKCS#12: 1.2.840.113549.1.12 */ - static final ASN1ObjectIdentifier pkcs_12 = new ASN1ObjectIdentifier("1.2.840.113549.1.12"); + ASN1ObjectIdentifier pkcs_12 = new ASN1ObjectIdentifier("1.2.840.113549.1.12"); /** PKCS#12: 1.2.840.113549.1.12.10.1 */ - static final ASN1ObjectIdentifier bagtypes = pkcs_12.branch("10.1"); + ASN1ObjectIdentifier bagtypes = pkcs_12.branch("10.1"); /** PKCS#12: 1.2.840.113549.1.12.10.1.1 */ - static final ASN1ObjectIdentifier keyBag = bagtypes.branch("1"); + ASN1ObjectIdentifier keyBag = bagtypes.branch("1"); /** PKCS#12: 1.2.840.113549.1.12.10.1.2 */ - static final ASN1ObjectIdentifier pkcs8ShroudedKeyBag = bagtypes.branch("2"); + ASN1ObjectIdentifier pkcs8ShroudedKeyBag = bagtypes.branch("2"); /** PKCS#12: 1.2.840.113549.1.12.10.1.3 */ - static final ASN1ObjectIdentifier certBag = bagtypes.branch("3"); + ASN1ObjectIdentifier certBag = bagtypes.branch("3"); /** PKCS#12: 1.2.840.113549.1.12.10.1.4 */ - static final ASN1ObjectIdentifier crlBag = bagtypes.branch("4"); + ASN1ObjectIdentifier crlBag = bagtypes.branch("4"); /** PKCS#12: 1.2.840.113549.1.12.10.1.5 */ - static final ASN1ObjectIdentifier secretBag = bagtypes.branch("5"); + ASN1ObjectIdentifier secretBag = bagtypes.branch("5"); /** PKCS#12: 1.2.840.113549.1.12.10.1.6 */ - static final ASN1ObjectIdentifier safeContentsBag = bagtypes.branch("6"); + ASN1ObjectIdentifier safeContentsBag = bagtypes.branch("6"); /** PKCS#12: 1.2.840.113549.1.12.1 */ - static final ASN1ObjectIdentifier pkcs_12PbeIds = pkcs_12.branch("1"); + ASN1ObjectIdentifier pkcs_12PbeIds = pkcs_12.branch("1"); /** PKCS#12: 1.2.840.113549.1.12.1.1 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1"); + ASN1ObjectIdentifier pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1"); /** PKCS#12: 1.2.840.113549.1.12.1.2 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC4 = pkcs_12PbeIds.branch("2"); + ASN1ObjectIdentifier pbeWithSHAAnd40BitRC4 = pkcs_12PbeIds.branch("2"); /** PKCS#12: 1.2.840.113549.1.12.1.3 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3"); + ASN1ObjectIdentifier pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3"); /** PKCS#12: 1.2.840.113549.1.12.1.4 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4"); + ASN1ObjectIdentifier pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4"); /** PKCS#12: 1.2.840.113549.1.12.1.5 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch("5"); + ASN1ObjectIdentifier pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch("5"); /** PKCS#12: 1.2.840.113549.1.12.1.6 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); + ASN1ObjectIdentifier pbeWithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); /** * PKCS#12: 1.2.840.113549.1.12.1.6 * @deprecated use pbeWithSHAAnd40BitRC2_CBC */ - static final ASN1ObjectIdentifier pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); + ASN1ObjectIdentifier pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); /** PKCS#9: 1.2.840.113549.1.9.16.3.6 */ - static final ASN1ObjectIdentifier id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"); + ASN1ObjectIdentifier id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"); /** PKCS#9: 1.2.840.113549.1.9.16.3.7 */ - static final ASN1ObjectIdentifier id_alg_CMSRC2wrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"); + ASN1ObjectIdentifier id_alg_CMSRC2wrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"); /** PKCS#9: 1.2.840.113549.1.9.16.3.5 */ - static final ASN1ObjectIdentifier id_alg_ESDH = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.5"); + ASN1ObjectIdentifier id_alg_ESDH = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.5"); /** PKCS#9: 1.2.840.113549.1.9.16.3.10 */ - static final ASN1ObjectIdentifier id_alg_SSDH = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.10"); + ASN1ObjectIdentifier id_alg_SSDH = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.10"); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java index 7885a795..ce7e0758 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java @@ -22,7 +22,7 @@ public class Pfx private Pfx( ASN1Sequence seq) { - BigInteger version = ((ASN1Integer)seq.getObjectAt(0)).getValue(); + BigInteger version = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue(); if (version.intValue() != 3) { throw new IllegalArgumentException("wrong version for PFX PDU"); diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java index 7f02e709..85700b6a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java @@ -4,9 +4,9 @@ import java.io.IOException; import java.math.BigInteger; import java.util.Enumeration; +import org.bouncycastle.asn1.ASN1BitString; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1OctetString; @@ -14,27 +14,65 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - +import org.bouncycastle.util.BigIntegers; + +/** + * RFC 5958 + * + * <pre> + * [IMPLICIT TAGS] + * + * OneAsymmetricKey ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] Attributes OPTIONAL, + * ..., + * [[2: publicKey [1] PublicKey OPTIONAL ]], + * ... + * } + * + * PrivateKeyInfo ::= OneAsymmetricKey + * + * Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) + * + * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + * { PUBLIC-KEY, + * { PrivateKeyAlgorithms } } + * + * PrivateKey ::= OCTET STRING + * -- Content varies based on type of key. The + * -- algorithm identifier dictates the format of + * -- the key. + * + * PublicKey ::= BIT STRING + * -- Content varies based on type of key. The + * -- algorithm identifier dictates the format of + * -- the key. + * + * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } + * </pre> + */ public class PrivateKeyInfo extends ASN1Object { - private ASN1OctetString privKey; - private AlgorithmIdentifier algId; - private ASN1Set attributes; + private ASN1Integer version; + private AlgorithmIdentifier privateKeyAlgorithm; + private ASN1OctetString privateKey; + private ASN1Set attributes; + private ASN1BitString publicKey; - public static PrivateKeyInfo getInstance( - ASN1TaggedObject obj, - boolean explicit) + public static PrivateKeyInfo getInstance(ASN1TaggedObject obj, boolean explicit) { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - public static PrivateKeyInfo getInstance( - Object obj) + public static PrivateKeyInfo getInstance(Object obj) { if (obj instanceof PrivateKeyInfo) { @@ -47,118 +85,165 @@ public class PrivateKeyInfo return null; } - + + private static int getVersionValue(ASN1Integer version) + { + BigInteger bigValue = version.getValue(); + if (bigValue.compareTo(BigIntegers.ZERO) < 0 || bigValue.compareTo(BigIntegers.ONE) > 0) + { + throw new IllegalArgumentException("invalid version for private key info"); + } + return bigValue.intValue(); + } + public PrivateKeyInfo( - AlgorithmIdentifier algId, - ASN1Encodable privateKey) + AlgorithmIdentifier privateKeyAlgorithm, + ASN1Encodable privateKey) throws IOException { - this(algId, privateKey, null); + this(privateKeyAlgorithm, privateKey, null, null); } public PrivateKeyInfo( - AlgorithmIdentifier algId, - ASN1Encodable privateKey, - ASN1Set attributes) + AlgorithmIdentifier privateKeyAlgorithm, + ASN1Encodable privateKey, + ASN1Set attributes) throws IOException { - this.privKey = new DEROctetString(privateKey.toASN1Primitive().getEncoded(ASN1Encoding.DER)); - this.algId = algId; - this.attributes = attributes; + this(privateKeyAlgorithm, privateKey, attributes, null); } - /** - * @deprecated use PrivateKeyInfo.getInstance() - * @param seq - */ public PrivateKeyInfo( - ASN1Sequence seq) + AlgorithmIdentifier privateKeyAlgorithm, + ASN1Encodable privateKey, + ASN1Set attributes, + byte[] publicKey) + throws IOException + { + this.version = new ASN1Integer(publicKey != null ? BigIntegers.ONE : BigIntegers.ZERO); + this.privateKeyAlgorithm = privateKeyAlgorithm; + this.privateKey = new DEROctetString(privateKey); + this.attributes = attributes; + this.publicKey = publicKey == null ? null : new DERBitString(publicKey); + } + + private PrivateKeyInfo(ASN1Sequence seq) { Enumeration e = seq.getObjects(); - BigInteger version = ((ASN1Integer)e.nextElement()).getValue(); - if (version.intValue() != 0) - { - throw new IllegalArgumentException("wrong version for private key info"); - } + this.version = ASN1Integer.getInstance(e.nextElement()); + + int versionValue = getVersionValue(version); - algId = AlgorithmIdentifier.getInstance(e.nextElement()); - privKey = ASN1OctetString.getInstance(e.nextElement()); - - if (e.hasMoreElements()) + this.privateKeyAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + this.privateKey = ASN1OctetString.getInstance(e.nextElement()); + + int lastTag = -1; + while (e.hasMoreElements()) { - attributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false); + ASN1TaggedObject tagged = (ASN1TaggedObject)e.nextElement(); + + int tag = tagged.getTagNo(); + if (tag <= lastTag) + { + throw new IllegalArgumentException("invalid optional field in private key info"); + } + + lastTag = tag; + + switch (tag) + { + case 0: + { + this.attributes = ASN1Set.getInstance(tagged, false); + break; + } + case 1: + { + if (versionValue < 1) + { + throw new IllegalArgumentException("'publicKey' requires version v2(1) or later"); + } + + this.publicKey = DERBitString.getInstance(tagged, false); + break; + } + default: + { + throw new IllegalArgumentException("unknown optional field in private key info"); + } + } } } - public AlgorithmIdentifier getPrivateKeyAlgorithm() + public ASN1Set getAttributes() { - return algId; + return attributes; } - /** - * @deprecated use getPrivateKeyAlgorithm() - */ - public AlgorithmIdentifier getAlgorithmId() + + public AlgorithmIdentifier getPrivateKeyAlgorithm() { - return algId; + return privateKeyAlgorithm; } public ASN1Encodable parsePrivateKey() throws IOException { - return ASN1Primitive.fromByteArray(privKey.getOctets()); + return ASN1Primitive.fromByteArray(privateKey.getOctets()); } /** - * @deprecated use parsePrivateKey() + * Return true if a public key is present, false otherwise. + * + * @return true if public included, otherwise false. */ - public ASN1Primitive getPrivateKey() + public boolean hasPublicKey() { - try - { - return parsePrivateKey().toASN1Primitive(); - } - catch (IOException e) - { - throw new IllegalStateException("unable to parse private key"); - } + return publicKey != null; } - - public ASN1Set getAttributes() + + /** + * for when the public key is an encoded object - if the bitstring + * can't be decoded this routine throws an IOException. + * + * @return the public key as an ASN.1 primitive. + * @throws IOException - if the bit string doesn't represent a DER + * encoded object. + */ + public ASN1Encodable parsePublicKey() + throws IOException { - return attributes; + return publicKey == null ? null : ASN1Primitive.fromByteArray(publicKey.getOctets()); } /** - * write out an RSA private key with its associated information - * as described in PKCS8. - * <pre> - * PrivateKeyInfo ::= SEQUENCE { - * version Version, - * privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}}, - * privateKey PrivateKey, - * attributes [0] IMPLICIT Attributes OPTIONAL - * } - * Version ::= INTEGER {v1(0)} (v1,...) + * for when the public key is raw bits. * - * PrivateKey ::= OCTET STRING - * - * Attributes ::= SET OF Attribute - * </pre> + * @return the public key as the raw bit string... */ + public ASN1BitString getPublicKeyData() + { + return publicKey; + } + public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1Integer(0)); - v.add(algId); - v.add(privKey); + v.add(version); + v.add(privateKeyAlgorithm); + v.add(privateKey); if (attributes != null) { v.add(new DERTaggedObject(false, 0, attributes)); } - + + if (publicKey != null) + { + v.add(new DERTaggedObject(false, 1, publicKey)); + } + return new DERSequence(v); } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java index 1ddc17d0..bb215bee 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java @@ -9,6 +9,8 @@ import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; * ellipticCurve OBJECT IDENTIFIER ::= { * iso(1) identified-organization(3) certicom(132) curve(0) * } + * secg-scheme OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) schemes(1) } * </pre> */ public interface SECObjectIdentifiers diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java index 59c961f2..f251702e 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java @@ -7,6 +7,7 @@ import org.bouncycastle.asn1.ASN1ApplicationSpecific; import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1External; import org.bouncycastle.asn1.ASN1GeneralizedTime; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; @@ -25,16 +26,17 @@ import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERApplicationSpecific; import org.bouncycastle.asn1.DERBMPString; import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERExternal; import org.bouncycastle.asn1.DERGraphicString; import org.bouncycastle.asn1.DERIA5String; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DERPrintableString; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.DERT61String; import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.DERVideotexString; import org.bouncycastle.asn1.DERVisibleString; +import org.bouncycastle.asn1.DLApplicationSpecific; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; @@ -147,11 +149,14 @@ public class ASN1Dump { buf.append("BER Set"); } - else + else if (obj instanceof DERSet) { buf.append("DER Set"); } - + else + { + buf.append("Set"); + } buf.append(nl); while (e.hasMoreElements()) @@ -268,14 +273,18 @@ public class ASN1Dump { buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl)); } + else if (obj instanceof DLApplicationSpecific) + { + buf.append(outputApplicationSpecific("", indent, verbose, obj, nl)); + } else if (obj instanceof ASN1Enumerated) { ASN1Enumerated en = (ASN1Enumerated) obj; buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl); } - else if (obj instanceof DERExternal) + else if (obj instanceof ASN1External) { - DERExternal ext = (DERExternal) obj; + ASN1External ext = (ASN1External) obj; buf.append(indent + "External " + nl); String tab = indent + TAB; if (ext.getDirectReference() != null) diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java index 6a1b318f..c84bd0e2 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java @@ -108,7 +108,7 @@ public class RDN * <pre> * RelativeDistinguishedName ::= * SET OF AttributeTypeAndValue - * + * AttributeTypeAndValue ::= SEQUENCE { * type AttributeType, * value AttributeValue } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java index 67c5cd1c..bcdfa334 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java @@ -130,7 +130,7 @@ public class X500Name X500NameStyle style, RDN[] rDNs) { - this.rdns = rDNs; + this.rdns = copy(rDNs); this.style = style; } @@ -247,6 +247,15 @@ public class X500Name return tmp; } + private RDN[] copy(RDN[] rdns) + { + RDN[] tmp = new RDN[rdns.length]; + + System.arraycopy(rdns, 0, tmp, 0, tmp.length); + + return tmp; + } + public ASN1Primitive toASN1Primitive() { return new DERSequence(rdns); 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 2ef24d36..8d2129ae 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 @@ -150,6 +150,12 @@ public class BCStyle */ public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name; + + /** + * id-at-organizationIdentifier + */ + public static final ASN1ObjectIdentifier ORGANIZATION_IDENTIFIER = X509ObjectIdentifiers.id_at_organizationIdentifier; + /** * Email address (RSA PKCS#9 extension) - IA5String. * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. @@ -222,6 +228,7 @@ public class BCStyle DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory"); DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber"); DefaultSymbols.put(NAME, "Name"); + DefaultSymbols.put(ORGANIZATION_IDENTIFIER, "organizationIdentifier"); DefaultLookUp.put("c", C); DefaultLookUp.put("o", O); @@ -257,6 +264,7 @@ public class BCStyle DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY); DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER); DefaultLookUp.put("name", NAME); + DefaultLookUp.put("organizationidentifier", ORGANIZATION_IDENTIFIER); } /** diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java index 54eaa329..b55d9a9b 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java @@ -21,7 +21,7 @@ public class AlgorithmIdentifier { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - + public static AlgorithmIdentifier getInstance( Object obj) { @@ -59,7 +59,7 @@ public class AlgorithmIdentifier throw new IllegalArgumentException("Bad sequence size: " + seq.size()); } - + algorithm = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); if (seq.size() == 2) diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java index dcde3034..df4ad65f 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java @@ -17,6 +17,7 @@ import org.bouncycastle.crypto.Digest; // Android-changed: Use Android digests // import org.bouncycastle.crypto.digests.SHA1Digest; import org.bouncycastle.crypto.digests.AndroidDigestFactory; +import org.bouncycastle.util.encoders.Hex; /** * The AuthorityKeyIdentifier object. @@ -230,6 +231,6 @@ public class AuthorityKeyIdentifier public String toString() { - return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.getOctets() + ")"); + return ("AuthorityKeyIdentifier: KeyID(" + ((keyidentifier != null) ? Hex.toHexString(this.keyidentifier.getOctets()) : "null") + ")"); } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java index dd3422f6..14bc2e23 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java @@ -20,6 +20,11 @@ public class CRLDistPoint return getInstance(ASN1Sequence.getInstance(obj, explicit)); } + public static CRLDistPoint fromExtensions(Extensions extensions) + { + return CRLDistPoint.getInstance(extensions.getExtensionParsedValue(Extension.cRLDistributionPoints)); + } + public static CRLDistPoint getInstance( Object obj) { diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java index fd17f1b5..4b040a72 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java @@ -10,6 +10,7 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.util.Arrays; /** * The DigestInfo object. @@ -51,7 +52,7 @@ public class DigestInfo AlgorithmIdentifier algId, byte[] digest) { - this.digest = digest; + this.digest = Arrays.clone(digest); this.algId = algId; } @@ -71,7 +72,7 @@ public class DigestInfo public byte[] getDigest() { - return digest; + return Arrays.clone(digest); } public ASN1Primitive toASN1Primitive() diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java index 6508f938..30a16f3c 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java @@ -56,6 +56,11 @@ public class Extensions { Extension ext = Extension.getInstance(e.nextElement()); + if (extensions.containsKey(ext.getExtnId())) + { + throw new IllegalArgumentException("repeated extension found: " + ext.getExtnId()); + } + extensions.put(ext.getExtnId(), ext); ordering.addElement(ext.getExtnId()); } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java index 405f6e4e..52e0c36b 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java @@ -56,7 +56,7 @@ public class GeneralNames public GeneralNames( GeneralName[] names) { - this.names = names; + this.names = copy(names); } private GeneralNames( @@ -72,9 +72,14 @@ public class GeneralNames public GeneralName[] getNames() { - GeneralName[] tmp = new GeneralName[names.length]; + return copy(names); + } + + private GeneralName[] copy(GeneralName[] nms) + { + GeneralName[] tmp = new GeneralName[nms.length]; - System.arraycopy(names, 0, tmp, 0, names.length); + System.arraycopy(nms, 0, tmp, 0, tmp.length); return tmp; } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/OtherName.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/OtherName.java new file mode 100644 index 00000000..eb652f7f --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/OtherName.java @@ -0,0 +1,92 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +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; + +/** + * The OtherName object. + * <pre> + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * </pre> + */ +public class OtherName + extends ASN1Object +{ + private final ASN1ObjectIdentifier typeID; + private final ASN1Encodable value; + + /** + * OtherName factory method. + * @param obj the object used to construct an instance of <code> + * OtherName</code>. It must be an instance of <code>OtherName + * </code> or <code>ASN1Sequence</code>. + * @return the instance of <code>OtherName</code> built from the + * supplied object. + * @throws java.lang.IllegalArgumentException if the object passed + * to the factory is not an instance of <code>OtherName</code> or something that + * can be converted into an appropriate <code>ASN1Sequence</code>. + */ + public static OtherName getInstance( + Object obj) + { + + if (obj instanceof OtherName) + { + return (OtherName)obj; + } + else if (obj != null) + { + return new OtherName(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Base constructor. + * @param typeID the type of the other name. + * @param value the ANY object that represents the value. + */ + public OtherName( + ASN1ObjectIdentifier typeID, + ASN1Encodable value) + { + this.typeID = typeID; + this.value = value; + } + + private OtherName(ASN1Sequence seq) + { + this.typeID = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + this.value = ASN1TaggedObject.getInstance(seq.getObjectAt(1)).getObject(); // explicitly tagged + } + + public ASN1ObjectIdentifier getTypeID() + { + return typeID; + } + + public ASN1Encodable getValue() + { + return value; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(typeID); + v.add(new DERTaggedObject(true, 0, value)); + + return new DERSequence(v); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java index 0f15dae1..d360609e 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java @@ -1,5 +1,6 @@ package org.bouncycastle.asn1.x509; +import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -15,6 +16,7 @@ import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Integers; import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; public class PKIXNameConstraintValidator implements NameConstraintValidator @@ -29,6 +31,8 @@ public class PKIXNameConstraintValidator private Set excludedSubtreesIP = new HashSet(); + private Set excludedSubtreesOtherName = new HashSet(); + private Set permittedSubtreesDN; private Set permittedSubtreesDNS; @@ -39,6 +43,8 @@ public class PKIXNameConstraintValidator private Set permittedSubtreesIP; + private Set permittedSubtreesOtherName; + public PKIXNameConstraintValidator() { } @@ -54,6 +60,9 @@ public class PKIXNameConstraintValidator { switch (name.getTagNo()) { + case GeneralName.otherName: + checkPermittedOtherName(permittedSubtreesOtherName, OtherName.getInstance(name.getName())); + break; case GeneralName.rfc822Name: checkPermittedEmail(permittedSubtreesEmail, extractNameAsString(name)); @@ -73,6 +82,9 @@ public class PKIXNameConstraintValidator byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets(); checkPermittedIP(permittedSubtreesIP, ip); + break; + default: + throw new IllegalStateException("Unknown tag encountered: " + name.getTagNo()); } } @@ -88,6 +100,9 @@ public class PKIXNameConstraintValidator { switch (name.getTagNo()) { + case GeneralName.otherName: + checkExcludedOtherName(excludedSubtreesOtherName, OtherName.getInstance(name.getName())); + break; case GeneralName.rfc822Name: checkExcludedEmail(excludedSubtreesEmail, extractNameAsString(name)); break; @@ -106,6 +121,9 @@ public class PKIXNameConstraintValidator byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets(); checkExcludedIP(excludedSubtreesIP, ip); + break; + default: + throw new IllegalStateException("Unknown tag encountered: " + name.getTagNo()); } } @@ -141,8 +159,13 @@ public class PKIXNameConstraintValidator Map.Entry entry = (Map.Entry)it.next(); // go through all subtree groups - switch (((Integer)entry.getKey()).intValue()) + int nameType = ((Integer)entry.getKey()).intValue(); + switch (nameType) { + case GeneralName.otherName: + permittedSubtreesOtherName = intersectOtherName(permittedSubtreesOtherName, + (Set)entry.getValue()); + break; case GeneralName.rfc822Name: permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail, (Set)entry.getValue()); @@ -162,6 +185,9 @@ public class PKIXNameConstraintValidator case GeneralName.iPAddress: permittedSubtreesIP = intersectIP(permittedSubtreesIP, (Set)entry.getValue()); + break; + default: + throw new IllegalStateException("Unknown tag encountered: " + nameType); } } } @@ -170,6 +196,9 @@ public class PKIXNameConstraintValidator { switch (nameType) { + case GeneralName.otherName: + permittedSubtreesOtherName = new HashSet(); + break; case GeneralName.rfc822Name: permittedSubtreesEmail = new HashSet(); break; @@ -184,6 +213,9 @@ public class PKIXNameConstraintValidator break; case GeneralName.iPAddress: permittedSubtreesIP = new HashSet(); + break; + default: + throw new IllegalStateException("Unknown tag encountered: " + nameType); } } @@ -198,6 +230,10 @@ public class PKIXNameConstraintValidator switch (base.getTagNo()) { + case GeneralName.otherName: + excludedSubtreesOtherName = unionOtherName(excludedSubtreesOtherName, + OtherName.getInstance(base.getName())); + break; case GeneralName.rfc822Name: excludedSubtreesEmail = unionEmail(excludedSubtreesEmail, extractNameAsString(base)); @@ -218,6 +254,8 @@ public class PKIXNameConstraintValidator excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString .getInstance(base.getName()).getOctets()); break; + default: + throw new IllegalStateException("Unknown tag encountered: " + base.getTagNo()); } } @@ -228,11 +266,13 @@ public class PKIXNameConstraintValidator + hashCollection(excludedSubtreesEmail) + hashCollection(excludedSubtreesIP) + hashCollection(excludedSubtreesURI) + + hashCollection(excludedSubtreesOtherName) + hashCollection(permittedSubtreesDN) + hashCollection(permittedSubtreesDNS) + hashCollection(permittedSubtreesEmail) + hashCollection(permittedSubtreesIP) - + hashCollection(permittedSubtreesURI); + + hashCollection(permittedSubtreesURI) + + hashCollection(permittedSubtreesOtherName); } public boolean equals(Object o) @@ -247,11 +287,13 @@ public class PKIXNameConstraintValidator && collectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail) && collectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP) && collectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI) + && collectionsAreEqual(constraintValidator.excludedSubtreesOtherName, excludedSubtreesOtherName) && collectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN) && collectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS) && collectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail) && collectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP) - && collectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI); + && collectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI) + && collectionsAreEqual(constraintValidator.permittedSubtreesOtherName, permittedSubtreesOtherName); } public String toString() @@ -283,6 +325,11 @@ public class PKIXNameConstraintValidator temp += "IP:\n"; temp += stringifyIPCollection(permittedSubtreesIP) + "\n"; } + if (permittedSubtreesOtherName != null) + { + temp += "OtherName:\n"; + temp += stringifyOtherNameCollection(permittedSubtreesOtherName) + "\n"; + } temp += "excluded:\n"; if (!excludedSubtreesDN.isEmpty()) { @@ -309,6 +356,11 @@ public class PKIXNameConstraintValidator temp += "IP:\n"; temp += stringifyIPCollection(excludedSubtreesIP) + "\n"; } + if (!excludedSubtreesOtherName.isEmpty()) + { + temp += "OtherName:\n"; + temp += stringifyOtherNameCollection(excludedSubtreesOtherName) + "\n"; + } return temp; } @@ -474,6 +526,25 @@ public class PKIXNameConstraintValidator } } + private Set intersectOtherName(Set permitted, Set otherNames) + { + Set intersect = new HashSet(permitted); + + intersect.retainAll(otherNames); + + return intersect; + } + + + private Set unionOtherName(Set permitted, OtherName otherName) + { + Set union = new HashSet(permitted); + + union.add(otherName); + + return union; + } + private Set intersectEmail(Set permitted, Set emails) { Set intersect = new HashSet(); @@ -774,6 +845,52 @@ public class PKIXNameConstraintValidator "Subject email address is not from a permitted subtree."); } + private void checkPermittedOtherName(Set permitted, OtherName name) + throws NameConstraintValidatorException + { + if (permitted == null) + { + return; + } + + Iterator it = permitted.iterator(); + + while (it.hasNext()) + { + OtherName str = ((OtherName)it.next()); + + if (otherNameIsConstrained(name, str)) + { + return; + } + } + + throw new NameConstraintValidatorException( + "Subject OtherName is not from a permitted subtree."); + } + + private void checkExcludedOtherName(Set excluded, OtherName name) + throws NameConstraintValidatorException + { + if (excluded.isEmpty()) + { + return; + } + + Iterator it = excluded.iterator(); + + while (it.hasNext()) + { + OtherName str = OtherName.getInstance(it.next()); + + if (otherNameIsConstrained(name, str)) + { + throw new NameConstraintValidatorException( + "OtherName is from an excluded subtree."); + } + } + } + private void checkExcludedEmail(Set excluded, String email) throws NameConstraintValidatorException { @@ -899,6 +1016,16 @@ public class PKIXNameConstraintValidator return Arrays.areEqual(permittedSubnetAddress, ipSubnetAddress); } + private boolean otherNameIsConstrained(OtherName name, OtherName constraint) + { + if (constraint.equals(name)) + { + return true; + } + + return false; + } + private boolean emailIsConstrained(String email, String constraint) { String sub = email.substring(email.indexOf('@') + 1); @@ -1887,34 +2014,73 @@ public class PKIXNameConstraintValidator */ private String stringifyIP(byte[] ip) { - String temp = ""; + StringBuilder temp = new StringBuilder(); for (int i = 0; i < ip.length / 2; i++) { - temp += Integer.toString(ip[i] & 0x00FF) + "."; + if (temp.length() > 0) + { + temp.append("."); + } + temp.append(Integer.toString(ip[i] & 0x00FF)); } - temp = temp.substring(0, temp.length() - 1); - temp += "/"; + + temp.append("/"); + boolean first = true; for (int i = ip.length / 2; i < ip.length; i++) { - temp += Integer.toString(ip[i] & 0x00FF) + "."; + if (first) + { + first = false; + } + else + { + temp.append("."); + } + temp.append(Integer.toString(ip[i] & 0x00FF)); } - temp = temp.substring(0, temp.length() - 1); - return temp; + + return temp.toString(); } private String stringifyIPCollection(Set ips) { - String temp = ""; - temp += "["; + StringBuilder temp = new StringBuilder(); + temp.append("["); for (Iterator it = ips.iterator(); it.hasNext(); ) { - temp += stringifyIP((byte[])it.next()) + ","; + if (temp.length() > 1) + { + temp.append(","); + } + temp.append(stringifyIP((byte[])it.next())); } - if (temp.length() > 1) + temp.append("]"); + return temp.toString(); + } + + private String stringifyOtherNameCollection(Set otherNames) + { + StringBuilder temp = new StringBuilder(); + temp.append("["); + for (Iterator it = otherNames.iterator(); it.hasNext(); ) { - temp = temp.substring(0, temp.length() - 1); + if (temp.length() > 1) + { + temp.append(","); + } + OtherName name = OtherName.getInstance(it.next()); + temp.append(name.getTypeID().getId()); + temp.append(":"); + try + { + temp.append(Hex.toHexString(name.getValue().toASN1Primitive().getEncoded())); + } + catch (IOException e) + { + temp.append(e.toString()); + } } - temp += "]"; - return temp; + temp.append("]"); + return temp.toString(); } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java index 0938a948..97c0f143 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java @@ -5,7 +5,6 @@ import java.util.Enumeration; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; @@ -14,7 +13,7 @@ import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DERSequence; /** - * The object that contains the public key stored in a certficate. + * The object that contains the public key stored in a certificate. * <p> * The getEncoded() method in the public keys in the JCE produces a DER * encoded one of these. @@ -107,9 +106,7 @@ public class SubjectPublicKeyInfo public ASN1Primitive parsePublicKey() throws IOException { - ASN1InputStream aIn = new ASN1InputStream(keyData.getOctets()); - - return aIn.readObject(); + return ASN1Primitive.fromByteArray(keyData.getOctets()); } /** @@ -124,9 +121,7 @@ public class SubjectPublicKeyInfo public ASN1Primitive getPublicKey() throws IOException { - ASN1InputStream aIn = new ASN1InputStream(keyData.getOctets()); - - return aIn.readObject(); + return ASN1Primitive.fromByteArray(keyData.getOctets()); } /** diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java index f7f60050..3d5e1be1 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java @@ -1,12 +1,13 @@ package org.bouncycastle.asn1.x509; +import java.math.BigInteger; + 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.DERBitString; -import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.x500.X500Name; /** @@ -87,6 +88,22 @@ public class TBSCertificate version = new ASN1Integer(0); } + boolean isV1 = false; + boolean isV2 = false; + + if (version.getValue().equals(BigInteger.valueOf(0))) + { + isV1 = true; + } + else if (version.getValue().equals(BigInteger.valueOf(1))) + { + isV2 = true; + } + else if (!version.getValue().equals(BigInteger.valueOf(2))) + { + throw new IllegalArgumentException("version number not recognised"); + } + serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1)); signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2)); @@ -107,7 +124,13 @@ public class TBSCertificate // subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6)); - for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--) + int extras = seq.size() - (seqStart + 6) - 1; + if (extras != 0 && isV1) + { + throw new IllegalArgumentException("version 1 certificate contains extra data"); + } + + while (extras > 0) { ASN1TaggedObject extra = (ASN1TaggedObject)seq.getObjectAt(seqStart + 6 + extras); @@ -120,8 +143,16 @@ public class TBSCertificate subjectUniqueId = DERBitString.getInstance(extra, false); break; case 3: + if (isV2) + { + throw new IllegalArgumentException("version 2 certificate cannot contain extensions"); + } extensions = Extensions.getInstance(ASN1Sequence.getInstance(extra, true)); + break; + default: + throw new IllegalArgumentException("Unknown tag encountered in structure: " + extra.getTagNo()); } + extras--; } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java index 2c5d920a..e7bdedc5 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java @@ -29,6 +29,7 @@ import org.bouncycastle.asn1.x500.X500Name; * <p> * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class * will parse them, but you really shouldn't be creating new ones. + * @deprecated use TBSCertificate */ public class TBSCertificateStructure extends ASN1Object 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 e58220e6..af218bca 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java @@ -23,6 +23,8 @@ public interface X509ObjectIdentifiers /** Subject RDN components: name = 2.5.4.41 */ static final ASN1ObjectIdentifier id_at_name = new ASN1ObjectIdentifier("2.5.4.41").intern(); + static final ASN1ObjectIdentifier id_at_organizationIdentifier = new ASN1ObjectIdentifier("2.5.4.97").intern(); + /** * id-SHA1 OBJECT IDENTIFIER ::= * {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/DomainParameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/DomainParameters.java index e23f1b84..0555190a 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/DomainParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/DomainParameters.java @@ -19,7 +19,7 @@ import org.bouncycastle.asn1.DERSequence; * p INTEGER, -- odd prime, p=jq +1 * g INTEGER, -- generator, g * q INTEGER, -- factor of p-1 - * j INTEGER OPTIONAL, -- subgroup factor, j>= 2 + * j INTEGER OPTIONAL, -- subgroup factor, j >= 2 * validationParams ValidationParams OPTIONAL * } * </pre> diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java index 0fc87379..41f12b1c 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java @@ -7,10 +7,13 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; // Android-removed: Unsupported curves // import org.bouncycastle.asn1.anssi.ANSSINamedCurves; // import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; +// import org.bouncycastle.asn1.gm.GMNamedCurves; import org.bouncycastle.asn1.nist.NISTNamedCurves; import org.bouncycastle.asn1.sec.SECNamedCurves; // Android-removed: Unsupported curves // import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; +import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.crypto.params.ECDomainParameters; /** * A general class that reads all X9.62 style EC curve tables. @@ -50,6 +53,16 @@ public class ECNamedCurveTable { ecP = ANSSINamedCurves.getByName(name); } + + if (ecP == null) + { + ecP = fromDomainParameters(ECGOST3410NamedCurves.getByName(name)); + } + + if (ecP == null) + { + ecP = GMNamedCurves.getByName(name); + } */ // END Android-removed: Unsupported curves @@ -88,6 +101,16 @@ public class ECNamedCurveTable { oid = ANSSINamedCurves.getOID(name); } + + if (oid == null) + { + oid = ECGOST3410NamedCurves.getOID(name); + } + + if (oid == null) + { + oid = GMNamedCurves.getOID(name); + } */ // END Android-removed: Unsupported curves @@ -104,33 +127,44 @@ public class ECNamedCurveTable public static String getName( ASN1ObjectIdentifier oid) { - String name = NISTNamedCurves.getName(oid); + String name = X962NamedCurves.getName(oid); if (name == null) { name = SECNamedCurves.getName(oid); } + if (name == null) + { + name = NISTNamedCurves.getName(oid); + } + // BEGIN Android-removed: Unsupported curves /* if (name == null) { name = TeleTrusTNamedCurves.getName(oid); } - */ - // END Android-removed: Unsupported curves if (name == null) { - name = X962NamedCurves.getName(oid); + name = ANSSINamedCurves.getName(oid); } - // BEGIN Android-removed: Unsupported curves - /* if (name == null) { name = ECGOST3410NamedCurves.getName(oid); } + + if (name == null) + { + name = GMNamedCurves.getName(oid); + } + + if (name == null) + { + name = CustomNamedCurves.getName(oid); + } */ // END Android-removed: Unsupported curves @@ -167,6 +201,16 @@ public class ECNamedCurveTable { ecP = ANSSINamedCurves.getByOID(oid); } + + if (ecP == null) + { + ecP = fromDomainParameters(ECGOST3410NamedCurves.getByOID(oid)); + } + + if (ecP == null) + { + ecP = GMNamedCurves.getByOID(oid); + } */ // END Android-removed: Unsupported curves @@ -188,6 +232,8 @@ public class ECNamedCurveTable // BEGIN Android-removed: Unsupported curves // addEnumeration(v, TeleTrusTNamedCurves.getNames()); // addEnumeration(v, ANSSINamedCurves.getNames()); + // addEnumeration(v, ECGOST3410NamedCurves.getNames()); + // addEnumeration(v, GMNamedCurves.getNames()); // END Android-removed: Unsupported curves return v.elements(); @@ -202,4 +248,9 @@ public class ECNamedCurveTable v.addElement(e.nextElement()); } } + + private static X9ECParameters fromDomainParameters(ECDomainParameters dp) + { + return dp == null ? null : new X9ECParameters(dp.getCurve(), dp.getG(), dp.getN(), dp.getH(), dp.getSeed()); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java index 022c0183..02968345 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java @@ -23,7 +23,7 @@ public class X962NamedCurves BigInteger h = BigInteger.valueOf(1); ECCurve cFp192v1 = new ECCurve.Fp( - new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16), new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), n, h); @@ -45,7 +45,7 @@ public class X962NamedCurves BigInteger h = BigInteger.valueOf(1); ECCurve cFp192v2 = new ECCurve.Fp( - new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16), new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16), n, h); @@ -67,7 +67,7 @@ public class X962NamedCurves BigInteger h = BigInteger.valueOf(1); ECCurve cFp192v3 = new ECCurve.Fp( - new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16), new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16), n, h); diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java index f1bac2b8..3838a232 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java @@ -13,6 +13,7 @@ import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.math.ec.ECAlgorithms; import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.util.Arrays; /** * ASN.1 def for Elliptic-Curve Curve structure. See @@ -29,9 +30,7 @@ public class X9Curve public X9Curve( ECCurve curve) { - this.curve = curve; - this.seed = null; - setFieldIdentifier(); + this(curve, null); } public X9Curve( @@ -39,25 +38,25 @@ public class X9Curve byte[] seed) { this.curve = curve; - this.seed = seed; + this.seed = Arrays.clone(seed); setFieldIdentifier(); } public X9Curve( X9FieldID fieldID, + BigInteger order, + BigInteger cofactor, ASN1Sequence seq) - { - // TODO Is it possible to get the order(n) and cofactor(h) too? - + { fieldIdentifier = fieldID.getIdentifier(); if (fieldIdentifier.equals(prime_field)) - { - BigInteger p = ((ASN1Integer)fieldID.getParameters()).getValue(); - X9FieldElement x9A = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(0)); - X9FieldElement x9B = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(1)); - curve = new ECCurve.Fp(p, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger()); + { + BigInteger p = ((ASN1Integer)fieldID.getParameters()).getValue(); + BigInteger A = new BigInteger(1, ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets()); + BigInteger B = new BigInteger(1, ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets()); + curve = new ECCurve.Fp(p, A, B, order, cofactor); } - else if (fieldIdentifier.equals(characteristic_two_field)) + else if (fieldIdentifier.equals(characteristic_two_field)) { // Characteristic two field ASN1Sequence parameters = ASN1Sequence.getInstance(fieldID.getParameters()); @@ -70,11 +69,11 @@ public class X9Curve int k2 = 0; int k3 = 0; - if (representation.equals(tpBasis)) + if (representation.equals(tpBasis)) { // Trinomial basis representation k1 = ASN1Integer.getInstance(parameters.getObjectAt(2)).getValue().intValue(); - } + } else if (representation.equals(ppBasis)) { // Pentanomial basis representation @@ -82,25 +81,25 @@ public class X9Curve k1 = ASN1Integer.getInstance(pentanomial.getObjectAt(0)).getValue().intValue(); k2 = ASN1Integer.getInstance(pentanomial.getObjectAt(1)).getValue().intValue(); k3 = ASN1Integer.getInstance(pentanomial.getObjectAt(2)).getValue().intValue(); - } + } else { throw new IllegalArgumentException("This type of EC basis is not implemented"); - } - X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(0)); - X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(1)); - curve = new ECCurve.F2m(m, k1, k2, k3, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger()); - } + } + BigInteger A = new BigInteger(1, ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets()); + BigInteger B = new BigInteger(1, ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets()); + curve = new ECCurve.F2m(m, k1, k2, k3, A, B, order, cofactor); + } else { throw new IllegalArgumentException("This type of ECCurve is not implemented"); - } + } if (seq.size() == 3) { - seed = ((DERBitString)seq.getObjectAt(2)).getBytes(); - } - } + seed = Arrays.clone(((DERBitString)seq.getObjectAt(2)).getBytes()); + } + } private void setFieldIdentifier() { @@ -125,7 +124,7 @@ public class X9Curve public byte[] getSeed() { - return seed; + return Arrays.clone(seed); } /** 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 85163651..f02404a9 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java @@ -13,6 +13,7 @@ import org.bouncycastle.math.ec.ECAlgorithms; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.field.PolynomialExtensionField; +import org.bouncycastle.util.Arrays; /** * ASN.1 def for Elliptic-Curve ECParameters structure. See @@ -35,34 +36,35 @@ public class X9ECParameters ASN1Sequence seq) { if (!(seq.getObjectAt(0) instanceof ASN1Integer) - || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE)) + || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE)) { throw new IllegalArgumentException("bad version in X9ECParameters"); } - X9Curve x9c = new X9Curve( - X9FieldID.getInstance(seq.getObjectAt(1)), - ASN1Sequence.getInstance(seq.getObjectAt(2))); + this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue(); + + if (seq.size() == 6) + { + this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue(); + } + + X9Curve x9c = new X9Curve( + X9FieldID.getInstance(seq.getObjectAt(1)), n, h, + ASN1Sequence.getInstance(seq.getObjectAt(2))); this.curve = x9c.getCurve(); Object p = seq.getObjectAt(3); if (p instanceof X9ECPoint) { - this.g = ((X9ECPoint)p); + this.g = (X9ECPoint)p; } else { this.g = new X9ECPoint(curve, (ASN1OctetString)p); } - this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue(); this.seed = x9c.getSeed(); - - if (seq.size() == 6) - { - this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue(); - } } public static X9ECParameters getInstance(Object obj) @@ -127,7 +129,7 @@ public class X9ECParameters this.g = g; this.n = n; this.h = h; - this.seed = seed; + this.seed = Arrays.clone(seed); if (ECAlgorithms.isFpCurve(curve)) { @@ -178,7 +180,7 @@ public class X9ECParameters public byte[] getSeed() { - return seed; + return Arrays.clone(seed); } /** diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java index 96130c6a..2dd8ff1c 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java @@ -1,5 +1,8 @@ package org.bouncycastle.asn1.x9; +/** + * A holding class that allows for X9ECParameters to be lazily constructed. + */ public abstract class X9ECParametersHolder { private X9ECParameters params; diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java index 95fdc672..b5037849 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java @@ -9,7 +9,7 @@ import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.util.Arrays; /** - * class for describing an ECPoint as a DER object. + * Class for describing an ECPoint as a DER object. */ public class X9ECPoint extends ASN1Object diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java index 13fe7721..4cba82de 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java @@ -22,17 +22,23 @@ public class X9FieldElement { this.f = f; } - + + /** + * @deprecated Will be removed + */ public X9FieldElement(BigInteger p, ASN1OctetString s) { this(new ECFieldElement.Fp(p, new BigInteger(1, s.getOctets()))); } - + + /** + * @deprecated Will be removed + */ public X9FieldElement(int m, int k1, int k2, int k3, ASN1OctetString s) { this(new ECFieldElement.F2m(m, k1, k2, k3, new BigInteger(1, s.getOctets()))); } - + public ECFieldElement getValue() { return f; 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 1317b4ab..ce6f86df 100644 --- a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java +++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java @@ -4,7 +4,7 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; /** * - * X9.62 + * Object identifiers for the various X9 standards. * <pre> * ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2) * us(840) ansi-x962(10045) } @@ -13,129 +13,129 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; public interface X9ObjectIdentifiers { /** Base OID: 1.2.840.10045 */ - static final ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045"); + ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045"); /** OID: 1.2.840.10045.1 */ - static final ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1"); + ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1"); /** OID: 1.2.840.10045.1.1 */ - static final ASN1ObjectIdentifier prime_field = id_fieldType.branch("1"); + ASN1ObjectIdentifier prime_field = id_fieldType.branch("1"); /** OID: 1.2.840.10045.1.2 */ - static final ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2"); + ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2"); /** OID: 1.2.840.10045.1.2.3.1 */ - static final ASN1ObjectIdentifier gnBasis = characteristic_two_field.branch("3.1"); + ASN1ObjectIdentifier gnBasis = characteristic_two_field.branch("3.1"); /** OID: 1.2.840.10045.1.2.3.2 */ - static final ASN1ObjectIdentifier tpBasis = characteristic_two_field.branch("3.2"); + ASN1ObjectIdentifier tpBasis = characteristic_two_field.branch("3.2"); /** OID: 1.2.840.10045.1.2.3.3 */ - static final ASN1ObjectIdentifier ppBasis = characteristic_two_field.branch("3.3"); + ASN1ObjectIdentifier ppBasis = characteristic_two_field.branch("3.3"); /** OID: 1.2.840.10045.4 */ - static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4"); + ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4"); /** OID: 1.2.840.10045.4.1 */ - static final ASN1ObjectIdentifier ecdsa_with_SHA1 = id_ecSigType.branch("1"); + ASN1ObjectIdentifier ecdsa_with_SHA1 = id_ecSigType.branch("1"); /** OID: 1.2.840.10045.2 */ - static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2"); + ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2"); /** OID: 1.2.840.10045.2.1 */ - static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1"); + ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1"); /** OID: 1.2.840.10045.4.3 */ - static final ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3"); + ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3"); /** OID: 1.2.840.10045.4.3.1 */ - static final ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1"); + ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1"); /** OID: 1.2.840.10045.4.3.2 */ - static final ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2"); + ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2"); /** OID: 1.2.840.10045.4.3.3 */ - static final ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3"); + ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3"); /** OID: 1.2.840.10045.4.3.4 */ - static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4"); + ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4"); /** * Named curves base * <p> * OID: 1.2.840.10045.3 */ - static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3"); + ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3"); /** * Two Curves * <p> * OID: 1.2.840.10045.3.0 */ - static final ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0"); + ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0"); /** Two Curve c2pnb163v1, OID: 1.2.840.10045.3.0.1 */ - static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1"); + ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1"); /** Two Curve c2pnb163v2, OID: 1.2.840.10045.3.0.2 */ - static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2"); + ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2"); /** Two Curve c2pnb163v3, OID: 1.2.840.10045.3.0.3 */ - static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3"); + ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3"); /** Two Curve c2pnb176w1, OID: 1.2.840.10045.3.0.4 */ - static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4"); + ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4"); /** Two Curve c2tnb191v1, OID: 1.2.840.10045.3.0.5 */ - static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5"); + ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5"); /** Two Curve c2tnb191v2, OID: 1.2.840.10045.3.0.6 */ - static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6"); + ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6"); /** Two Curve c2tnb191v3, OID: 1.2.840.10045.3.0.7 */ - static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7"); + ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7"); /** Two Curve c2onb191v4, OID: 1.2.840.10045.3.0.8 */ - static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8"); + ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8"); /** Two Curve c2onb191v5, OID: 1.2.840.10045.3.0.9 */ - static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9"); + ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9"); /** Two Curve c2pnb208w1, OID: 1.2.840.10045.3.0.10 */ - static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10"); + ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10"); /** Two Curve c2tnb239v1, OID: 1.2.840.10045.3.0.11 */ - static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11"); + ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11"); /** Two Curve c2tnb239v2, OID: 1.2.840.10045.3.0.12 */ - static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12"); + ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12"); /** Two Curve c2tnb239v3, OID: 1.2.840.10045.3.0.13 */ - static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13"); + ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13"); /** Two Curve c2onb239v4, OID: 1.2.840.10045.3.0.14 */ - static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14"); + ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14"); /** Two Curve c2onb239v5, OID: 1.2.840.10045.3.0.15 */ - static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15"); + ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15"); /** Two Curve c2pnb272w1, OID: 1.2.840.10045.3.0.16 */ - static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16"); + ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16"); /** Two Curve c2pnb304w1, OID: 1.2.840.10045.3.0.17 */ - static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17"); + ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17"); /** Two Curve c2tnb359v1, OID: 1.2.840.10045.3.0.18 */ - static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18"); + ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18"); /** Two Curve c2pnb368w1, OID: 1.2.840.10045.3.0.19 */ - static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19"); + ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19"); /** Two Curve c2tnb431r1, OID: 1.2.840.10045.3.0.20 */ - static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20"); + ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20"); /** * Prime Curves * <p> * OID: 1.2.840.10045.3.1 */ - static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1"); + ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1"); /** Prime Curve prime192v1, OID: 1.2.840.10045.3.1.1 */ - static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1"); + ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1"); /** Prime Curve prime192v2, OID: 1.2.840.10045.3.1.2 */ - static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2"); + ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2"); /** Prime Curve prime192v3, OID: 1.2.840.10045.3.1.3 */ - static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3"); + ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3"); /** Prime Curve prime239v1, OID: 1.2.840.10045.3.1.4 */ - static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4"); + ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4"); /** Prime Curve prime239v2, OID: 1.2.840.10045.3.1.5 */ - static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5"); + ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5"); /** Prime Curve prime239v3, OID: 1.2.840.10045.3.1.6 */ - static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6"); + ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6"); /** Prime Curve prime256v1, OID: 1.2.840.10045.3.1.7 */ - static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7"); + ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7"); /** * DSA @@ -145,7 +145,7 @@ public interface X9ObjectIdentifiers * </pre> * Base OID: 1.2.840.10040.4.1 */ - static final ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1"); + ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1"); /** * <pre> @@ -154,26 +154,26 @@ public interface X9ObjectIdentifiers * </pre> * OID: 1.2.840.10040.4.3 */ - static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3"); + ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3"); /** * X9.63 - Signature Specification * <p> * Base OID: 1.3.133.16.840.63.0 */ - static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0"); + ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0"); /** OID: 1.3.133.16.840.63.0.2 */ - static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2"); + ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2"); /** OID: 1.3.133.16.840.63.0.3 */ - static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3"); + ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3"); /** OID: 1.3.133.16.840.63.0.16 */ - static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16"); + ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16"); /** * X9.42 */ - static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046"); + ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046"); /** * Diffie-Hellman @@ -184,26 +184,26 @@ public interface X9ObjectIdentifiers * </pre> * OID: 1.2.840.10046.2.1 */ - static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1"); + ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1"); /** X9.42 schemas base OID: 1.2.840.10046.3 */ - static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3"); + ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3"); /** X9.42 dhStatic OID: 1.2.840.10046.3.1 */ - static final ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1"); + ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1"); /** X9.42 dhEphem OID: 1.2.840.10046.3.2 */ - static final ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2"); + ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2"); /** X9.42 dhOneFlow OID: 1.2.840.10046.3.3 */ - static final ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3"); + ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3"); /** X9.42 dhHybrid1 OID: 1.2.840.10046.3.4 */ - static final ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4"); + ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4"); /** X9.42 dhHybrid2 OID: 1.2.840.10046.3.5 */ - static final ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5"); + ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5"); /** X9.42 dhHybridOneFlow OID: 1.2.840.10046.3.6 */ - static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6"); + ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6"); /** X9.42 MQV2 OID: 1.2.840.10046.3.7 */ - static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7"); + ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7"); /** X9.42 MQV1 OID: 1.2.840.10046.3.8 */ - static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8"); + ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8"); /** * X9.44 diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/CryptoServicesPermission.java b/bcprov/src/main/java/org/bouncycastle/crypto/CryptoServicesPermission.java new file mode 100644 index 00000000..8a62a8df --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/CryptoServicesPermission.java @@ -0,0 +1,81 @@ +package org.bouncycastle.crypto; + +import java.security.Permission; +import java.util.HashSet; +import java.util.Set; + +/** + * Permissions that need to be configured if a SecurityManager is used. + */ +public class CryptoServicesPermission + extends Permission +{ + /** + * Enable the setting of global configuration properties. This permission implies THREAD_LOCAL_CONFIG + */ + public static final String GLOBAL_CONFIG = "globalConfig"; + + /** + * Enable the setting of thread local configuration properties. + */ + public static final String THREAD_LOCAL_CONFIG = "threadLocalConfig"; + + /** + * Enable the setting of the default SecureRandom. + */ + public static final String DEFAULT_RANDOM = "defaultRandomConfig"; + + private final Set<String> actions = new HashSet<String>(); + + public CryptoServicesPermission(String name) + { + super(name); + + this.actions.add(name); + } + + public boolean implies(Permission permission) + { + if (permission instanceof CryptoServicesPermission) + { + CryptoServicesPermission other = (CryptoServicesPermission)permission; + + if (this.getName().equals(other.getName())) + { + return true; + } + + if (this.actions.containsAll(other.actions)) + { + return true; + } + } + + return false; + } + + public boolean equals(Object obj) + { + if (obj instanceof CryptoServicesPermission) + { + CryptoServicesPermission other = (CryptoServicesPermission)obj; + + if (this.actions.equals(other.actions)) + { + return true; + } + } + + return false; + } + + public int hashCode() + { + return actions.hashCode(); + } + + public String getActions() + { + return actions.toString(); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/CryptoServicesRegistrar.java b/bcprov/src/main/java/org/bouncycastle/crypto/CryptoServicesRegistrar.java new file mode 100644 index 00000000..4448be04 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/CryptoServicesRegistrar.java @@ -0,0 +1,417 @@ +package org.bouncycastle.crypto; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.Permission; +import java.security.PrivilegedAction; +import java.security.SecureRandom; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.params.DHParameters; +import org.bouncycastle.crypto.params.DHValidationParameters; +import org.bouncycastle.crypto.params.DSAParameters; +import org.bouncycastle.crypto.params.DSAValidationParameters; +import org.bouncycastle.util.encoders.Hex; + +/** + * Basic registrar class for providing defaults for cryptography services in this module. + */ +public final class CryptoServicesRegistrar +{ + private static final Permission CanSetDefaultProperty = new CryptoServicesPermission(CryptoServicesPermission.GLOBAL_CONFIG); + private static final Permission CanSetThreadProperty = new CryptoServicesPermission(CryptoServicesPermission.THREAD_LOCAL_CONFIG); + private static final Permission CanSetDefaultRandom = new CryptoServicesPermission(CryptoServicesPermission.DEFAULT_RANDOM); + + private static final ThreadLocal<Map<String, Object[]>> threadProperties = new ThreadLocal<Map<String, Object[]>>(); + private static final Map<String, Object[]> globalProperties = Collections.synchronizedMap(new HashMap<String, Object[]>()); + + private static volatile SecureRandom defaultSecureRandom; + + static + { + // default domain parameters for DSA and Diffie-Hellman + + DSAParameters def512Params = new DSAParameters( + new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16), + new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16), + new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16), + new DSAValidationParameters(Hex.decode("b869c82b35d70e1b1ff91b28e37a62ecdc34409b"), 123)); + + DSAParameters def768Params = new DSAParameters( + new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5" + + "d890141922d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a" + + "22219d470bce7d777d4a21fbe9c270b57f607002f3cef8393694cf45" + + "ee3688c11a8c56ab127a3daf", 16), + new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", 16), + new BigInteger("30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7" + + "a31d23c4dbbcbe06174544401a5b2c020965d8c2bd2171d366844577" + + "1f74ba084d2029d83c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a" + + "7064f316933a346d3f529252", 16), + new DSAValidationParameters(Hex.decode("77d0f8c4dad15eb8c4f2f8d6726cefd96d5bb399"), 263)); + + DSAParameters def1024Params = new DSAParameters( + new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80" + + "b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b" + + "801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c6" + + "1bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675" + + "f3ae2b61d72aeff22203199dd14801c7", 16), + new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16), + new BigInteger("f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b" + + "3d0782675159578ebad4594fe67107108180b449167123e84c281613" + + "b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f" + + "0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06" + + "928b665e807b552564014c3bfecf492a", 16), + new DSAValidationParameters(Hex.decode("8d5155894229d5e689ee01e6018a237e2cae64cd"), 92)); + + DSAParameters def2048Params = new DSAParameters( + new BigInteger("95475cf5d93e596c3fcd1d902add02f427f5f3c7210313bb45fb4d5b" + + "b2e5fe1cbd678cd4bbdd84c9836be1f31c0777725aeb6c2fc38b85f4" + + "8076fa76bcd8146cc89a6fb2f706dd719898c2083dc8d896f84062e2" + + "c9c94d137b054a8d8096adb8d51952398eeca852a0af12df83e475aa" + + "65d4ec0c38a9560d5661186ff98b9fc9eb60eee8b030376b236bc73b" + + "e3acdbd74fd61c1d2475fa3077b8f080467881ff7e1ca56fee066d79" + + "506ade51edbb5443a563927dbc4ba520086746175c8885925ebc64c6" + + "147906773496990cb714ec667304e261faee33b3cbdf008e0c3fa906" + + "50d97d3909c9275bf4ac86ffcb3d03e6dfc8ada5934242dd6d3bcca2" + + "a406cb0b", 16), + new BigInteger("f8183668ba5fc5bb06b5981e6d8b795d30b8978d43ca0ec572e37e09939a9773", 16), + new BigInteger("42debb9da5b3d88cc956e08787ec3f3a09bba5f48b889a74aaf53174" + + "aa0fbe7e3c5b8fcd7a53bef563b0e98560328960a9517f4014d3325f" + + "c7962bf1e049370d76d1314a76137e792f3f0db859d095e4a5b93202" + + "4f079ecf2ef09c797452b0770e1350782ed57ddf794979dcef23cb96" + + "f183061965c4ebc93c9c71c56b925955a75f94cccf1449ac43d586d0" + + "beee43251b0b2287349d68de0d144403f13e802f4146d882e057af19" + + "b6f6275c6676c8fa0e3ca2713a3257fd1b27d0639f695e347d8d1cf9" + + "ac819a26ca9b04cb0eb9b7b035988d15bbac65212a55239cfc7e58fa" + + "e38d7250ab9991ffbc97134025fe8ce04c4399ad96569be91a546f49" + + "78693c7a", 16), + new DSAValidationParameters(Hex.decode("b0b4417601b59cbc9d8ac8f935cadaec4f5fbb2f23785609ae466748d9b5a536"), 497)); + + localSetGlobalProperty(Property.DSA_DEFAULT_PARAMS, def512Params, def768Params, def1024Params, def2048Params); + localSetGlobalProperty(Property.DH_DEFAULT_PARAMS, toDH(def512Params), toDH(def768Params), toDH(def1024Params), toDH(def2048Params)); + } + + private CryptoServicesRegistrar() + { + + } + + /** + * Return the default source of randomness. + * + * @return the default SecureRandom + * @throws IllegalStateException if no source of randomness has been provided. + */ + public static SecureRandom getSecureRandom() + { + if (defaultSecureRandom == null) + { + return new SecureRandom(); + } + + return defaultSecureRandom; + } + + /** + * Set a default secure random to be used where none is otherwise provided. + * + * @param secureRandom the SecureRandom to use as the default. + */ + public static void setSecureRandom(SecureRandom secureRandom) + { + checkPermission(CanSetDefaultRandom); + + defaultSecureRandom = secureRandom; + } + + /** + * Return the default value for a particular property if one exists. The look up is done on the thread's local + * configuration first and then on the global configuration in no local configuration exists. + * + * @param property the property to look up. + * @param <T> the type to be returned + * @return null if the property is not set, the default value otherwise, + */ + public static <T> T getProperty(Property property) + { + Object[] values = lookupProperty(property); + + if (values != null) + { + return (T)values[0]; + } + + return null; + } + + private static Object[] lookupProperty(Property property) + { + Map<String, Object[]> properties = threadProperties.get(); + Object[] values; + + if (properties == null || !properties.containsKey(property.name)) + { + values = globalProperties.get(property.name); + } + else + { + values = properties.get(property.name); + } + return values; + } + + /** + * Return an array representing the current values for a sized property such as DH_DEFAULT_PARAMS or + * DSA_DEFAULT_PARAMS. + * + * @param property the name of the property to look up. + * @param <T> the base type of the array to be returned. + * @return null if the property is not set, an array of the current values otherwise. + */ + public static <T> T[] getSizedProperty(Property property) + { + Object[] values = lookupProperty(property); + + if (values == null) + { + return null; + } + + return (T[])values.clone(); + } + + /** + * Return the value for a specific size for a sized property such as DH_DEFAULT_PARAMS or + * DSA_DEFAULT_PARAMS. + * + * @param property the name of the property to look up. + * @param size the size (in bits) of the defining value in the property type. + * @param <T> the type of the value to be returned. + * @return the current value for the size, null if there is no value set, + */ + public static <T> T getSizedProperty(Property property, int size) + { + Object[] values = lookupProperty(property); + + if (values == null) + { + return null; + } + + if (property.type.isAssignableFrom(DHParameters.class)) + { + for (int i = 0; i != values.length; i++) + { + DHParameters params = (DHParameters)values[i]; + + if (params.getP().bitLength() == size) + { + return (T)params; + } + } + } + else if (property.type.isAssignableFrom(DSAParameters.class)) + { + for (int i = 0; i != values.length; i++) + { + DSAParameters params = (DSAParameters)values[i]; + + if (params.getP().bitLength() == size) + { + return (T)params; + } + } + } + + return null; + } + + /** + * Set the value of the the passed in property on the current thread only. More than + * one value can be passed in for a sized property. If more than one value is provided the + * first value in the argument list becomes the default value. + * + * @param property the name of the property to set. + * @param propertyValue the values to assign to the property. + * @param <T> the base type of the property value. + */ + public static <T> void setThreadProperty(Property property, T... propertyValue) + { + checkPermission(CanSetThreadProperty); + + if (!property.type.isAssignableFrom(propertyValue[0].getClass())) + { + throw new IllegalArgumentException("Bad property value passed"); + } + + localSetThread(property, propertyValue.clone()); + } + + /** + * Set the value of the the passed in property globally in the JVM. More than + * one value can be passed in for a sized property. If more than one value is provided the + * first value in the argument list becomes the default value. + * + * @param property the name of the property to set. + * @param propertyValue the values to assign to the property. + * @param <T> the base type of the property value. + */ + public static <T> void setGlobalProperty(Property property, T... propertyValue) + { + checkPermission(CanSetDefaultProperty); + + localSetGlobalProperty(property, propertyValue.clone()); + } + + private static <T> void localSetThread(Property property, T[] propertyValue) + { + Map<String, Object[]> properties = threadProperties.get(); + + if (properties == null) + { + properties = new HashMap<String, Object[]>(); + threadProperties.set(properties); + } + + properties.put(property.name, propertyValue); + } + + private static <T> void localSetGlobalProperty(Property property, T... propertyValue) + { + if (!property.type.isAssignableFrom(propertyValue[0].getClass())) + { + throw new IllegalArgumentException("Bad property value passed"); + } + + // set the property for the current thread as well to avoid mass confusion + localSetThread(property, propertyValue); + + globalProperties.put(property.name, propertyValue); + } + + /** + * Clear the global value for the passed in property. + * + * @param property the property to be cleared. + * @param <T> the base type of the property value + * @return an array of T if a value was previously set, null otherwise. + */ + public static <T> T[] clearGlobalProperty(Property property) + { + checkPermission(CanSetDefaultProperty); + + // clear the property for the current thread as well to avoid confusion + localClearThreadProperty(property); + + return (T[])globalProperties.remove(property.name); + } + + /** + * Clear the thread local value for the passed in property. + * + * @param property the property to be cleared. + * @param <T> the base type of the property value + * @return an array of T if a value was previously set, null otherwise. + */ + public static <T> T[] clearThreadProperty(Property property) + { + checkPermission(CanSetThreadProperty); + + return (T[])localClearThreadProperty(property); + } + + private static Object[] localClearThreadProperty(Property property) + { + Map<String, Object[]> properties = threadProperties.get(); + + if (properties == null) + { + properties = new HashMap<String, Object[]>(); + threadProperties.set(properties); + } + + return properties.remove(property.name); + } + + private static void checkPermission(final Permission permission) + { + final SecurityManager securityManager = System.getSecurityManager(); + + if (securityManager != null) + { + AccessController.doPrivileged(new PrivilegedAction<Object>() + { + public Object run() + { + securityManager.checkPermission(permission); + + return null; + } + }); + } + } + + private static DHParameters toDH(DSAParameters dsaParams) + { + int pSize = dsaParams.getP().bitLength(); + int m = chooseLowerBound(pSize); + return new DHParameters(dsaParams.getP(), dsaParams.getG(), dsaParams.getQ(), m, 0, null, + new DHValidationParameters(dsaParams.getValidationParameters().getSeed(), dsaParams.getValidationParameters().getCounter())); + } + + // based on lower limit of at least 2^{2 * bits_of_security} + private static int chooseLowerBound(int pSize) + { + int m = 160; + if (pSize > 1024) + { + if (pSize <= 2048) + { + m = 224; + } + else if (pSize <= 3072) + { + m = 256; + } + else if (pSize <= 7680) + { + m = 384; + } + else + { + m = 512; + } + } + return m; + } + + /** + * Available properties that can be set. + */ + public static final class Property + { + /** + * The parameters to be used for processing implicitlyCA X9.62 parameters + */ + public static final Property EC_IMPLICITLY_CA = new Property("ecImplicitlyCA", X9ECParameters.class); + /** + * The default parameters for a particular size of Diffie-Hellman key.This is a sized property. + */ + public static final Property DH_DEFAULT_PARAMS= new Property("dhDefaultParams", DHParameters.class); + /** + * The default parameters for a particular size of DSA key. This is a sized property. + */ + public static final Property DSA_DEFAULT_PARAMS= new Property("dsaDefaultParams", DSAParameters.class); + private final String name; + private final Class type; + + private Property(String name, Class type) + { + this.name = name; + this.type = type; + } + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/DSAExt.java b/bcprov/src/main/java/org/bouncycastle/crypto/DSAExt.java new file mode 100644 index 00000000..b6099619 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/DSAExt.java @@ -0,0 +1,16 @@ +package org.bouncycastle.crypto; + +import java.math.BigInteger; + +/** + * An "extended" interface for classes implementing DSA-style algorithms, that provides access to + * the group order. + */ +public interface DSAExt + extends DSA +{ + /** + * Get the order of the group that the r, s values in signatures belong to. + */ + public BigInteger getOrder(); +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/RawAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/RawAgreement.java new file mode 100644 index 00000000..4bac34d1 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/RawAgreement.java @@ -0,0 +1,10 @@ +package org.bouncycastle.crypto; + +public interface RawAgreement +{ + void init(CipherParameters parameters); + + int getAgreementSize(); + + void calculateAgreement(CipherParameters publicKey, byte[] buf, int off); +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java index 09aadfbf..77d8ac91 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java @@ -32,15 +32,14 @@ public abstract class StreamBlockCipher public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException { - if (outOff + len > out.length) - { - throw new DataLengthException("output buffer too short"); - } - if (inOff + len > in.length) { throw new DataLengthException("input buffer too small"); } + if (outOff + len > out.length) + { + throw new OutputLengthException("output buffer too short"); + } int inStart = inOff; int inEnd = inOff + len; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java index 4dd80d0a..34908191 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java @@ -68,8 +68,16 @@ public class DHBasicAgreement throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters."); } - BigInteger result = pub.getY().modPow(key.getX(), dhParams.getP()); - if (result.compareTo(ONE) == 0) + BigInteger p = dhParams.getP(); + + BigInteger peerY = pub.getY(); + if (peerY == null || peerY.compareTo(ONE) <= 0 || peerY.compareTo(p.subtract(ONE)) >= 0) + { + throw new IllegalArgumentException("Diffie-Hellman public key is weak"); + } + + BigInteger result = peerY.modPow(key.getX(), p); + if (result.equals(ONE)) { throw new IllegalStateException("Shared key can't be 1"); } 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 45ff0d36..49a79c81 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java @@ -4,11 +4,11 @@ import java.math.BigInteger; import org.bouncycastle.crypto.BasicAgreement; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; -// BEGIN android-added -import org.bouncycastle.math.ec.ECCurve; -// END android-added +import org.bouncycastle.math.ec.ECAlgorithms; +import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECPoint; /** @@ -44,29 +44,30 @@ public class ECDHBasicAgreement public BigInteger calculateAgreement( CipherParameters pubKey) { - // BEGIN android-changed - ECPoint peerPoint = ((ECPublicKeyParameters) pubKey).getQ(); - ECCurve myCurve = key.getParameters().getCurve(); - if (peerPoint.isInfinity()) { - throw new IllegalStateException("Infinity is not a valid public key for ECDH"); - } - try { - myCurve.validatePoint(peerPoint.getXCoord().toBigInteger(), - peerPoint.getYCoord().toBigInteger()); - } catch (IllegalArgumentException ex) { - throw new IllegalStateException("The peer public key must be on the curve for ECDH"); - } - // Explicitly construct a public key using the private key's curve. - ECPoint pubPoint = myCurve.createPoint(peerPoint.getXCoord().toBigInteger(), - peerPoint.getYCoord().toBigInteger()); ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey; - if (!pub.getParameters().equals(key.getParameters())) + ECDomainParameters params = key.getParameters(); + if (!params.equals(pub.getParameters())) { throw new IllegalStateException("ECDH public key has wrong domain parameters"); } - ECPoint P = pubPoint.multiply(key.getD()).normalize(); - // END android-changed + BigInteger d = key.getD(); + + // Always perform calculations on the exact curve specified by our private key's parameters + ECPoint Q = ECAlgorithms.cleanPoint(params.getCurve(), pub.getQ()); + if (Q.isInfinity()) + { + throw new IllegalStateException("Infinity is not a valid public key for ECDH"); + } + + BigInteger h = params.getH(); + if (!h.equals(ECConstants.ONE)) + { + d = params.getHInv().multiply(d).mod(params.getN()); + Q = ECAlgorithms.referenceMultiply(Q, h); + } + + ECPoint P = Q.multiply(d).normalize(); if (P.isInfinity()) { throw new IllegalStateException("Infinity is not a valid agreement value for ECDH"); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/NullDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/NullDigest.java index 6cb0d4ac..9219d9df 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/NullDigest.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/NullDigest.java @@ -3,12 +3,13 @@ package org.bouncycastle.crypto.digests; import java.io.ByteArrayOutputStream; import org.bouncycastle.crypto.Digest; +import org.bouncycastle.util.Arrays; public class NullDigest implements Digest { - private ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + private OpenByteArrayOutputStream bOut = new OpenByteArrayOutputStream(); public String getAlgorithmName() { @@ -32,17 +33,33 @@ public class NullDigest public int doFinal(byte[] out, int outOff) { - byte[] res = bOut.toByteArray(); + int size = bOut.size(); - System.arraycopy(res, 0, out, outOff, res.length); + bOut.copy(out, outOff); reset(); - return res.length; + return size; } public void reset() { bOut.reset(); } + + private static class OpenByteArrayOutputStream + extends ByteArrayOutputStream + { + public void reset() + { + super.reset(); + + Arrays.clear(buf); + } + + void copy(byte[] out, int outOff) + { + System.arraycopy(buf, 0, out, outOff, this.size()); + } + } }
\ No newline at end of file diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java index b81e7c0a..4290d200 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java @@ -110,7 +110,7 @@ public class SHA1Digest } X[14] = (int)(bitLength >>> 32); - X[15] = (int)(bitLength & 0xffffffff); + X[15] = (int)bitLength; } public int doFinal( diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java b/bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java index 2c23bed1..006047cc 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java @@ -6,14 +6,17 @@ import java.util.Hashtable; import java.util.Vector; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers; +import org.bouncycastle.asn1.gm.GMObjectIdentifiers; import org.bouncycastle.asn1.sec.SECObjectIdentifiers; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ECParametersHolder; import org.bouncycastle.asn1.x9.X9ECPoint; import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.ECPoint; // BEGIN android-removed // import org.bouncycastle.math.ec.custom.djb.Curve25519; +// import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve; // import org.bouncycastle.math.ec.custom.sec.SecP128R1Curve; // import org.bouncycastle.math.ec.custom.sec.SecP160K1Curve; // import org.bouncycastle.math.ec.custom.sec.SecP160R1Curve; @@ -624,10 +627,25 @@ public class CustomNamedCurves return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; + + /* + * sm2p256v1 + * + static X9ECParametersHolder sm2p256v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = null; + ECCurve curve = configureCurve(new SM2P256V1Curve()); + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" + + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; */ // END Android-removed: Unsupported curves - static final Hashtable nameToCurve = new Hashtable(); static final Hashtable nameToOID = new Hashtable(); static final Hashtable oidToCurve = new Hashtable(); @@ -668,7 +686,7 @@ public class CustomNamedCurves { // BEGIN Android-removed: Unsupported curves /* - defineCurve("curve25519", curve25519); + defineCurveWithOID("curve25519", CryptlibObjectIdentifiers.curvey25519, curve25519); // defineCurveWithOID("secp112r1", SECObjectIdentifiers.secp112r1, secp112r1); // defineCurveWithOID("secp112r2", SECObjectIdentifiers.secp112r2, secp112r2); @@ -709,6 +727,8 @@ public class CustomNamedCurves defineCurveWithOID("sect571k1", SECObjectIdentifiers.sect571k1, sect571k1); defineCurveWithOID("sect571r1", SECObjectIdentifiers.sect571r1, sect571r1); + defineCurveWithOID("sm2p256v1", GMObjectIdentifiers.sm2p256v1, sm2p256v1); + defineCurveAlias("B-163", SECObjectIdentifiers.sect163r2); defineCurveAlias("B-233", SECObjectIdentifiers.sect233r1); defineCurveAlias("B-283", SECObjectIdentifiers.sect283r1); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java index 8df10697..417161e4 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java @@ -4,6 +4,7 @@ import java.security.SecureRandom; import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.InvalidCipherTextException; @@ -86,7 +87,7 @@ public class OAEPEncoding } else { - this.random = new SecureRandom(); + this.random = CryptoServicesRegistrar.getSecureRandom(); } engine.init(forEncryption, param); @@ -224,10 +225,17 @@ public class OAEPEncoding // on encryption, we need to make sure our decrypted block comes back // the same size. // + boolean wrongData = (block.length < (2 * defHash.length) + 1); - System.arraycopy(data, 0, block, block.length - data.length, data.length); - - boolean shortData = (block.length < (2 * defHash.length) + 1); + if (data.length <= block.length) + { + System.arraycopy(data, 0, block, block.length - data.length, data.length); + } + else + { + System.arraycopy(data, 0, block, 0, block.length); + wrongData = true; + } // // unmask the seed. @@ -281,7 +289,7 @@ public class OAEPEncoding start++; - if (defHashWrong | shortData | dataStartWrong) + if (defHashWrong | wrongData | dataStartWrong) { Arrays.fill(block, (byte)0); throw new InvalidCipherTextException("data wrong"); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java index e79557f4..cfd6dcf9 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java @@ -6,6 +6,7 @@ import java.security.SecureRandom; import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.ParametersWithRandom; @@ -141,7 +142,7 @@ public class PKCS1Encoding kParam = (AsymmetricKeyParameter)param; if (!kParam.isPrivate() && forEncryption) { - this.random = new SecureRandom(); + this.random = CryptoServicesRegistrar.getSecureRandom(); } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java index 6980fd08..58ea618b 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java @@ -5,6 +5,7 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.Pack; /** * a class that provides a basic DES engine. @@ -407,15 +408,8 @@ public class DESEngine { int work, right, left; - left = (in[inOff + 0] & 0xff) << 24; - left |= (in[inOff + 1] & 0xff) << 16; - left |= (in[inOff + 2] & 0xff) << 8; - left |= (in[inOff + 3] & 0xff); - - right = (in[inOff + 4] & 0xff) << 24; - right |= (in[inOff + 5] & 0xff) << 16; - right |= (in[inOff + 6] & 0xff) << 8; - right |= (in[inOff + 7] & 0xff); + left = Pack.bigEndianToInt(in, inOff); + right = Pack.bigEndianToInt(in, inOff + 4); work = ((left >>> 4) ^ right) & 0x0f0f0f0f; right ^= work; @@ -429,11 +423,11 @@ public class DESEngine work = ((right >>> 8) ^ left) & 0x00ff00ff; left ^= work; right ^= (work << 8); - right = ((right << 1) | ((right >>> 31) & 1)) & 0xffffffff; + right = (right << 1) | (right >>> 31); work = (left ^ right) & 0xaaaaaaaa; left ^= work; right ^= work; - left = ((left << 1) | ((left >>> 31) & 1)) & 0xffffffff; + left = (left << 1) | (left >>> 31); for (int round = 0; round < 8; round++) { @@ -483,13 +477,7 @@ public class DESEngine left ^= work; right ^= (work << 4); - out[outOff + 0] = (byte)((right >>> 24) & 0xff); - out[outOff + 1] = (byte)((right >>> 16) & 0xff); - out[outOff + 2] = (byte)((right >>> 8) & 0xff); - out[outOff + 3] = (byte)(right & 0xff); - out[outOff + 4] = (byte)((left >>> 24) & 0xff); - out[outOff + 5] = (byte)((left >>> 16) & 0xff); - out[outOff + 6] = (byte)((left >>> 8) & 0xff); - out[outOff + 7] = (byte)(left & 0xff); + Pack.intToBigEndian(right, out, outOff); + Pack.intToBigEndian(left, out, outOff + 4); } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java index 652d8ac8..76f20bbc 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java @@ -3,6 +3,7 @@ package org.bouncycastle.crypto.engines; import java.security.SecureRandom; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.Wrapper; @@ -79,7 +80,7 @@ public class DESedeWrapEngine } else { - sr = new SecureRandom(); + sr = CryptoServicesRegistrar.getSecureRandom(); } if (param instanceof KeyParameter) 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 d74e2b3c..65ac67bd 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java @@ -5,6 +5,7 @@ import java.security.SecureRandom; import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.params.RSAKeyParameters; @@ -45,7 +46,7 @@ public class RSABlindedEngine else { key = (RSAKeyParameters)param; - random = new SecureRandom(); + random = CryptoServicesRegistrar.getSecureRandom(); } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java index 510cd5a5..ca482d9b 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java @@ -1,12 +1,13 @@ package org.bouncycastle.crypto.engines; +import java.math.BigInteger; + import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; - -import java.math.BigInteger; +import org.bouncycastle.util.Arrays; /** * this does your basic RSA algorithm. @@ -142,20 +143,29 @@ class RSACoreEngine return tmp; } + + return output; } else { + byte[] rv; if (output[0] == 0) // have ended up with an extra zero byte, copy down. { - byte[] tmp = new byte[output.length - 1]; + rv = new byte[output.length - 1]; - System.arraycopy(output, 1, tmp, 0, tmp.length); + System.arraycopy(output, 1, rv, 0, rv.length); + } + else // maintain decryption time + { + rv = new byte[output.length]; - return tmp; + System.arraycopy(output, 0, rv, 0, rv.length); } - } - return output; + Arrays.fill(output, (byte)0); + + return rv; + } } public BigInteger processBlock(BigInteger input) diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java index 6795ec96..17d9403b 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java @@ -27,7 +27,7 @@ class DHKeyGeneratorHelper int minWeight = limit >>> 2; for (;;) { - BigInteger x = new BigInteger(limit, random).setBit(limit - 1); + BigInteger x = BigIntegers.createRandomBigInteger(limit, random).setBit(limit - 1); if (WNafUtil.getNafWeight(x) >= minWeight) { return x; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java index f5d42642..9b7bb863 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java @@ -1,10 +1,10 @@ package org.bouncycastle.crypto.generators; -import org.bouncycastle.crypto.params.DHParameters; - import java.math.BigInteger; import java.security.SecureRandom; +import org.bouncycastle.crypto.params.DHParameters; + public class DHParametersGenerator { private int size; @@ -35,6 +35,7 @@ public class DHParametersGenerator * returning the DHParameters object. * <p> * Note: can take a while... + * @return a generated Diffie-Hellman parameters object. */ public DHParameters generateParameters() { diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java index 1075f22e..c857af1e 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java @@ -36,7 +36,7 @@ class DHParametersHelper { // Android-added: Log long-running operation tries++; - q = new BigInteger(qLength, 2, random); + q = BigIntegers.createRandomPrime(qLength, 2, random); // p <- 2q + 1 p = q.shiftLeft(1).add(ONE); 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 961b367d..cb09f73f 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java @@ -113,6 +113,7 @@ public class DSAParametersGenerator * returning the DSAParameters object. * <p> * Note: can take a while... + * @return a generated DSA parameters object. */ public DSAParameters generateParameters() { 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 c7660719..502f8b3e 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java @@ -5,6 +5,7 @@ import java.security.SecureRandom; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.KeyGenerationParameters; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyGenerationParameters; @@ -15,6 +16,7 @@ import org.bouncycastle.math.ec.ECMultiplier; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.FixedPointCombMultiplier; import org.bouncycastle.math.ec.WNafUtil; +import org.bouncycastle.util.BigIntegers; public class ECKeyPairGenerator implements AsymmetricCipherKeyPairGenerator, ECConstants @@ -32,7 +34,7 @@ public class ECKeyPairGenerator if (this.random == null) { - this.random = new SecureRandom(); + this.random = CryptoServicesRegistrar.getSecureRandom(); } } @@ -49,7 +51,7 @@ public class ECKeyPairGenerator BigInteger d; for (;;) { - d = new BigInteger(nBitLength, random); + d = BigIntegers.createRandomBigInteger(nBitLength, random); if (d.compareTo(TWO) < 0 || (d.compareTo(n) >= 0)) { diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java index beb1aee2..eadbaa6c 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java @@ -10,6 +10,7 @@ import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import org.bouncycastle.math.Primes; import org.bouncycastle.math.ec.WNafUtil; +import org.bouncycastle.util.BigIntegers; /** * an RSA key pair generator. @@ -159,7 +160,7 @@ public class RSAKeyPairGenerator { for (int i = 0; i != 5 * bitlength; i++) { - BigInteger p = new BigInteger(bitlength, 1, param.getRandom()); + BigInteger p = BigIntegers.createRandomPrime(bitlength, 1, param.getRandom()); if (p.mod(e).equals(ONE)) { diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java index 64b076dd..ea807067 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java @@ -4,6 +4,7 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.StreamBlockCipher; /** @@ -135,7 +136,7 @@ public class CTSBlockCipher { if ((outOff + length) > out.length) { - throw new DataLengthException("output buffer too short"); + throw new OutputLengthException("output buffer too short"); } } @@ -192,7 +193,7 @@ public class CTSBlockCipher { if (bufOff + outOff > out.length) { - throw new DataLengthException("output buffer to small in doFinal"); + throw new OutputLengthException("output buffer to small in doFinal"); } int blockSize = cipher.getBlockSize(); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java index c6453a3b..75343d8b 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java @@ -5,11 +5,11 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.crypto.modes.gcm.BasicGCMExponentiator; import org.bouncycastle.crypto.modes.gcm.GCMExponentiator; import org.bouncycastle.crypto.modes.gcm.GCMMultiplier; import org.bouncycastle.crypto.modes.gcm.GCMUtil; -import org.bouncycastle.crypto.modes.gcm.Tables1kGCMExponentiator; -import org.bouncycastle.crypto.modes.gcm.Tables8kGCMMultiplier; +import org.bouncycastle.crypto.modes.gcm.Tables4kGCMMultiplier; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; @@ -73,8 +73,7 @@ public class GCMBlockCipher if (m == null) { - // TODO Consider a static property specifying default multiplier - m = new Tables8kGCMMultiplier(); + m = new Tables4kGCMMultiplier(); } this.cipher = c; @@ -268,6 +267,7 @@ public class GCMBlockCipher throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes"); } // END Android-added: Max input size limitation from NIST. + atBlock[atBlockPos] = in; if (++atBlockPos == BLOCK_SIZE) { @@ -280,11 +280,13 @@ public class GCMBlockCipher public void processAADBytes(byte[] in, int inOff, int len) { + checkStatus(); // BEGIN Android-added: Max input size limitation from NIST. if (getTotalInputSizeAfterNewInput(len) > MAX_INPUT_SIZE) { throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes"); } // END Android-added: Max input size limitation from NIST. + for (int i = 0; i < len; ++i) { atBlock[atBlockPos] = in[inOff + i]; @@ -328,11 +330,20 @@ public class GCMBlockCipher throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes"); } // END Android-added: Max input size limitation from NIST. - + bufBlock[bufOff] = in; if (++bufOff == bufBlock.length) { - outputBlock(out, outOff); + processBlock(bufBlock, 0, out, outOff); + if (forEncryption) + { + bufOff = 0; + } + else + { + System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize); + bufOff = macSize; + } return BLOCK_SIZE; } return 0; @@ -348,45 +359,61 @@ public class GCMBlockCipher } // END Android-added: Max input size limitation from NIST. - if (in.length < (inOff + len)) + if ((in.length - inOff) < len) { throw new DataLengthException("Input buffer too short"); } + int resultLen = 0; - for (int i = 0; i < len; ++i) + if (forEncryption) { - bufBlock[bufOff] = in[inOff + i]; - if (++bufOff == bufBlock.length) + if (bufOff != 0) { - outputBlock(out, outOff + resultLen); - resultLen += BLOCK_SIZE; + while (len > 0) + { + --len; + bufBlock[bufOff] = in[inOff++]; + if (++bufOff == BLOCK_SIZE) + { + processBlock(bufBlock, 0, out, outOff); + bufOff = 0; + resultLen += BLOCK_SIZE; + break; + } + } } - } - return resultLen; - } + while (len >= BLOCK_SIZE) + { + processBlock(in, inOff, out, outOff + resultLen); + inOff += BLOCK_SIZE; + len -= BLOCK_SIZE; + resultLen += BLOCK_SIZE; + } - private void outputBlock(byte[] output, int offset) - { - if (output.length < (offset + BLOCK_SIZE)) - { - throw new OutputLengthException("Output buffer too short"); - } - if (totalLength == 0) - { - initCipher(); - } - gCTRBlock(bufBlock, output, offset); - if (forEncryption) - { - bufOff = 0; + if (len > 0) + { + System.arraycopy(in, inOff, bufBlock, 0, len); + bufOff = len; + } } else { - System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize); - bufOff = macSize; + for (int i = 0; i < len; ++i) + { + bufBlock[bufOff] = in[inOff + i]; + if (++bufOff == bufBlock.length) + { + processBlock(bufBlock, 0, out, outOff + resultLen); + System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize); + bufOff = macSize; + resultLen += BLOCK_SIZE; + } + } } + + return resultLen; } public int doFinal(byte[] out, int outOff) @@ -403,7 +430,7 @@ public class GCMBlockCipher if (forEncryption) { - if (out.length < (outOff + extra + macSize)) + if ((out.length - outOff) < (extra + macSize)) { throw new OutputLengthException("Output buffer too short"); } @@ -416,7 +443,7 @@ public class GCMBlockCipher } extra -= macSize; - if (out.length < (outOff + extra)) + if ((out.length - outOff) < extra) { throw new OutputLengthException("Output buffer too short"); } @@ -424,7 +451,7 @@ public class GCMBlockCipher if (extra > 0) { - gCTRPartial(bufBlock, 0, extra, out, outOff); + processPartial(bufBlock, 0, extra, out, outOff); } atLength += atBlockPos; @@ -457,7 +484,7 @@ public class GCMBlockCipher byte[] H_c = new byte[16]; if (exp == null) { - exp = new Tables1kGCMExponentiator(); + exp = new BasicGCMExponentiator(); exp.init(H); } exp.exponentiateX(c, H_c); @@ -556,27 +583,52 @@ public class GCMBlockCipher } } - private void gCTRBlock(byte[] block, byte[] out, int outOff) + private void processBlock(byte[] buf, int bufOff, byte[] out, int outOff) { - byte[] tmp = getNextCounterBlock(); + if ((out.length - outOff) < BLOCK_SIZE) + { + throw new OutputLengthException("Output buffer too short"); + } + if (totalLength == 0) + { + initCipher(); + } - GCMUtil.xor(tmp, block); - System.arraycopy(tmp, 0, out, outOff, BLOCK_SIZE); + byte[] ctrBlock = new byte[BLOCK_SIZE]; + getNextCTRBlock(ctrBlock); - gHASHBlock(S, forEncryption ? tmp : block); + if (forEncryption) + { + GCMUtil.xor(ctrBlock, buf, bufOff); + gHASHBlock(S, ctrBlock); + System.arraycopy(ctrBlock, 0, out, outOff, BLOCK_SIZE); + } + else + { + gHASHBlock(S, buf, bufOff); + GCMUtil.xor(ctrBlock, 0, buf, bufOff, out, outOff); + } totalLength += BLOCK_SIZE; } - private void gCTRPartial(byte[] buf, int off, int len, byte[] out, int outOff) + private void processPartial(byte[] buf, int off, int len, byte[] out, int outOff) { - byte[] tmp = getNextCounterBlock(); + byte[] ctrBlock = new byte[BLOCK_SIZE]; + getNextCTRBlock(ctrBlock); - GCMUtil.xor(tmp, buf, off, len); - System.arraycopy(tmp, 0, out, outOff, len); - - gHASHPartial(S, forEncryption ? tmp : buf, 0, len); + if (forEncryption) + { + GCMUtil.xor(buf, off, ctrBlock, 0, len); + gHASHPartial(S, buf, off, len); + } + else + { + gHASHPartial(S, buf, off, len); + GCMUtil.xor(buf, off, ctrBlock, 0, len); + } + System.arraycopy(buf, off, out, outOff, len); totalLength += len; } @@ -595,13 +647,19 @@ public class GCMBlockCipher multiplier.multiplyH(Y); } + private void gHASHBlock(byte[] Y, byte[] b, int off) + { + GCMUtil.xor(Y, b, off); + multiplier.multiplyH(Y); + } + private void gHASHPartial(byte[] Y, byte[] b, int off, int len) { GCMUtil.xor(Y, b, off, len); multiplier.multiplyH(Y); } - private byte[] getNextCounterBlock() + private void getNextCTRBlock(byte[] block) { if (blocksRemaining == 0) { @@ -615,10 +673,7 @@ public class GCMBlockCipher c += counter[13] & 0xFF; counter[13] = (byte)c; c >>>= 8; c += counter[12] & 0xFF; counter[12] = (byte)c; - byte[] tmp = new byte[BLOCK_SIZE]; - // TODO Sure would be nice if ciphers could operate on int[] - cipher.processBlock(counter, 0, tmp, 0); - return tmp; + cipher.processBlock(counter, 0, block, 0); } private void checkStatus() diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java new file mode 100644 index 00000000..7316a04b --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/BasicGCMExponentiator.java @@ -0,0 +1,37 @@ +package org.bouncycastle.crypto.modes.gcm; + +import org.bouncycastle.util.Arrays; + +public class BasicGCMExponentiator + implements GCMExponentiator +{ + private long[] x; + + public void init(byte[] x) + { + this.x = GCMUtil.asLongs(x); + } + + public void exponentiateX(long pow, byte[] output) + { + // Initial value is little-endian 1 + long[] y = GCMUtil.oneAsLongs(); + + if (pow > 0) + { + long[] powX = Arrays.clone(x); + do + { + if ((pow & 1L) != 0) + { + GCMUtil.multiply(y, powX); + } + GCMUtil.square(powX, powX); + pow >>>= 1; + } + while (pow > 0); + } + + GCMUtil.asBytes(y, output); + } +} 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 f08f71f3..3e24a15f 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 @@ -1,5 +1,6 @@ package org.bouncycastle.crypto.modes.gcm; +import org.bouncycastle.math.raw.Interleave; import org.bouncycastle.util.Pack; public abstract class GCMUtil @@ -7,28 +8,6 @@ public abstract class GCMUtil private static final int E1 = 0xe1000000; private static final long E1L = (E1 & 0xFFFFFFFFL) << 32; - 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(); - public static byte[] oneAsBytes() { byte[] tmp = new byte[16]; @@ -98,216 +77,214 @@ public abstract class GCMUtil Pack.bigEndianToLong(x, 0, z); } + public static void copy(int[] x, int[] z) + { + z[0] = x[0]; + z[1] = x[1]; + z[2] = x[2]; + z[3] = x[3]; + } + + public static void copy(long[] x, long[] z) + { + z[0] = x[0]; + z[1] = x[1]; + } + + public static void divideP(long[] x, long[] z) + { + long x0 = x[0], x1 = x[1]; + long m = x0 >> 63; + x0 ^= (m & E1L); + z[0] = (x0 << 1) | (x1 >>> 63); + z[1] = (x1 << 1) | -m; + } + public static void multiply(byte[] x, byte[] y) { - int[] t1 = GCMUtil.asInts(x); - int[] t2 = GCMUtil.asInts(y); + long[] t1 = GCMUtil.asLongs(x); + long[] t2 = GCMUtil.asLongs(y); GCMUtil.multiply(t1, t2); GCMUtil.asBytes(t1, x); } public static void multiply(int[] x, int[] y) { - int r00 = x[0], r01 = x[1], r02 = x[2], r03 = x[3]; - int r10 = 0, r11 = 0, r12 = 0, r13 = 0; - + int y0 = y[0], y1 = y[1], y2 = y[2], y3 = y[3]; + int z0 = 0, z1 = 0, z2 = 0, z3 = 0; + for (int i = 0; i < 4; ++i) { - int bits = y[i]; + int bits = x[i]; for (int j = 0; j < 32; ++j) { int m1 = bits >> 31; bits <<= 1; - r10 ^= (r00 & m1); - r11 ^= (r01 & m1); - r12 ^= (r02 & m1); - r13 ^= (r03 & m1); - - int m2 = (r03 << 31) >> 8; - r03 = (r03 >>> 1) | (r02 << 31); - r02 = (r02 >>> 1) | (r01 << 31); - r01 = (r01 >>> 1) | (r00 << 31); - r00 = (r00 >>> 1) ^ (m2 & E1); + z0 ^= (y0 & m1); + z1 ^= (y1 & m1); + z2 ^= (y2 & m1); + z3 ^= (y3 & m1); + + int m2 = (y3 << 31) >> 8; + y3 = (y3 >>> 1) | (y2 << 31); + y2 = (y2 >>> 1) | (y1 << 31); + y1 = (y1 >>> 1) | (y0 << 31); + y0 = (y0 >>> 1) ^ (m2 & E1); } } - x[0] = r10; - x[1] = r11; - x[2] = r12; - x[3] = r13; + x[0] = z0; + x[1] = z1; + x[2] = z2; + x[3] = z3; } public static void multiply(long[] x, long[] y) { - long r00 = x[0], r01 = x[1], r10 = 0, r11 = 0; + long x0 = x[0], x1 = x[1]; + long y0 = y[0], y1 = y[1]; + long z0 = 0, z1 = 0, z2 = 0; - for (int i = 0; i < 2; ++i) + for (int j = 0; j < 64; ++j) { - long bits = y[i]; - for (int j = 0; j < 64; ++j) - { - long m1 = bits >> 63; bits <<= 1; - r10 ^= (r00 & m1); - r11 ^= (r01 & m1); + long m0 = x0 >> 63; x0 <<= 1; + z0 ^= (y0 & m0); + z1 ^= (y1 & m0); - long m2 = (r01 << 63) >> 8; - r01 = (r01 >>> 1) | (r00 << 63); - r00 = (r00 >>> 1) ^ (m2 & E1L); - } + long m1 = x1 >> 63; x1 <<= 1; + z1 ^= (y0 & m1); + z2 ^= (y1 & m1); + + long c = (y1 << 63) >> 8; + y1 = (y1 >>> 1) | (y0 << 63); + y0 = (y0 >>> 1) ^ (c & E1L); } - x[0] = r10; - x[1] = r11; + z0 ^= z2 ^ (z2 >>> 1) ^ (z2 >>> 2) ^ (z2 >>> 7); + z1 ^= (z2 << 63) ^ (z2 << 62) ^ (z2 << 57); + + x[0] = z0; + x[1] = z1; } - // P is the value with only bit i=1 set public static void multiplyP(int[] x) { - int m = shiftRight(x) >> 8; - x[0] ^= (m & E1); + int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3]; + int m = (x3 << 31) >> 31; + x[0] = (x0 >>> 1) ^ (m & E1); + x[1] = (x1 >>> 1) | (x0 << 31); + x[2] = (x2 >>> 1) | (x1 << 31); + x[3] = (x3 >>> 1) | (x2 << 31); } public static void multiplyP(int[] x, int[] z) { - int m = shiftRight(x, z) >> 8; - z[0] ^= (m & E1); + int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3]; + int m = (x3 << 31) >> 31; + z[0] = (x0 >>> 1) ^ (m & E1); + z[1] = (x1 >>> 1) | (x0 << 31); + z[2] = (x2 >>> 1) | (x1 << 31); + z[3] = (x3 >>> 1) | (x2 << 31); } - // P is the value with only bit i=1 set - public static void multiplyP8(int[] x) + public static void multiplyP(long[] x) + { + long x0 = x[0], x1 = x[1]; + long m = (x1 << 63) >> 63; + x[0] = (x0 >>> 1) ^ (m & E1L); + x[1] = (x1 >>> 1) | (x0 << 63); + } + + public static void multiplyP(long[] x, long[] z) + { + long x0 = x[0], x1 = x[1]; + long m = (x1 << 63) >> 63; + z[0] = (x0 >>> 1) ^ (m & E1L); + z[1] = (x1 >>> 1) | (x0 << 63); + } + + public static void multiplyP3(long[] x, long[] z) + { + long x0 = x[0], x1 = x[1]; + long c = x1 << 61; + z[0] = (x0 >>> 3) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7); + z[1] = (x1 >>> 3) | (x0 << 61); + } + + public static void multiplyP4(long[] x, long[] z) + { + long x0 = x[0], x1 = x[1]; + long c = x1 << 60; + z[0] = (x0 >>> 4) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7); + z[1] = (x1 >>> 4) | (x0 << 60); + } + + public static void multiplyP7(long[] x, long[] z) { -// for (int i = 8; i != 0; --i) -// { -// multiplyP(x); -// } + long x0 = x[0], x1 = x[1]; + long c = x1 << 57; + z[0] = (x0 >>> 7) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7); + z[1] = (x1 >>> 7) | (x0 << 57); + } - int c = shiftRightN(x, 8); - x[0] ^= LOOKUP[c >>> 24]; + public static void multiplyP8(int[] x) + { + int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3]; + int c = x3 << 24; + x[0] = (x0 >>> 8) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7); + x[1] = (x1 >>> 8) | (x0 << 24); + x[2] = (x2 >>> 8) | (x1 << 24); + x[3] = (x3 >>> 8) | (x2 << 24); } public static void multiplyP8(int[] x, int[] y) { - int c = shiftRightN(x, 8, y); - y[0] ^= LOOKUP[c >>> 24]; - } - - static int shiftRight(int[] x) - { -// 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 int shiftRight(int[] x, int[] z) - { -// 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 long shiftRight(long[] x) - { - 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 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; + int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3]; + int c = x3 << 24; + y[0] = (x0 >>> 8) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7); + y[1] = (x1 >>> 8) | (x0 << 24); + y[2] = (x2 >>> 8) | (x1 << 24); + y[3] = (x3 >>> 8) | (x2 << 24); + } + + public static void multiplyP8(long[] x) + { + long x0 = x[0], x1 = x[1]; + long c = x1 << 56; + x[0] = (x0 >>> 8) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7); + x[1] = (x1 >>> 8) | (x0 << 56); + } + + public static void multiplyP8(long[] x, long[] y) + { + long x0 = x[0], x1 = x[1]; + long c = x1 << 56; + y[0] = (x0 >>> 8) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7); + y[1] = (x1 >>> 8) | (x0 << 56); + } + + public static long[] pAsLongs() + { + long[] tmp = new long[2]; + tmp[0] = 1L << 62; + return tmp; + } + + public static void square(long[] x, long[] z) + { + long[] t = new long[4]; + Interleave.expand64To128Rev(x[0], t, 0); + Interleave.expand64To128Rev(x[1], t, 2); + + long z0 = t[0], z1 = t[1], z2 = t[2], z3 = t[3]; + + z1 ^= z3 ^ (z3 >>> 1) ^ (z3 >>> 2) ^ (z3 >>> 7); + z2 ^= (z3 << 63) ^ (z3 << 62) ^ (z3 << 57); + + z0 ^= z2 ^ (z2 >>> 1) ^ (z2 >>> 2) ^ (z2 >>> 7); + z1 ^= (z2 << 63) ^ (z2 << 62) ^ (z2 << 57); + + z[0] = z0; + z[1] = z1; } public static void xor(byte[] x, byte[] y) @@ -323,6 +300,32 @@ public abstract class GCMUtil while (i < 16); } + public static void xor(byte[] x, byte[] y, int yOff) + { + int i = 0; + do + { + x[i] ^= y[yOff + i]; ++i; + x[i] ^= y[yOff + i]; ++i; + x[i] ^= y[yOff + i]; ++i; + x[i] ^= y[yOff + i]; ++i; + } + while (i < 16); + } + + public static void xor(byte[] x, int xOff, byte[] y, int yOff, byte[] z, int zOff) + { + int i = 0; + do + { + z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i; + z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i; + z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i; + z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i; + } + while (i < 16); + } + public static void xor(byte[] x, byte[] y, int yOff, int yLen) { while (--yLen >= 0) @@ -331,6 +334,14 @@ public abstract class GCMUtil } } + public static void xor(byte[] x, int xOff, byte[] y, int yOff, int len) + { + while (--len >= 0) + { + x[xOff + len] ^= y[yOff + len]; + } + } + public static void xor(byte[] x, byte[] y, byte[] z) { int i = 0; 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 6eff4e3f..b8766bd7 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 @@ -4,7 +4,8 @@ import java.util.Vector; import org.bouncycastle.util.Arrays; -public class Tables1kGCMExponentiator implements GCMExponentiator +public class Tables1kGCMExponentiator + implements GCMExponentiator { // A lookup table of the power-of-two powers of 'x' // - lookupPowX2[i] = x^(2^i) @@ -12,8 +13,8 @@ public class Tables1kGCMExponentiator implements GCMExponentiator public void init(byte[] x) { - int[] y = GCMUtil.asInts(x); - if (lookupPowX2 != null && Arrays.areEqual(y, (int[])lookupPowX2.elementAt(0))) + long[] y = GCMUtil.asLongs(x); + if (lookupPowX2 != null && Arrays.areEqual(y, (long[])lookupPowX2.elementAt(0))) { return; } @@ -24,14 +25,14 @@ public class Tables1kGCMExponentiator implements GCMExponentiator public void exponentiateX(long pow, byte[] output) { - int[] y = GCMUtil.oneAsInts(); + long[] y = GCMUtil.oneAsLongs(); int bit = 0; while (pow > 0) { if ((pow & 1L) != 0) { ensureAvailable(bit); - GCMUtil.multiply(y, (int[])lookupPowX2.elementAt(bit)); + GCMUtil.multiply(y, (long[])lookupPowX2.elementAt(bit)); } ++bit; pow >>>= 1; @@ -45,11 +46,11 @@ public class Tables1kGCMExponentiator implements GCMExponentiator int count = lookupPowX2.size(); if (count <= bit) { - int[] tmp = (int[])lookupPowX2.elementAt(count - 1); + long[] tmp = (long[])lookupPowX2.elementAt(count - 1); do { tmp = Arrays.clone(tmp); - GCMUtil.multiply(tmp, tmp); + GCMUtil.square(tmp, tmp); lookupPowX2.addElement(tmp); } while (++count <= bit); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables4kGCMMultiplier.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables4kGCMMultiplier.java new file mode 100644 index 00000000..e5ea7483 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables4kGCMMultiplier.java @@ -0,0 +1,67 @@ +package org.bouncycastle.crypto.modes.gcm; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; + +public class Tables4kGCMMultiplier + implements GCMMultiplier +{ + private byte[] H; + private long[][] T; + + public void init(byte[] H) + { + if (T == null) + { + T = new long[256][2]; + } + else if (Arrays.areEqual(this.H, H)) + { + return; + } + + this.H = Arrays.clone(H); + + // T[0] = 0 + + // T[1] = H.p^7 + GCMUtil.asLongs(this.H, T[1]); + GCMUtil.multiplyP7(T[1], T[1]); + + for (int n = 2; n < 256; n += 2) + { + // T[2.n] = T[n].p^-1 + GCMUtil.divideP(T[n >> 1], T[n]); + + // T[2.n + 1] = T[2.n] + T[1] + GCMUtil.xor(T[n], T[1], T[n + 1]); + } + } + + public void multiplyH(byte[] x) + { +// long[] z = new long[2]; +// GCMUtil.copy(T[x[15] & 0xFF], z); +// for (int i = 14; i >= 0; --i) +// { +// GCMUtil.multiplyP8(z); +// GCMUtil.xor(z, T[x[i] & 0xFF]); +// } +// Pack.longToBigEndian(z, x, 0); + + long[] t = T[x[15] & 0xFF]; + long z0 = t[0], z1 = t[1]; + + for (int i = 14; i >= 0; --i) + { + t = T[x[i] & 0xFF]; + + long c = z1 << 56; + z1 = t[1] ^ ((z1 >>> 8) | (z0 << 56)); + z0 = t[0] ^ (z0 >>> 8) ^ c ^ (c >>> 1) ^ (c >>> 2) ^ (c >>> 7); + } + + Pack.longToBigEndian(z0, x, 0); + Pack.longToBigEndian(z1, x, 8); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java index 69c1dce8..6c3ae26c 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java @@ -3,16 +3,17 @@ package org.bouncycastle.crypto.modes.gcm; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; -public class Tables8kGCMMultiplier implements GCMMultiplier +public class Tables8kGCMMultiplier + implements GCMMultiplier { private byte[] H; - private int[][][] M; + private long[][][] T; public void init(byte[] H) { - if (M == null) + if (T == null) { - M = new int[32][16][4]; + T = new long[32][16][2]; } else if (Arrays.areEqual(this.H, H)) { @@ -21,70 +22,58 @@ public class Tables8kGCMMultiplier implements GCMMultiplier this.H = Arrays.clone(H); - // M[0][0] is ZEROES; - // M[1][0] is ZEROES; - GCMUtil.asInts(H, M[1][8]); - - for (int j = 4; j >= 1; j >>= 1) + for (int i = 0; i < 32; ++i) { - GCMUtil.multiplyP(M[1][j + j], M[1][j]); - } - - GCMUtil.multiplyP(M[1][1], M[0][8]); + long[][] t = T[i]; - for (int j = 4; j >= 1; j >>= 1) - { - GCMUtil.multiplyP(M[0][j + j], M[0][j]); - } + // t[0] = 0 - int i = 0; - for (;;) - { - for (int j = 2; j < 16; j += j) + if (i == 0) { - for (int k = 1; k < j; ++k) - { - GCMUtil.xor(M[i][j], M[i][k], M[i][j + k]); - } + // t[1] = H.p^3 + GCMUtil.asLongs(this.H, t[1]); + GCMUtil.multiplyP3(t[1], t[1]); } - - if (++i == 32) + else { - return; + // t[1] = T[i-1][1].p^4 + GCMUtil.multiplyP4(T[i - 1][1], t[1]); } - if (i > 1) + for (int n = 2; n < 16; n += 2) { - // M[i][0] is ZEROES; - for(int j = 8; j > 0; j >>= 1) - { - GCMUtil.multiplyP8(M[i - 2][j], M[i][j]); - } + // t[2.n] = t[n].p^-1 + GCMUtil.divideP(t[n >> 1], t[n]); + + // t[2.n + 1] = t[2.n] + t[1] + GCMUtil.xor(t[n], t[1], t[n + 1]); } } + } public void multiplyH(byte[] x) { -// assert x.Length == 16; +// long[] z = new long[2]; +// for (int i = 15; i >= 0; --i) +// { +// GCMUtil.xor(z, T[i + i + 1][(x[i] & 0x0F)]); +// GCMUtil.xor(z, T[i + i ][(x[i] & 0xF0) >>> 4]); +// } +// Pack.longToBigEndian(z, x, 0); + + long z0 = 0, z1 = 0; - int[] z = new int[4]; for (int i = 15; i >= 0; --i) { -// GCMUtil.xor(z, M[i + i][x[i] & 0x0f]); - int[] m = M[i + i][x[i] & 0x0f]; - z[0] ^= m[0]; - z[1] ^= m[1]; - z[2] ^= m[2]; - z[3] ^= m[3]; -// GCMUtil.xor(z, M[i + i + 1][(x[i] & 0xf0) >>> 4]); - m = M[i + i + 1][(x[i] & 0xf0) >>> 4]; - z[0] ^= m[0]; - z[1] ^= m[1]; - z[2] ^= m[2]; - z[3] ^= m[3]; + long[] u = T[i + i + 1][(x[i] & 0x0F)]; + long[] v = T[i + i ][(x[i] & 0xF0) >>> 4]; + + z0 ^= u[0] ^ v[0]; + z1 ^= u[1] ^ v[1]; } - Pack.intToBigEndian(z, x, 0); - } -}
\ No newline at end of file + Pack.longToBigEndian(z0, x, 0); + Pack.longToBigEndian(z1, x, 8); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java index 63e29d84..076ad588 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java @@ -2,6 +2,7 @@ package org.bouncycastle.crypto.paddings; import java.security.SecureRandom; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.InvalidCipherTextException; /** @@ -26,7 +27,7 @@ public class ISO10126d2Padding } else { - this.random = new SecureRandom(); + this.random = CryptoServicesRegistrar.getSecureRandom(); } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java index 9a9272ba..c0648159 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java @@ -1,6 +1,7 @@ package org.bouncycastle.crypto.params; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.util.Arrays; public class AEADParameters implements CipherParameters @@ -33,9 +34,9 @@ public class AEADParameters public AEADParameters(KeyParameter key, int macSize, byte[] nonce, byte[] associatedText) { this.key = key; - this.nonce = nonce; + this.nonce = Arrays.clone(nonce); this.macSize = macSize; - this.associatedText = associatedText; + this.associatedText = Arrays.clone(associatedText); } public KeyParameter getKey() @@ -50,11 +51,11 @@ public class AEADParameters public byte[] getAssociatedText() { - return associatedText; + return Arrays.clone(associatedText); } public byte[] getNonce() { - return nonce; + return Arrays.clone(nonce); } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java index fec6dfdc..5bdb10a1 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java @@ -94,6 +94,11 @@ public class DHParameters } } + if (m > p.bitLength()) + { + throw new IllegalArgumentException("unsafe p value so small specific l required"); + } + this.g = g; this.p = p; this.q = q; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java index b22f7a03..8c4b187d 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java @@ -11,7 +11,7 @@ public class DHValidationParameters byte[] seed, int counter) { - this.seed = seed; + this.seed = Arrays.clone(seed); this.counter = counter; } @@ -22,7 +22,7 @@ public class DHValidationParameters public byte[] getSeed() { - return seed; + return Arrays.clone(seed); } public boolean equals( diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java index 07d93d07..11613e8e 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java @@ -20,7 +20,7 @@ public class DSAValidationParameters int counter, int usageIndex) { - this.seed = seed; + this.seed = Arrays.clone(seed); this.counter = counter; this.usageIndex = usageIndex; } @@ -32,7 +32,7 @@ public class DSAValidationParameters public byte[] getSeed() { - return seed; + return Arrays.clone(seed); } public int getUsageIndex() diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java index c97f2e76..1cead6f3 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java @@ -2,6 +2,7 @@ package org.bouncycastle.crypto.params; import java.math.BigInteger; +import org.bouncycastle.math.ec.ECAlgorithms; import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; @@ -15,6 +16,7 @@ public class ECDomainParameters private ECPoint G; private BigInteger n; private BigInteger h; + private BigInteger hInv = null; public ECDomainParameters( ECCurve curve, @@ -40,11 +42,21 @@ public class ECDomainParameters BigInteger h, byte[] seed) { + if (curve == null) + { + throw new NullPointerException("curve"); + } + if (n == null) + { + throw new NullPointerException("n"); + } + // we can't check for h == null here as h is optional in X9.62 as it is not required for ECDSA + this.curve = curve; - this.G = G.normalize(); + this.G = validate(curve, G); this.n = n; this.h = h; - this.seed = seed; + this.seed = Arrays.clone(seed); } public ECCurve getCurve() @@ -67,6 +79,15 @@ public class ECDomainParameters return h; } + public synchronized BigInteger getHInv() + { + if (hInv == null) + { + hInv = h.modInverse(n); + } + return hInv; + } + public byte[] getSeed() { return Arrays.clone(seed); @@ -101,4 +122,26 @@ public class ECDomainParameters hc ^= h.hashCode(); return hc; } + + static ECPoint validate(ECCurve c, ECPoint q) + { + if (q == null) + { + throw new IllegalArgumentException("Point has null value"); + } + + q = ECAlgorithms.importPoint(c, q).normalize(); + + if (q.isInfinity()) + { + throw new IllegalArgumentException("Point at infinity"); + } + + if (!q.isValid()) + { + throw new IllegalArgumentException("Point not on curve"); + } + + return q; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java index 5b694bec..ed89589f 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java @@ -3,6 +3,7 @@ package org.bouncycastle.crypto.params; import java.math.BigInteger; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; @@ -13,7 +14,7 @@ public class ECNamedDomainParameters public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n) { - this(name, curve, G, n, null, null); + this(name, curve, G, n, ECConstants.ONE, null); } public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n, BigInteger h) @@ -28,6 +29,12 @@ public class ECNamedDomainParameters this.name = name; } + public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECDomainParameters domainParameters) + { + super(domainParameters.getCurve(), domainParameters.getG(), domainParameters.getN(), domainParameters.getH(), domainParameters.getSeed()); + this.name = name; + } + public ASN1ObjectIdentifier getName() { return name; diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java index 036bf4ae..6f097ad3 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java @@ -13,29 +13,7 @@ public class ECPublicKeyParameters { super(false, params); - this.Q = validate(Q); - } - - private ECPoint validate(ECPoint q) - { - if (q == null) - { - throw new IllegalArgumentException("point has null value"); - } - - if (q.isInfinity()) - { - throw new IllegalArgumentException("point at infinity"); - } - - q = q.normalize(); - - if (!q.isValid()) - { - throw new IllegalArgumentException("point not on curve"); - } - - return q; + this.Q = ECDomainParameters.validate(params.getCurve(), Q); } public ECPoint getQ() diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java index a7b18e51..9c6ed020 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java @@ -1,9 +1,10 @@ package org.bouncycastle.crypto.params; -import org.bouncycastle.crypto.CipherParameters; - import java.security.SecureRandom; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; + public class ParametersWithRandom implements CipherParameters { @@ -21,7 +22,7 @@ public class ParametersWithRandom public ParametersWithRandom( CipherParameters parameters) { - this(parameters, new SecureRandom()); + this(parameters, CryptoServicesRegistrar.getSecureRandom()); } public SecureRandom getRandom() diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSAEncoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSAEncoding.java new file mode 100644 index 00000000..9ee166f9 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSAEncoding.java @@ -0,0 +1,31 @@ +package org.bouncycastle.crypto.signers; + +import java.io.IOException; +import java.math.BigInteger; + +/** + * An interface for different encoding formats for DSA signatures. + */ +public interface DSAEncoding +{ + /** + * Decode the (r, s) pair of a DSA signature. + * + * @param n the order of the group that r, s belong to. + * @param encoding an encoding of the (r, s) pair of a DSA signature. + * @return the (r, s) of a DSA signature, stored in an array of exactly two elements, r followed by s. + * @throws IOException + */ + BigInteger[] decode(BigInteger n, byte[] encoding) throws IOException; + + /** + * Encode the (r, s) pair of a DSA signature. + * + * @param n the order of the group that r, s belong to. + * @param r the r value of a DSA signature. + * @param s the s value of a DSA signature. + * @return an encoding of the DSA signature given by the provided (r, s) pair. + * @throws IOException + */ + byte[] encode(BigInteger n, BigInteger r, BigInteger s) throws IOException; +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java index 920611bc..668ac276 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java @@ -4,19 +4,21 @@ import java.math.BigInteger; import java.security.SecureRandom; import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.DSAExt; import org.bouncycastle.crypto.params.DSAKeyParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.util.BigIntegers; /** * The Digital Signature Algorithm - as described in "Handbook of Applied * Cryptography", pages 452 - 453. */ public class DSASigner - implements DSA + implements DSAExt { private final DSAKCalculator kCalculator; @@ -69,6 +71,11 @@ public class DSASigner this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom); } + public BigInteger getOrder() + { + return key.getParameters().getQ(); + } + /** * generate a signature for the given message using the key we were * initialised with. For conventional DSA the message should be a SHA-1 @@ -162,7 +169,7 @@ public class DSASigner protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided) { - return !needed ? null : (provided != null) ? provided : new SecureRandom(); + return !needed ? null : (provided != null) ? provided : CryptoServicesRegistrar.getSecureRandom(); } private BigInteger getRandomizer(BigInteger q, SecureRandom provided) @@ -170,6 +177,6 @@ public class DSASigner // Calculate a random multiple of q to add to k. Note that g^q = 1 (mod p), so adding multiple of q to k does not change r. int randomBits = 7; - return new BigInteger(randomBits, provided != null ? provided : new SecureRandom()).add(BigInteger.valueOf(128)).multiply(q); + return BigIntegers.createRandomBigInteger(randomBits, provided != null ? provided : CryptoServicesRegistrar.getSecureRandom()).add(BigInteger.valueOf(128)).multiply(q); } } 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 adb2558a..057beed7 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java @@ -4,7 +4,8 @@ import java.math.BigInteger; import java.security.SecureRandom; import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.DSAExt; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; @@ -22,7 +23,7 @@ import org.bouncycastle.math.ec.FixedPointCombMultiplier; * EC-DSA as described in X9.62 */ public class ECDSASigner - implements ECConstants, DSA + implements ECConstants, DSAExt { private final DSAKCalculator kCalculator; @@ -75,6 +76,11 @@ public class ECDSASigner this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom); } + public BigInteger getOrder() + { + return key.getParameters().getN(); + } + // 5.3 pg 28 /** * generate a signature for the given message using the key we were @@ -247,6 +253,6 @@ public class ECDSASigner protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided) { - return !needed ? null : (provided != null) ? provided : new SecureRandom(); + return !needed ? null : (provided != null) ? provided : CryptoServicesRegistrar.getSecureRandom(); } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/PlainDSAEncoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/PlainDSAEncoding.java new file mode 100644 index 00000000..9bb30dde --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/PlainDSAEncoding.java @@ -0,0 +1,62 @@ +package org.bouncycastle.crypto.signers; + +import java.math.BigInteger; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; + +public class PlainDSAEncoding + implements DSAEncoding +{ + public static final PlainDSAEncoding INSTANCE = new PlainDSAEncoding(); + + public byte[] encode(BigInteger n, BigInteger r, BigInteger s) + { + int valueLength = BigIntegers.getUnsignedByteLength(n); + byte[] result = new byte[valueLength * 2]; + encodeValue(n, r, result, 0, valueLength); + encodeValue(n, s, result, valueLength, valueLength); + return result; + } + + public BigInteger[] decode(BigInteger n, byte[] encoding) + { + int valueLength = BigIntegers.getUnsignedByteLength(n); + if (encoding.length != valueLength * 2) + { + throw new IllegalArgumentException("Encoding has incorrect length"); + } + + return new BigInteger[] { + decodeValue(n, encoding, 0, valueLength), + decodeValue(n, encoding, valueLength, valueLength), + }; + } + + protected BigInteger checkValue(BigInteger n, BigInteger x) + { + if (x.signum() < 0 || x.compareTo(n) >= 0) + { + throw new IllegalArgumentException("Value out of range"); + } + + return x; + } + + protected BigInteger decodeValue(BigInteger n, byte[] buf, int off, int len) + { + byte[] bs = Arrays.copyOfRange(buf, off, off + len); + return checkValue(n, new BigInteger(1, bs)); + } + + private void encodeValue(BigInteger n, BigInteger x, byte[] buf, int off, int len) + { + byte[] bs = checkValue(n, x).toByteArray(); + int bsOff = Math.max(0, bs.length - len); + int bsLen = bs.length - bsOff; + + int pos = len - bsLen; + Arrays.fill(buf, off, off + pos, (byte)0); + System.arraycopy(bs, bsOff, buf, off + pos, bsLen); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java index 6a693080..cf54b85c 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java @@ -3,6 +3,8 @@ package org.bouncycastle.crypto.signers; import java.math.BigInteger; import java.security.SecureRandom; +import org.bouncycastle.util.BigIntegers; + public class RandomDSAKCalculator implements DSAKCalculator { @@ -34,7 +36,7 @@ public class RandomDSAKCalculator BigInteger k; do { - k = new BigInteger(qBitLength, random); + k = BigIntegers.createRandomBigInteger(qBitLength, random); } while (k.equals(ZERO) || k.compareTo(q) >= 0); diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/StandardDSAEncoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/StandardDSAEncoding.java new file mode 100644 index 00000000..c92b9769 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/StandardDSAEncoding.java @@ -0,0 +1,64 @@ +package org.bouncycastle.crypto.signers; + +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.util.Arrays; + +public class StandardDSAEncoding + implements DSAEncoding +{ + public static final StandardDSAEncoding INSTANCE = new StandardDSAEncoding(); + + public byte[] encode(BigInteger n, BigInteger r, BigInteger s) throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + encodeValue(n, v, r); + encodeValue(n, v, s); + return new DERSequence(v).getEncoded(ASN1Encoding.DER); + } + + public BigInteger[] decode(BigInteger n, byte[] encoding) throws IOException + { + ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); + if (seq.size() == 2) + { + BigInteger r = decodeValue(n, seq, 0); + BigInteger s = decodeValue(n, seq, 1); + + byte[] expectedEncoding = encode(n, r, s); + if (Arrays.areEqual(expectedEncoding, encoding)) + { + return new BigInteger[]{ r, s }; + } + } + + throw new IllegalArgumentException("Malformed signature"); + } + + protected BigInteger checkValue(BigInteger n, BigInteger x) + { + if (x.signum() < 0 || (null != n && x.compareTo(n) >= 0)) + { + throw new IllegalArgumentException("Value out of range"); + } + + return x; + } + + protected BigInteger decodeValue(BigInteger n, ASN1Sequence s, int pos) + { + return checkValue(n, ((ASN1Integer)s.getObjectAt(pos)).getValue()); + } + + protected void encodeValue(BigInteger n, ASN1EncodableVector v, BigInteger x) + { + v.add(new ASN1Integer(checkValue(n, x))); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java index a5c583b0..997d9907 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java @@ -12,4 +12,8 @@ import java.io.EOFException; public class TlsNoCloseNotifyException extends EOFException { + public TlsNoCloseNotifyException() + { + super("No close_notify alert received before connection closed"); + } } 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 911f1dae..58c7871c 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java @@ -8,17 +8,25 @@ import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; // Android-removed: Unsupported algorithms // import org.bouncycastle.asn1.oiw.ElGamalParameter; +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; +// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters; +// import org.bouncycastle.asn1.edec.EdECObjectIdentifiers; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.DHParameter; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.pkcs.RSAPrivateKey; +// import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; import org.bouncycastle.asn1.sec.ECPrivateKey; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DSAParameter; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; @@ -30,12 +38,19 @@ import org.bouncycastle.crypto.params.DHPrivateKeyParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.ECDomainParameters; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.params.ECGOST3410Parameters; import org.bouncycastle.crypto.params.ECNamedDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; // Android-removed: Unsupported algorithms // import org.bouncycastle.crypto.params.ElGamalParameters; // import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters; +// import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +// import org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.params.X25519PrivateKeyParameters; +// import org.bouncycastle.crypto.params.X448PrivateKeyParameters; /** * Factory for creating private key objects from PKCS8 PrivateKeyInfo objects. @@ -44,12 +59,13 @@ public class PrivateKeyFactory { /** * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding. - * + * * @param privateKeyInfoData the PrivateKeyInfo encoding * @return a suitable private key parameter * @throws IOException on an error decoding the key */ - public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) throws IOException + public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) + throws IOException { return createKey(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(privateKeyInfoData))); } @@ -57,28 +73,33 @@ public class PrivateKeyFactory /** * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding read from a * stream. - * + * * @param inStr the stream to read the PrivateKeyInfo encoding from * @return a suitable private key parameter * @throws IOException on an error decoding the key */ - public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException + public static AsymmetricKeyParameter createKey(InputStream inStr) + throws IOException { return createKey(PrivateKeyInfo.getInstance(new ASN1InputStream(inStr).readObject())); } /** * Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object. - * + * * @param keyInfo the PrivateKeyInfo object containing the key material * @return a suitable private key parameter * @throws IOException on an error decoding the key */ - public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) throws IOException + public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) + throws IOException { AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm(); + ASN1ObjectIdentifier algOID = algId.getAlgorithm(); - if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption)) + if (algOID.equals(PKCSObjectIdentifiers.rsaEncryption) + || algOID.equals(PKCSObjectIdentifiers.id_RSASSA_PSS) + || algOID.equals(X509ObjectIdentifiers.id_ea_rsa)) { RSAPrivateKey keyStructure = RSAPrivateKey.getInstance(keyInfo.parsePrivateKey()); @@ -88,8 +109,8 @@ public class PrivateKeyFactory keyStructure.getExponent2(), keyStructure.getCoefficient()); } // TODO? -// else if (algId.getObjectId().equals(X9ObjectIdentifiers.dhpublicnumber)) - else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement)) +// else if (algOID.equals(X9ObjectIdentifiers.dhpublicnumber)) + else if (algOID.equals(PKCSObjectIdentifiers.dhKeyAgreement)) { DHParameter params = DHParameter.getInstance(algId.getParameters()); ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey(); @@ -102,7 +123,7 @@ public class PrivateKeyFactory } // BEGIN Android-removed: Unsupported algorithms /* - else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm)) + else if (algOID.equals(OIWObjectIdentifiers.elGamalAlgorithm)) { ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters()); ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey(); @@ -112,7 +133,7 @@ public class PrivateKeyFactory } */ // END Android-removed: Unsupported algorithms - else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa)) + else if (algOID.equals(X9ObjectIdentifiers.id_dsa)) { ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey(); ASN1Encodable de = algId.getParameters(); @@ -126,7 +147,7 @@ public class PrivateKeyFactory return new DSAPrivateKeyParameters(derX.getValue(), parameters); } - else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey)) + else if (algOID.equals(X9ObjectIdentifiers.id_ecPublicKey)) { X962Parameters params = new X962Parameters((ASN1Primitive)algId.getParameters()); @@ -157,9 +178,151 @@ public class PrivateKeyFactory return new ECPrivateKeyParameters(d, dParams); } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (algOID.equals(EdECObjectIdentifiers.id_X25519)) + { + return new X25519PrivateKeyParameters(getRawKey(keyInfo, X25519PrivateKeyParameters.KEY_SIZE), 0); + } + else if (algOID.equals(EdECObjectIdentifiers.id_X448)) + { + return new X448PrivateKeyParameters(getRawKey(keyInfo, X448PrivateKeyParameters.KEY_SIZE), 0); + } + else if (algOID.equals(EdECObjectIdentifiers.id_Ed25519)) + { + return new Ed25519PrivateKeyParameters(getRawKey(keyInfo, Ed25519PrivateKeyParameters.KEY_SIZE), 0); + } + else if (algOID.equals(EdECObjectIdentifiers.id_Ed448)) + { + return new Ed448PrivateKeyParameters(getRawKey(keyInfo, Ed448PrivateKeyParameters.KEY_SIZE), 0); + } + else if ( + algOID.equals(CryptoProObjectIdentifiers.gostR3410_2001) || + algOID.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512) || + algOID.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256)) + { + GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters()); + ECGOST3410Parameters ecSpec = null; + BigInteger d = null; + ASN1Primitive p = keyInfo.getPrivateKeyAlgorithm().getParameters().toASN1Primitive(); + if (p instanceof ASN1Sequence && (ASN1Sequence.getInstance(p).size() == 2 || ASN1Sequence.getInstance(p).size() == 3)) + { + + ECDomainParameters ecP = ECGOST3410NamedCurves.getByOID(gostParams.getPublicKeyParamSet()); + + ecSpec = new ECGOST3410Parameters( + new ECNamedDomainParameters( + gostParams.getPublicKeyParamSet(), ecP), + gostParams.getPublicKeyParamSet(), + gostParams.getDigestParamSet(), + gostParams.getEncryptionParamSet()); + ASN1Encodable privKey = keyInfo.parsePrivateKey(); + if (privKey instanceof ASN1Integer) + { + d = ASN1Integer.getInstance(privKey).getPositiveValue(); + } + else + { + byte[] encVal = ASN1OctetString.getInstance(privKey).getOctets(); + byte[] dVal = new byte[encVal.length]; + + for (int i = 0; i != encVal.length; i++) + { + dVal[i] = encVal[encVal.length - 1 - i]; + } + + d = new BigInteger(1, dVal); + } + + + } + else + { + X962Parameters params = X962Parameters.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters()); + + if (params.isNamedCurve()) + { + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); + X9ECParameters ecP = ECNamedCurveTable.getByOID(oid); + if (ecP == null) + { + ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid); + ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters( + oid, + gParam.getCurve(), + gParam.getG(), + gParam.getN(), + gParam.getH(), + gParam.getSeed()), gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet()); + } + else + { + ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters( + oid, + ecP.getCurve(), + ecP.getG(), + ecP.getN(), + ecP.getH(), + ecP.getSeed()), gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet()); + } + } + else if (params.isImplicitlyCA()) + { + ecSpec = null; + } + else + { + X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); + ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters( + algOID, + ecP.getCurve(), + ecP.getG(), + ecP.getN(), + ecP.getH(), + ecP.getSeed()), gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet()); + } + + ASN1Encodable privKey = keyInfo.parsePrivateKey(); + if (privKey instanceof ASN1Integer) + { + ASN1Integer derD = ASN1Integer.getInstance(privKey); + + d = derD.getValue(); + } + else + { + org.bouncycastle.asn1.sec.ECPrivateKey ec = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(privKey); + + d = ec.getKey(); + } + + } + + return new ECPrivateKeyParameters( + d, + new ECGOST3410Parameters( + ecSpec, + gostParams.getPublicKeyParamSet(), + gostParams.getDigestParamSet(), + gostParams.getEncryptionParamSet())); + + } + */ + // END Android-removed: Unsupported algorithms else { - throw new RuntimeException("algorithm identifier in key not recognised"); + throw new RuntimeException("algorithm identifier in private key not recognised"); + } + } + + private static byte[] getRawKey(PrivateKeyInfo keyInfo, int expectedSize) + throws IOException + { + byte[] result = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(); + if (expectedSize != result.length) + { + throw new RuntimeException("private key encoding has incorrect length"); } + return result; } } diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java index 86028870..b64c6a2a 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java @@ -3,6 +3,8 @@ package org.bouncycastle.crypto.util; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1InputStream; @@ -10,13 +12,25 @@ import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DEROctetString; -// Android-removed: Unsupported algorithm +// Android-removed: Unsupported algorithms +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; +// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters; +// import org.bouncycastle.asn1.edec.EdECObjectIdentifiers; // import org.bouncycastle.asn1.oiw.ElGamalParameter; 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.rosstandart.RosstandartObjectIdentifiers; +// import org.bouncycastle.asn1.ua.DSTU4145BinaryField; +// import org.bouncycastle.asn1.ua.DSTU4145ECBinary; +// import org.bouncycastle.asn1.ua.DSTU4145NamedCurves; +// import org.bouncycastle.asn1.ua.DSTU4145Params; +// import org.bouncycastle.asn1.ua.DSTU4145PointEncoder; +// import org.bouncycastle.asn1.ua.UAObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DSAParameter; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; @@ -28,6 +42,7 @@ import org.bouncycastle.asn1.x9.ValidationParams; import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ECPoint; +import org.bouncycastle.asn1.x9.X9IntegerConverter; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.ec.CustomNamedCurves; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; @@ -37,12 +52,19 @@ import org.bouncycastle.crypto.params.DHValidationParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; import org.bouncycastle.crypto.params.ECDomainParameters; +// import org.bouncycastle.crypto.params.ECGOST3410Parameters; import org.bouncycastle.crypto.params.ECNamedDomainParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; -// Android-removed: Unsupported algorithm +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +// import org.bouncycastle.crypto.params.Ed448PublicKeyParameters; // import org.bouncycastle.crypto.params.ElGamalParameters; // import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.params.X25519PublicKeyParameters; +// import org.bouncycastle.crypto.params.X448PublicKeyParameters; +import org.bouncycastle.math.ec.ECCurve; /** * Factory to create asymmetric public key parameters for asymmetric ciphers from range of @@ -50,55 +72,127 @@ import org.bouncycastle.crypto.params.RSAKeyParameters; */ public class PublicKeyFactory { + private static Map converters = new HashMap(); + + static + { + converters.put(PKCSObjectIdentifiers.rsaEncryption, new RSAConverter()); + converters.put(PKCSObjectIdentifiers.id_RSASSA_PSS, new RSAConverter()); + converters.put(X509ObjectIdentifiers.id_ea_rsa, new RSAConverter()); + converters.put(X9ObjectIdentifiers.dhpublicnumber, new DHPublicNumberConverter()); + converters.put(PKCSObjectIdentifiers.dhKeyAgreement, new DHAgreementConverter()); + converters.put(X9ObjectIdentifiers.id_dsa, new DSAConverter()); + converters.put(OIWObjectIdentifiers.dsaWithSHA1, new DSAConverter()); + // Android-removed: Unsupported algorithm + // converters.put(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalConverter()); + converters.put(X9ObjectIdentifiers.id_ecPublicKey, new ECConverter()); + // BEGIN Android-removed: Unsupported algorithms + /* + converters.put(CryptoProObjectIdentifiers.gostR3410_2001, new GOST3410_2001Converter()); + converters.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256, new GOST3410_2012Converter()); + converters.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512, new GOST3410_2012Converter()); + converters.put(UAObjectIdentifiers.dstu4145be, new DSTUConverter()); + converters.put(UAObjectIdentifiers.dstu4145le, new DSTUConverter()); + converters.put(EdECObjectIdentifiers.id_X25519, new X25519Converter()); + converters.put(EdECObjectIdentifiers.id_X448, new X448Converter()); + converters.put(EdECObjectIdentifiers.id_Ed25519, new Ed25519Converter()); + converters.put(EdECObjectIdentifiers.id_Ed448, new Ed448Converter()); + */ + // END Android-removed: Unsupported algorithms + } + /** * Create a public key from a SubjectPublicKeyInfo encoding - * + * * @param keyInfoData the SubjectPublicKeyInfo encoding * @return the appropriate key parameter * @throws IOException on an error decoding the key */ - public static AsymmetricKeyParameter createKey(byte[] keyInfoData) throws IOException + public static AsymmetricKeyParameter createKey(byte[] keyInfoData) + throws IOException { return createKey(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(keyInfoData))); } /** * Create a public key from a SubjectPublicKeyInfo encoding read from a stream - * + * * @param inStr the stream to read the SubjectPublicKeyInfo encoding from * @return the appropriate key parameter * @throws IOException on an error decoding the key */ - public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException + public static AsymmetricKeyParameter createKey(InputStream inStr) + throws IOException { return createKey(SubjectPublicKeyInfo.getInstance(new ASN1InputStream(inStr).readObject())); } /** * Create a public key from the passed in SubjectPublicKeyInfo - * + * * @param keyInfo the SubjectPublicKeyInfo containing the key data * @return the appropriate key parameter * @throws IOException on an error decoding the key */ - public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo) throws IOException + public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo) + throws IOException + { + return createKey(keyInfo, null); + } + + /** + * Create a public key from the passed in SubjectPublicKeyInfo + * + * @param keyInfo the SubjectPublicKeyInfo containing the key data + * @param defaultParams default parameters that might be needed. + * @return the appropriate key parameter + * @throws IOException on an error decoding the key + */ + public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException { AlgorithmIdentifier algId = keyInfo.getAlgorithm(); + SubjectPublicKeyInfoConverter converter = (SubjectPublicKeyInfoConverter)converters.get(algId.getAlgorithm()); + + if (converter != null) + { + return converter.getPublicKeyParameters(keyInfo, defaultParams); + } + else + { + throw new IOException("algorithm identifier in public key not recognised: " + algId.getAlgorithm()); + } + } + + private static abstract class SubjectPublicKeyInfoConverter + { + abstract AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException; + } - if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption) - || algId.getAlgorithm().equals(X509ObjectIdentifiers.id_ea_rsa)) + private static class RSAConverter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException { RSAPublicKey pubKey = RSAPublicKey.getInstance(keyInfo.parsePublicKey()); return new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent()); } - else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.dhpublicnumber)) + } + + private static class DHPublicNumberConverter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException { DHPublicKey dhPublicKey = DHPublicKey.getInstance(keyInfo.parsePublicKey()); BigInteger y = dhPublicKey.getY(); - DomainParameters dhParams = DomainParameters.getInstance(algId.getParameters()); + DomainParameters dhParams = DomainParameters.getInstance(keyInfo.getAlgorithm().getParameters()); BigInteger p = dhParams.getP(); BigInteger g = dhParams.getG(); @@ -124,9 +218,15 @@ public class PublicKeyFactory return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation)); } - else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement)) + } + + private static class DHAgreementConverter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException { - DHParameter params = DHParameter.getInstance(algId.getParameters()); + DHParameter params = DHParameter.getInstance(keyInfo.getAlgorithm().getParameters()); ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey(); BigInteger lVal = params.getL(); @@ -135,23 +235,34 @@ public class PublicKeyFactory return new DHPublicKeyParameters(derY.getValue(), dhParams); } - // BEGIN Android-removed: Unsupported algorithm - /* - else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm)) + } + + // BEGIN Android-removed: Unsupported algorithm + /* + private static class ElGamalConverter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException { - ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters()); + ElGamalParameter params = ElGamalParameter.getInstance(keyInfo.getAlgorithm().getParameters()); ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey(); return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters( params.getP(), params.getG())); } - */ - // END Android-removed: Unsupported algorithm - else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa) - || algId.getAlgorithm().equals(OIWObjectIdentifiers.dsaWithSHA1)) + } + */ + // END Android-removed: Unsupported algorithm + + private static class DSAConverter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException { ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey(); - ASN1Encodable de = algId.getParameters(); + ASN1Encodable de = keyInfo.getAlgorithm().getParameters(); DSAParameters parameters = null; if (de != null) @@ -162,40 +273,282 @@ public class PublicKeyFactory return new DSAPublicKeyParameters(derY.getValue(), parameters); } - else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey)) - { - X962Parameters params = X962Parameters.getInstance(algId.getParameters()); + } - X9ECParameters x9; + private static class ECConverter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + X962Parameters params = X962Parameters.getInstance(keyInfo.getAlgorithm().getParameters()); ECDomainParameters dParams; if (params.isNamedCurve()) { ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters(); - x9 = CustomNamedCurves.getByOID(oid); + X9ECParameters x9 = CustomNamedCurves.getByOID(oid); if (x9 == null) { x9 = ECNamedCurveTable.getByOID(oid); } dParams = new ECNamedDomainParameters( - oid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + oid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + } + else if (params.isImplicitlyCA()) + { + dParams = (ECDomainParameters)defaultParams; } else { - x9 = X9ECParameters.getInstance(params.getParameters()); + X9ECParameters x9 = X9ECParameters.getInstance(params.getParameters()); dParams = new ECDomainParameters( - x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); } - ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes()); - X9ECPoint derQ = new X9ECPoint(x9.getCurve(), key); + DERBitString bits = keyInfo.getPublicKeyData(); + byte[] data = bits.getBytes(); + ASN1OctetString key = new DEROctetString(data); + + // + // extra octet string - the old extra embedded octet string + // + if (data[0] == 0x04 && data[1] == data.length - 2 + && (data[2] == 0x02 || data[2] == 0x03)) + { + int qLength = new X9IntegerConverter().getByteLength(dParams.getCurve()); + + if (qLength >= data.length - 3) + { + try + { + key = (ASN1OctetString)ASN1Primitive.fromByteArray(data); + } + catch (IOException ex) + { + throw new IllegalArgumentException("error recovering public key"); + } + } + } + + X9ECPoint derQ = new X9ECPoint(dParams.getCurve(), key); return new ECPublicKeyParameters(derQ.getPoint(), dParams); } - else + } + + // BEGIN Android-removed: Unsupported algorithms + /* + private static class GOST3410_2001Converter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + DERBitString bits = keyInfo.getPublicKeyData(); + ASN1OctetString key; + + try + { + key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes()); + } + catch (IOException ex) + { + throw new IllegalArgumentException("error recovering public key"); + } + + byte[] keyEnc = key.getOctets(); + + byte[] x9Encoding = new byte[65]; + x9Encoding[0] = 0x04; + for (int i = 1; i <= 32; ++i) + { + x9Encoding[i] = keyEnc[32 - i]; + x9Encoding[i + 32] = keyEnc[64 - i]; + } + + GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(keyInfo.getAlgorithm().getParameters()); + + ECGOST3410Parameters ecDomainParameters = + new ECGOST3410Parameters( + new ECNamedDomainParameters(gostParams.getPublicKeyParamSet(), ECGOST3410NamedCurves.getByOID(gostParams.getPublicKeyParamSet())), + gostParams.getPublicKeyParamSet(), + gostParams.getDigestParamSet(), + gostParams.getEncryptionParamSet()); + + + return new ECPublicKeyParameters(ecDomainParameters.getCurve().decodePoint(x9Encoding), ecDomainParameters); + + } + } + + private static class GOST3410_2012Converter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm(); + DERBitString bits = keyInfo.getPublicKeyData(); + ASN1OctetString key; + + try + { + key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes()); + } + catch (IOException ex) + { + throw new IllegalArgumentException("error recovering public key"); + } + + byte[] keyEnc = key.getOctets(); + + int fieldSize = 32; + if (algOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512)) + { + fieldSize = 64; + } + + int keySize = 2 * fieldSize; + + byte[] x9Encoding = new byte[1 + keySize]; + x9Encoding[0] = 0x04; + for (int i = 1; i <= fieldSize; ++i) + { + x9Encoding[i] = keyEnc[fieldSize - i]; + x9Encoding[i + fieldSize] = keyEnc[keySize - i]; + } + + GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(keyInfo.getAlgorithm().getParameters()); + + ECGOST3410Parameters ecDomainParameters = + new ECGOST3410Parameters( + new ECNamedDomainParameters(gostParams.getPublicKeyParamSet(), ECGOST3410NamedCurves.getByOID(gostParams.getPublicKeyParamSet())), + gostParams.getPublicKeyParamSet(), + gostParams.getDigestParamSet(), + gostParams.getEncryptionParamSet()); + + + return new ECPublicKeyParameters(ecDomainParameters.getCurve().decodePoint(x9Encoding), ecDomainParameters); + } + } + + private static class DSTUConverter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException + { + DERBitString bits = keyInfo.getPublicKeyData(); + ASN1OctetString key; + + try + { + key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes()); + } + catch (IOException ex) + { + throw new IllegalArgumentException("error recovering public key"); + } + + byte[] keyEnc = key.getOctets(); + + if (keyInfo.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + { + reverseBytes(keyEnc); + } + + DSTU4145Params dstuParams = DSTU4145Params.getInstance(keyInfo.getAlgorithm().getParameters()); + + ECDomainParameters ecDomain; + if (dstuParams.isNamedCurve()) + { + ASN1ObjectIdentifier curveOid = dstuParams.getNamedCurve(); + + ecDomain = DSTU4145NamedCurves.getByOID(curveOid); + } + else + { + DSTU4145ECBinary binary = dstuParams.getECBinary(); + byte[] b_bytes = binary.getB(); + if (keyInfo.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + { + reverseBytes(b_bytes); + } + DSTU4145BinaryField field = binary.getField(); + ECCurve curve = new ECCurve.F2m(field.getM(), field.getK1(), field.getK2(), field.getK3(), binary.getA(), new BigInteger(1, b_bytes)); + byte[] g_bytes = binary.getG(); + if (keyInfo.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + { + reverseBytes(g_bytes); + } + ecDomain = new ECDomainParameters(curve, DSTU4145PointEncoder.decodePoint(curve, g_bytes), binary.getN()); + } + + return new ECPublicKeyParameters(DSTU4145PointEncoder.decodePoint(ecDomain.getCurve(), keyEnc), ecDomain); + } + + private void reverseBytes(byte[] bytes) + { + byte tmp; + + for (int i = 0; i < bytes.length / 2; i++) + { + tmp = bytes[i]; + bytes[i] = bytes[bytes.length - 1 - i]; + bytes[bytes.length - 1 - i] = tmp; + } + } + } + + private static class X25519Converter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + return new X25519PublicKeyParameters(getRawKey(keyInfo, defaultParams, X25519PublicKeyParameters.KEY_SIZE), 0); + } + } + + private static class X448Converter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + return new X448PublicKeyParameters(getRawKey(keyInfo, defaultParams, X448PublicKeyParameters.KEY_SIZE), 0); + } + } + + private static class Ed25519Converter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + return new Ed25519PublicKeyParameters(getRawKey(keyInfo, defaultParams, Ed25519PublicKeyParameters.KEY_SIZE), 0); + } + } + + private static class Ed448Converter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + return new Ed448PublicKeyParameters(getRawKey(keyInfo, defaultParams, Ed448PublicKeyParameters.KEY_SIZE), 0); + } + } + */ + // END Android-removed: Unsupported algorithms + + private static byte[] getRawKey(SubjectPublicKeyInfo keyInfo, Object defaultParams, int expectedSize) + { + /* + * TODO[RFC 8422] + * - Require defaultParams == null? + * - Require keyInfo.getAlgorithm().getParameters() == null? + */ + byte[] result = keyInfo.getPublicKeyData().getOctets(); + if (expectedSize != result.length) { - throw new RuntimeException("algorithm identifier in key not recognised"); + throw new RuntimeException("public key encoding has incorrect length"); } + return result; } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXExtendedParameters.java b/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXExtendedParameters.java index cd24f069..34ac2b0a 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXExtendedParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXExtendedParameters.java @@ -41,7 +41,7 @@ public class PKIXExtendedParameters * when the end certificate was signed. The CA (or Root CA) certificate must * have been valid, when the CA certificate was signed and so on. So the * {@link PKIXParameters#setDate(Date)} method sets the time, when - * the <em>end certificate</em> must have been valid. <p/> It is used e.g. + * the <em>end certificate</em> must have been valid. It is used e.g. * in the German signature law. */ public static final int CHAIN_VALIDITY_MODEL = 1; @@ -337,4 +337,8 @@ public class PKIXExtendedParameters return revocationEnabled; } + public boolean getPolicyQualifiersRejected() + { + return baseParameters.getPolicyQualifiersRejected(); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/io/DigestUpdatingOutputStream.java b/bcprov/src/main/java/org/bouncycastle/jcajce/io/DigestUpdatingOutputStream.java new file mode 100644 index 00000000..3e3542da --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/io/DigestUpdatingOutputStream.java @@ -0,0 +1,34 @@ +package org.bouncycastle.jcajce.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.MessageDigest; + +class DigestUpdatingOutputStream + extends OutputStream +{ + private MessageDigest digest; + + DigestUpdatingOutputStream(MessageDigest digest) + { + this.digest = digest; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + digest.update(bytes, off, len); + } + + public void write(byte[] bytes) + throws IOException + { + digest.update(bytes); + } + + public void write(int b) + throws IOException + { + digest.update((byte)b); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacUpdatingOutputStream.java b/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacUpdatingOutputStream.java new file mode 100644 index 00000000..88496e82 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacUpdatingOutputStream.java @@ -0,0 +1,35 @@ +package org.bouncycastle.jcajce.io; + +import java.io.IOException; +import java.io.OutputStream; + +import javax.crypto.Mac; + +class MacUpdatingOutputStream + extends OutputStream +{ + private Mac mac; + + MacUpdatingOutputStream(Mac mac) + { + this.mac = mac; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + mac.update(bytes, off, len); + } + + public void write(byte[] bytes) + throws IOException + { + mac.update(bytes); + } + + public void write(int b) + throws IOException + { + mac.update((byte)b); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/io/OutputStreamFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/io/OutputStreamFactory.java new file mode 100644 index 00000000..92763281 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/io/OutputStreamFactory.java @@ -0,0 +1,46 @@ +package org.bouncycastle.jcajce.io; + +import java.io.OutputStream; +import java.security.MessageDigest; +import java.security.Signature; + +import javax.crypto.Mac; + +/** + * Utility class for creating OutputStreams from different JCA/JCE operators. + */ +public class OutputStreamFactory +{ + /** + * Create an OutputStream that wraps a signature. + * + * @param signature the signature to be updated as the stream is written to. + * @return an OutputStream. + */ + public static OutputStream createStream(Signature signature) + { + return new SignatureUpdatingOutputStream(signature); + } + + /** + * Create an OutputStream that wraps a digest. + * + * @param digest the digest to be updated as the stream is written to. + * @return an OutputStream. + */ + public static OutputStream createStream(MessageDigest digest) + { + return new DigestUpdatingOutputStream(digest); + } + + /** + * Create an OutputStream that wraps a mac. + * + * @param mac the signature to be updated as the stream is written to. + * @return an OutputStream. + */ + public static OutputStream createStream(Mac mac) + { + return new MacUpdatingOutputStream(mac); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/io/SignatureUpdatingOutputStream.java b/bcprov/src/main/java/org/bouncycastle/jcajce/io/SignatureUpdatingOutputStream.java new file mode 100644 index 00000000..f092df1b --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/io/SignatureUpdatingOutputStream.java @@ -0,0 +1,56 @@ +package org.bouncycastle.jcajce.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.Signature; +import java.security.SignatureException; + +class SignatureUpdatingOutputStream + extends OutputStream +{ + private Signature sig; + + SignatureUpdatingOutputStream(Signature sig) + { + this.sig = sig; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + try + { + sig.update(bytes, off, len); + } + catch (SignatureException e) + { + throw new IOException(e.getMessage()); + } + } + + public void write(byte[] bytes) + throws IOException + { + try + { + sig.update(bytes); + } + catch (SignatureException e) + { + throw new IOException(e.getMessage()); + } + } + + public void write(int b) + throws IOException + { + try + { + sig.update((byte)b); + } + catch (SignatureException e) + { + throw new IOException(e.getMessage()); + } + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java index dcc963cc..a0c2f84e 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java @@ -62,6 +62,36 @@ public class DH provider.addAlgorithm("Cipher.DHIESwithAES-CBC", PREFIX + "IESCipher$IESwithAESCBC"); provider.addAlgorithm("Cipher.DHIESWITHAES-CBC", PREFIX + "IESCipher$IESwithAESCBC"); provider.addAlgorithm("Cipher.DHIESWITHDESEDE-CBC", PREFIX + "IESCipher$IESwithDESedeCBC"); + + provider.addAlgorithm("KeyAgreement.DHWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHwithSHA1KDF"); + provider.addAlgorithm("KeyAgreement.DHWITHSHA224KDF", PREFIX + "KeyAgreementSpi$DHwithSHA224KDF"); + provider.addAlgorithm("KeyAgreement.DHWITHSHA256KDF", PREFIX + "KeyAgreementSpi$DHwithSHA256KDF"); + provider.addAlgorithm("KeyAgreement.DHWITHSHA384KDF", PREFIX + "KeyAgreementSpi$DHwithSHA384KDF"); + provider.addAlgorithm("KeyAgreement.DHWITHSHA512KDF", PREFIX + "KeyAgreementSpi$DHwithSHA512KDF"); + + provider.addAlgorithm("KeyAgreement.DHUWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA1KDF"); + provider.addAlgorithm("KeyAgreement.DHUWITHSHA224KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA224KDF"); + provider.addAlgorithm("KeyAgreement.DHUWITHSHA256KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA256KDF"); + provider.addAlgorithm("KeyAgreement.DHUWITHSHA384KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA384KDF"); + provider.addAlgorithm("KeyAgreement.DHUWITHSHA512KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA512KDF"); + + provider.addAlgorithm("KeyAgreement.DHUWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA1CKDF"); + provider.addAlgorithm("KeyAgreement.DHUWITHSHA224CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA224CKDF"); + provider.addAlgorithm("KeyAgreement.DHUWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA256CKDF"); + provider.addAlgorithm("KeyAgreement.DHUWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA384CKDF"); + provider.addAlgorithm("KeyAgreement.DHUWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA512CKDF"); + + provider.addAlgorithm("KeyAgreement.MQVWITHSHA1KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA1KDF"); + provider.addAlgorithm("KeyAgreement.MQVWITHSHA224KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA224KDF"); + provider.addAlgorithm("KeyAgreement.MQVWITHSHA256KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA256KDF"); + provider.addAlgorithm("KeyAgreement.MQVWITHSHA384KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA384KDF"); + provider.addAlgorithm("KeyAgreement.MQVWITHSHA512KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA512KDF"); + + provider.addAlgorithm("KeyAgreement.MQVWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA1CKDF"); + provider.addAlgorithm("KeyAgreement.MQVWITHSHA224CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA224CKDF"); + provider.addAlgorithm("KeyAgreement.MQVWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA256CKDF"); + provider.addAlgorithm("KeyAgreement.MQVWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA384CKDF"); + provider.addAlgorithm("KeyAgreement.MQVWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA512CKDF"); */ // END Android-removed: Unsupported algorithms 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 44bf12ef..6323b75f 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 @@ -84,10 +84,6 @@ public class DSA provider.addAlgorithm("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA"); // END Android-changed: Change primary ID from DSA to SHA1withDSA - // BEGIN Android-removed: Unsupported algorithms - // provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10040.4.3", "DSA"); - // END Android-removed: Unsupported algorithms - AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi(); for (int i = 0; i != DSAUtil.dsaOids.length; i++) 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 016b465f..b79b0c51 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 @@ -50,27 +50,70 @@ public class EC provider.addAttributes("KeyAgreement.ECCDH", generalEcAttributes); provider.addAlgorithm("KeyAgreement.ECCDH", PREFIX + "KeyAgreementSpi$DHC"); - provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA1KDFAndSharedInfo"); - provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA1KDFAndSharedInfo"); + provider.addAttributes("KeyAgreement.ECCDHU", generalEcAttributes); + provider.addAlgorithm("KeyAgreement.ECCDHU", PREFIX + "KeyAgreementSpi$DHUC"); - provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA224KDFAndSharedInfo"); - provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA224KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement.ECDHWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHwithSHA1KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA1KDF", PREFIX + "KeyAgreementSpi$CDHwithSHA1KDFAndSharedInfo"); - provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_stdDH_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA256KDFAndSharedInfo"); - provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_cofactorDH_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA256KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement.ECDHWITHSHA224KDF", PREFIX + "KeyAgreementSpi$DHwithSHA224KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA224KDF", PREFIX + "KeyAgreementSpi$CDHwithSHA224KDFAndSharedInfo"); - provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_stdDH_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA384KDFAndSharedInfo"); - provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_cofactorDH_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA384KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement.ECDHWITHSHA256KDF", PREFIX + "KeyAgreementSpi$DHwithSHA256KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA256KDF", PREFIX + "KeyAgreementSpi$CDHwithSHA256KDFAndSharedInfo"); - provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_stdDH_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA512KDFAndSharedInfo"); - provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_cofactorDH_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA512KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement.ECDHWITHSHA384KDF", PREFIX + "KeyAgreementSpi$DHwithSHA384KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA384KDF", PREFIX + "KeyAgreementSpi$CDHwithSHA384KDFAndSharedInfo"); - provider.addAlgorithm("KeyAgreement.ECDHWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHwithSHA1KDF"); + provider.addAlgorithm("KeyAgreement.ECDHWITHSHA512KDF", PREFIX + "KeyAgreementSpi$DHwithSHA512KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA512KDF", PREFIX + "KeyAgreementSpi$CDHwithSHA512KDFAndSharedInfo"); + + provider.addAlgorithm("KeyAgreement", X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA1KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement", X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA1KDFAndSharedInfo"); + + provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA224KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA224KDFAndSharedInfo"); + + provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_stdDH_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA256KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_cofactorDH_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA256KDFAndSharedInfo"); + + provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_stdDH_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA384KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_cofactorDH_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA384KDFAndSharedInfo"); + + provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_stdDH_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA512KDFAndSharedInfo"); + provider.addAlgorithm("KeyAgreement", SECObjectIdentifiers.dhSinglePass_cofactorDH_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA512KDFAndSharedInfo"); provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA1CKDF"); provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA256CKDF"); provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA384CKDF"); provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA512CKDF"); + + provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA1CKDF"); + provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA224CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA224CKDF"); + provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA256CKDF"); + provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA384CKDF"); + provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$DHUwithSHA512CKDF"); + + provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA1KDF"); + provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA224KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA224KDF"); + provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA256KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA256KDF"); + provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA384KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA384KDF"); + provider.addAlgorithm("KeyAgreement.ECCDHUWITHSHA512KDF", PREFIX + "KeyAgreementSpi$DHUwithSHA512KDF"); + + provider.addAlgorithm("KeyAgreement.ECKAEGWITHSHA1KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithSHA1KDF"); + provider.addAlgorithm("KeyAgreement.ECKAEGWITHSHA224KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithSHA224KDF"); + provider.addAlgorithm("KeyAgreement.ECKAEGWITHSHA256KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithSHA256KDF"); + provider.addAlgorithm("KeyAgreement.ECKAEGWITHSHA384KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithSHA384KDF"); + provider.addAlgorithm("KeyAgreement.ECKAEGWITHSHA512KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithSHA512KDF"); + + provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA1, PREFIX + "KeyAgreementSpi$ECKAEGwithSHA1KDF"); + provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA224, PREFIX + "KeyAgreementSpi$ECKAEGwithSHA224KDF"); + provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA256, PREFIX + "KeyAgreementSpi$ECKAEGwithSHA256KDF"); + provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA384, PREFIX + "KeyAgreementSpi$ECKAEGwithSHA384KDF"); + provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA512, PREFIX + "KeyAgreementSpi$ECKAEGwithSHA512KDF"); + + provider.addAlgorithm("KeyAgreement", BSIObjectIdentifiers.ecka_eg_X963kdf_RIPEMD160, PREFIX + "KeyAgreementSpi$ECKAEGwithRIPEMD160KDF"); + provider.addAlgorithm("KeyAgreement.ECKAEGWITHRIPEMD160KDF", PREFIX + "KeyAgreementSpi$ECKAEGwithRIPEMD160KDF"); */ // END Android-removed: Unsupported algorithms @@ -120,6 +163,12 @@ public class EC provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA384CKDF"); provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA512CKDF"); + provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA1KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA1KDF"); + provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA224KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA224KDF"); + provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA256KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA256KDF"); + provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA384KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA384KDF"); + provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA512KDF", PREFIX + "KeyAgreementSpi$MQVwithSHA512KDF"); + provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA1KDFAndSharedInfo"); provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA224KDFAndSharedInfo"); provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA256KDFAndSharedInfo"); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java index bf6bfe71..b1ef7e5e 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java @@ -8,6 +8,7 @@ import java.security.spec.AlgorithmParameterSpec; import javax.crypto.spec.DHGenParameterSpec; import javax.crypto.spec.DHParameterSpec; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.generators.DHParametersGenerator; import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAlgorithmParameterGeneratorSpi; @@ -57,7 +58,7 @@ public class AlgorithmParameterGeneratorSpi } else { - pGen.init(strength, certainty, new SecureRandom()); + pGen.init(strength, certainty, CryptoServicesRegistrar.getSecureRandom()); } DHParameters p = pGen.generateParameters(); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java index 6fb54b67..21182ef1 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java @@ -19,11 +19,14 @@ import org.bouncycastle.asn1.pkcs.DHParameter; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x9.DHDomainParameters; import org.bouncycastle.asn1.x9.DomainParameters; +import org.bouncycastle.asn1.x9.ValidationParams; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.crypto.params.DHPrivateKeyParameters; +import org.bouncycastle.crypto.params.DHValidationParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; +import org.bouncycastle.jcajce.spec.DHDomainParameterSpec; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; @@ -36,6 +39,7 @@ public class BCDHPrivateKey private transient DHParameterSpec dhSpec; private transient PrivateKeyInfo info; + private transient DHPrivateKeyParameters dhPrivateKey; private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl(); @@ -75,29 +79,37 @@ public class BCDHPrivateKey if (params.getL() != null) { this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue()); + this.dhPrivateKey = new DHPrivateKeyParameters(x, + new DHParameters(params.getP(), params.getG(), null, params.getL().intValue())); } else { this.dhSpec = new DHParameterSpec(params.getP(), params.getG()); + this.dhPrivateKey = new DHPrivateKeyParameters(x, + new DHParameters(params.getP(), params.getG())); } } else if (id.equals(X9ObjectIdentifiers.dhpublicnumber)) { DomainParameters params = DomainParameters.getInstance(seq); - this.dhSpec = new DHParameterSpec(params.getP(), params.getG()); + this.dhSpec = new DHDomainParameterSpec(params.getP(), params.getQ(), params.getG(), params.getJ(), 0); + this.dhPrivateKey = new DHPrivateKeyParameters(x, + new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), null)); } else { throw new IllegalArgumentException("unknown algorithm type: " + id); } + + } BCDHPrivateKey( DHPrivateKeyParameters params) { this.x = params.getX(); - this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL()); + this.dhSpec = new DHDomainParameterSpec(params.getParameters()); } public String getAlgorithm() @@ -130,16 +142,35 @@ public class BCDHPrivateKey return info.getEncoded(ASN1Encoding.DER); } - PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(getX())); - + PrivateKeyInfo info; + if (dhSpec instanceof DHDomainParameterSpec && ((DHDomainParameterSpec)dhSpec).getQ() != null) + { + DHParameters params = ((DHDomainParameterSpec)dhSpec).getDomainParameters(); + DHValidationParameters validationParameters = params.getValidationParameters(); + ValidationParams vParams = null; + if (validationParameters != null) + { + vParams = new ValidationParams(validationParameters.getSeed(), validationParameters.getCounter()); + } + info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.dhpublicnumber, new DomainParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), vParams).toASN1Primitive()), new ASN1Integer(getX())); + } + else + { + info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(getX())); + } return info.getEncoded(ASN1Encoding.DER); } catch (Exception e) - { + { return null; } } + public String toString() + { + return DHUtil.privateKeyToString("DH", x, new DHParameters(dhSpec.getP(), dhSpec.getG())); + } + public DHParameterSpec getParams() { return dhSpec; @@ -150,6 +181,20 @@ public class BCDHPrivateKey return x; } + DHPrivateKeyParameters engineGetKeyParameters() + { + if (dhPrivateKey != null) + { + return dhPrivateKey; + } + + if (dhSpec instanceof DHDomainParameterSpec) + { + return new DHPrivateKeyParameters(x, ((DHDomainParameterSpec)dhSpec).getDomainParameters()); + } + return new DHPrivateKeyParameters(x, new DHParameters(dhSpec.getP(), dhSpec.getG(), null, dhSpec.getL())); + } + public boolean equals( Object o) { diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java index 1462a38b..039b8d3d 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java @@ -23,6 +23,7 @@ import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.crypto.params.DHPublicKeyParameters; import org.bouncycastle.crypto.params.DHValidationParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; +import org.bouncycastle.jcajce.spec.DHDomainParameterSpec; public class BCDHPublicKey implements DHPublicKey @@ -55,7 +56,7 @@ public class BCDHPublicKey DHPublicKeyParameters params) { this.y = params.getY(); - this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL()); + this.dhSpec = new DHDomainParameterSpec(params.getParameters()); this.dhPublicKey = params; } @@ -65,7 +66,15 @@ public class BCDHPublicKey { this.y = y; this.dhSpec = dhSpec; - this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG())); + + if (dhSpec instanceof DHDomainParameterSpec) + { + this.dhPublicKey = new DHPublicKeyParameters(y, ((DHDomainParameterSpec)dhSpec).getDomainParameters()); + } + else + { + this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(dhSpec.getP(), dhSpec.getG())); + } } public BCDHPublicKey( @@ -107,7 +116,6 @@ public class BCDHPublicKey { DomainParameters params = DomainParameters.getInstance(seq); - this.dhSpec = new DHParameterSpec(params.getP(), params.getG()); ValidationParams validationParams = params.getValidationParams(); if (validationParams != null) { @@ -118,6 +126,7 @@ public class BCDHPublicKey { this.dhPublicKey = new DHPublicKeyParameters(y, new DHParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), null)); } + this.dhSpec = new DHDomainParameterSpec(dhPublicKey.getParameters()); } else { @@ -142,9 +151,25 @@ public class BCDHPublicKey return KeyUtil.getEncodedSubjectPublicKeyInfo(info); } + if (dhSpec instanceof DHDomainParameterSpec && ((DHDomainParameterSpec)dhSpec).getQ() != null) + { + DHParameters params = ((DHDomainParameterSpec)dhSpec).getDomainParameters(); + DHValidationParameters validationParameters = params.getValidationParameters(); + ValidationParams vParams = null; + if (validationParameters != null) + { + vParams = new ValidationParams(validationParameters.getSeed(), validationParameters.getCounter()); + } + return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.dhpublicnumber, new DomainParameters(params.getP(), params.getG(), params.getQ(), params.getJ(), vParams).toASN1Primitive()), new ASN1Integer(y)); + } return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(y)); } + public String toString() + { + return DHUtil.publicKeyToString("DH", y, new DHParameters(dhSpec.getP(), dhSpec.getG())); + } + public DHParameterSpec getParams() { return dhSpec; diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java new file mode 100644 index 00000000..f26b83bd --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java @@ -0,0 +1,45 @@ +package org.bouncycastle.jcajce.provider.asymmetric.dh; + +import java.math.BigInteger; + +import org.bouncycastle.crypto.params.DHParameters; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Fingerprint; +import org.bouncycastle.util.Strings; + +class DHUtil +{ + static String privateKeyToString(String algorithm, BigInteger x, DHParameters dhParams) + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + BigInteger y = dhParams.getG().modPow(x, dhParams.getP()); + + buf.append(algorithm); + buf.append(" Private Key [").append(generateKeyFingerprint(y, dhParams)).append("]").append(nl); + buf.append(" Y: ").append(y.toString(16)).append(nl); + + return buf.toString(); + } + + static String publicKeyToString(String algorithm, BigInteger y, DHParameters dhParams) + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + buf.append(algorithm); + buf.append(" Public Key [").append(generateKeyFingerprint(y, dhParams)).append("]").append(nl); + buf.append(" Y: ").append(y.toString(16)).append(nl); + + return buf.toString(); + } + + private static String generateKeyFingerprint(BigInteger y, DHParameters dhParams) + { + return new Fingerprint( + Arrays.concatenate( + y.toByteArray(), + dhParams.getP().toByteArray(), dhParams.getG().toByteArray())).toString(); + } +} diff --git a/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 890674ed..502854de 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 @@ -5,6 +5,8 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; @@ -15,11 +17,28 @@ import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import javax.crypto.spec.SecretKeySpec; +import org.bouncycastle.crypto.BasicAgreement; import org.bouncycastle.crypto.DerivationFunction; -// Android-removed: Unsupported algorithm +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.agreement.DHUnifiedAgreement; +// import org.bouncycastle.crypto.agreement.MQVBasicAgreement; +// import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator; // import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator; +// import org.bouncycastle.crypto.generators.KDF2BytesGenerator; +// import org.bouncycastle.crypto.params.DHMQVPrivateParameters; +// import org.bouncycastle.crypto.params.DHMQVPublicParameters; +import org.bouncycastle.crypto.params.DHParameters; +import org.bouncycastle.crypto.params.DHPrivateKeyParameters; +import org.bouncycastle.crypto.params.DHPublicKeyParameters; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.params.DHUPrivateParameters; +// import org.bouncycastle.crypto.params.DHUPublicParameters; // import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi; +import org.bouncycastle.jcajce.spec.DHDomainParameterSpec; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.jcajce.spec.DHUParameterSpec; +// import org.bouncycastle.jcajce.spec.MQVParameterSpec; import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec; /** @@ -33,22 +52,58 @@ public class KeyAgreementSpi private static final BigInteger ONE = BigInteger.valueOf(1); private static final BigInteger TWO = BigInteger.valueOf(2); + // Android-removed: Unsupported algorithms + // private final DHUnifiedAgreement unifiedAgreement; + private final BasicAgreement mqvAgreement; + + // Android-removed: Unsupported algorithms + // private DHUParameterSpec dheParameters; + // private MQVParameterSpec mqvParameters; + private BigInteger x; private BigInteger p; private BigInteger g; - private BigInteger result; + private byte[] result; public KeyAgreementSpi() { - super("Diffie-Hellman", null); + this("Diffie-Hellman", null); + } + + public KeyAgreementSpi( + String kaAlgorithm, + DerivationFunction kdf) + { + super(kaAlgorithm, kdf); + // Android-removed: Unsupported algorithm + // this.unifiedAgreement = null; + this.mqvAgreement = null; + } + + // BEGIN Android-removed: Unsupported algorithm + /* + public KeyAgreementSpi( + String kaAlgorithm, + DHUnifiedAgreement unifiedAgreement, + DerivationFunction kdf) + { + super(kaAlgorithm, kdf); + this.unifiedAgreement = unifiedAgreement; + this.mqvAgreement = null; } + */ + // END Android-removed: Unsupported algorithm public KeyAgreementSpi( String kaAlgorithm, + BasicAgreement mqvAgreement, DerivationFunction kdf) { super(kaAlgorithm, kdf); + // Android-removed: Unsupported algorithm + // this.unifiedAgreement = null; + this.mqvAgreement = mqvAgreement; } protected byte[] bigIntToBytes( @@ -112,18 +167,61 @@ public class KeyAgreementSpi throw new InvalidKeyException("Invalid DH PublicKey"); } - result = peerY.modPow(x, p); - if (result.compareTo(ONE) == 0) + // BEGIN Android-removed: Unsupported algorithms + /* + if (unifiedAgreement != null) { - throw new InvalidKeyException("Shared key can't be 1"); - } + if (!lastPhase) + { + throw new IllegalStateException("unified Diffie-Hellman can use only two key pairs"); + } + + DHPublicKeyParameters staticKey = generatePublicKeyParameter((PublicKey)key); + DHPublicKeyParameters ephemKey = generatePublicKeyParameter(dheParameters.getOtherPartyEphemeralKey()); + + DHUPublicParameters pKey = new DHUPublicParameters(staticKey, ephemKey); + + result = unifiedAgreement.calculateAgreement(pKey); - if (lastPhase) + return null; + } + else if (mqvAgreement != null) { + if (!lastPhase) + { + throw new IllegalStateException("MQV Diffie-Hellman can use only two key pairs"); + } + + DHPublicKeyParameters staticKey = generatePublicKeyParameter((PublicKey)key); + DHPublicKeyParameters ephemKey = generatePublicKeyParameter(mqvParameters.getOtherPartyEphemeralKey()); + + DHMQVPublicParameters pKey = new DHMQVPublicParameters(staticKey, ephemKey); + + result = bigIntToBytes(mqvAgreement.calculateAgreement(pKey)); + return null; } + else + { + */ + // END Android-removed: Unsupported algorithms + BigInteger res = peerY.modPow(x, p); + if (res.compareTo(ONE) == 0) + { + throw new InvalidKeyException("Shared key can't be 1"); + } + + result = bigIntToBytes(res); - return new BCDHPublicKey(result, pubKey.getParams()); + if (lastPhase) + { + return null; + } + + return new BCDHPublicKey(res, pubKey.getParams()); + /* + } + */ } protected byte[] engineGenerateSecret() @@ -159,12 +257,10 @@ public class KeyAgreementSpi throw new IllegalStateException("Diffie-Hellman not initialised."); } - byte[] res = bigIntToBytes(result); - // for JSSE compatibility if (algorithm.equals("TlsPremasterSecret")) { - return new SecretKeySpec(trimZeroes(res), algorithm); + return new SecretKeySpec(trimZeroes(result), algorithm); } return super.engineGenerateSecret(algorithm); @@ -190,11 +286,70 @@ public class KeyAgreementSpi this.p = p.getP(); this.g = p.getG(); + // Android-removed: Unsupported algorithm + // this.dheParameters = null; + this.ukmParameters = null; + } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (params instanceof DHUParameterSpec) + { + if (unifiedAgreement == null) + { + throw new InvalidAlgorithmParameterException("agreement algorithm not DHU based"); + } + this.p = privKey.getParams().getP(); + this.g = privKey.getParams().getG(); + this.dheParameters = (DHUParameterSpec)params; + this.ukmParameters = ((DHUParameterSpec)params).getUserKeyingMaterial(); + + if (dheParameters.getEphemeralPublicKey() != null) + { + unifiedAgreement.init(new DHUPrivateParameters(generatePrivateKeyParameter(privKey), + generatePrivateKeyParameter(dheParameters.getEphemeralPrivateKey()), + generatePublicKeyParameter(dheParameters.getEphemeralPublicKey()))); + } + else + { + unifiedAgreement.init(new DHUPrivateParameters(generatePrivateKeyParameter(privKey), + generatePrivateKeyParameter(dheParameters.getEphemeralPrivateKey()))); + } } + else if (params instanceof MQVParameterSpec) + { + if (mqvAgreement == null) + { + throw new InvalidAlgorithmParameterException("agreement algorithm not MQV based"); + } + this.p = privKey.getParams().getP(); + this.g = privKey.getParams().getG(); + this.mqvParameters = (MQVParameterSpec)params; + this.ukmParameters = ((MQVParameterSpec)params).getUserKeyingMaterial(); + + if (mqvParameters.getEphemeralPublicKey() != null) + { + mqvAgreement.init(new DHMQVPrivateParameters(generatePrivateKeyParameter(privKey), + generatePrivateKeyParameter(mqvParameters.getEphemeralPrivateKey()), + generatePublicKeyParameter(mqvParameters.getEphemeralPublicKey()))); + } + else + { + mqvAgreement.init(new DHMQVPrivateParameters(generatePrivateKeyParameter(privKey), + generatePrivateKeyParameter(mqvParameters.getEphemeralPrivateKey()))); + } + } + */ + // END Android-removed: Unsupported algorithms else if (params instanceof UserKeyingMaterialSpec) { + if (kdf == null) + { + throw new InvalidAlgorithmParameterException("no KDF specified for UserKeyingMaterialSpec"); + } this.p = privKey.getParams().getP(); this.g = privKey.getParams().getG(); + // Android-removed: Unsupported algorithm + // this.dheParameters = null; this.ukmParameters = ((UserKeyingMaterialSpec)params).getUserKeyingMaterial(); } else @@ -208,7 +363,8 @@ public class KeyAgreementSpi this.g = privKey.getParams().getG(); } - this.x = this.result = privKey.getX(); + this.x = privKey.getX(); + this.result = bigIntToBytes(x); } protected void engineInit( @@ -225,15 +381,69 @@ public class KeyAgreementSpi this.p = privKey.getParams().getP(); this.g = privKey.getParams().getG(); - this.x = this.result = privKey.getX(); + this.x = privKey.getX(); + this.result = bigIntToBytes(x); } protected byte[] calcSecret() { - return bigIntToBytes(result); + return result; } - // BEGIN Android-removed: Unsupported algorithm + private DHPrivateKeyParameters generatePrivateKeyParameter(PrivateKey privKey) + throws InvalidKeyException + { + if (privKey instanceof DHPrivateKey) + { + if (privKey instanceof BCDHPrivateKey) + { + return ((BCDHPrivateKey)privKey).engineGetKeyParameters(); + } + else + { + DHPrivateKey pub = (DHPrivateKey)privKey; + + DHParameterSpec params = pub.getParams(); + return new DHPrivateKeyParameters(pub.getX(), + new DHParameters(params.getP(), params.getG(), null, params.getL())); + } + } + else + { + throw new InvalidKeyException("private key not a DHPrivateKey"); + } + } + + private DHPublicKeyParameters generatePublicKeyParameter(PublicKey pubKey) + throws InvalidKeyException + { + if (pubKey instanceof DHPublicKey) + { + if (pubKey instanceof BCDHPublicKey) + { + return ((BCDHPublicKey)pubKey).engineGetKeyParameters(); + } + else + { + DHPublicKey pub = (DHPublicKey)pubKey; + + DHParameterSpec params = pub.getParams(); + + if (params instanceof DHDomainParameterSpec) + { + return new DHPublicKeyParameters(pub.getY(), ((DHDomainParameterSpec)params).getDomainParameters()); + } + return new DHPublicKeyParameters(pub.getY(), + new DHParameters(params.getP(), params.getG(), null, params.getL())); + } + } + else + { + throw new InvalidKeyException("public key not a DHPublicKey"); + } + } + + // BEGIN Android-removed: Unsupported algorithms /* public static class DHwithRFC2631KDF extends KeyAgreementSpi @@ -243,6 +453,276 @@ public class KeyAgreementSpi super("DHwithRFC2631KDF", new DHKEKGenerator(DigestFactory.createSHA1())); } } + + public static class DHwithSHA1KDF + extends KeyAgreementSpi + { + public DHwithSHA1KDF() + { + super("DHwithSHA1CKDF", new KDF2BytesGenerator(DigestFactory.createSHA1())); + } + } + + public static class DHwithSHA224KDF + extends KeyAgreementSpi + { + public DHwithSHA224KDF() + { + super("DHwithSHA224CKDF", new KDF2BytesGenerator(DigestFactory.createSHA224())); + } + } + + public static class DHwithSHA256KDF + extends KeyAgreementSpi + { + public DHwithSHA256KDF() + { + super("DHwithSHA256CKDF", new KDF2BytesGenerator(DigestFactory.createSHA256())); + } + } + + public static class DHwithSHA384KDF + extends KeyAgreementSpi + { + public DHwithSHA384KDF() + { + super("DHwithSHA384KDF", new KDF2BytesGenerator(DigestFactory.createSHA384())); + } + } + + public static class DHwithSHA512KDF + extends KeyAgreementSpi + { + public DHwithSHA512KDF() + { + super("DHwithSHA512KDF", new KDF2BytesGenerator(DigestFactory.createSHA512())); + } + } + + public static class DHwithSHA1CKDF + extends KeyAgreementSpi + { + public DHwithSHA1CKDF() + { + super("DHwithSHA1CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA1())); + } + } + + public static class DHwithSHA224CKDF + extends KeyAgreementSpi + { + public DHwithSHA224CKDF() + { + super("DHwithSHA224CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA224())); + } + } + + public static class DHwithSHA256CKDF + extends KeyAgreementSpi + { + public DHwithSHA256CKDF() + { + super("DHwithSHA256CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA256())); + } + } + + public static class DHwithSHA384CKDF + extends KeyAgreementSpi + { + public DHwithSHA384CKDF() + { + super("DHwithSHA384CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA384())); + } + } + + public static class DHwithSHA512CKDF + extends KeyAgreementSpi + { + public DHwithSHA512CKDF() + { + super("DHwithSHA512CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA512())); + } + } + + public static class DHUwithSHA1KDF + extends KeyAgreementSpi + { + public DHUwithSHA1KDF() + { + super("DHUwithSHA1KDF", new DHUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); + } + } + + public static class DHUwithSHA224KDF + extends KeyAgreementSpi + { + public DHUwithSHA224KDF() + { + super("DHUwithSHA224KDF", new DHUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224())); + } + } + + public static class DHUwithSHA256KDF + extends KeyAgreementSpi + { + public DHUwithSHA256KDF() + { + super("DHUwithSHA256KDF", new DHUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256())); + } + } + + public static class DHUwithSHA384KDF + extends KeyAgreementSpi + { + public DHUwithSHA384KDF() + { + super("DHUwithSHA384KDF", new DHUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384())); + } + } + + public static class DHUwithSHA512KDF + extends KeyAgreementSpi + { + public DHUwithSHA512KDF() + { + super("DHUwithSHA512KDF", new DHUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); + } + } + + public static class DHUwithSHA1CKDF + extends KeyAgreementSpi + { + public DHUwithSHA1CKDF() + { + super("DHUwithSHA1CKDF", new DHUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1())); + } + } + + public static class DHUwithSHA224CKDF + extends KeyAgreementSpi + { + public DHUwithSHA224CKDF() + { + super("DHUwithSHA224CKDF", new DHUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224())); + } + } + + public static class DHUwithSHA256CKDF + extends KeyAgreementSpi + { + public DHUwithSHA256CKDF() + { + super("DHUwithSHA256CKDF", new DHUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256())); + } + } + + public static class DHUwithSHA384CKDF + extends KeyAgreementSpi + { + public DHUwithSHA384CKDF() + { + super("DHUwithSHA384CKDF", new DHUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384())); + } + } + + public static class DHUwithSHA512CKDF + extends KeyAgreementSpi + { + public DHUwithSHA512CKDF() + { + super("DHUwithSHA512CKDF", new DHUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512())); + } + } + + public static class MQVwithSHA1KDF + extends KeyAgreementSpi + { + public MQVwithSHA1KDF() + { + super("MQVwithSHA1KDF", new MQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); + } + } + + public static class MQVwithSHA224KDF + extends KeyAgreementSpi + { + public MQVwithSHA224KDF() + { + super("MQVwithSHA224KDF", new MQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224())); + } + } + + public static class MQVwithSHA256KDF + extends KeyAgreementSpi + { + public MQVwithSHA256KDF() + { + super("MQVwithSHA256KDF", new MQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256())); + } + } + + public static class MQVwithSHA384KDF + extends KeyAgreementSpi + { + public MQVwithSHA384KDF() + { + super("MQVwithSHA384KDF", new MQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384())); + } + } + + public static class MQVwithSHA512KDF + extends KeyAgreementSpi + { + public MQVwithSHA512KDF() + { + super("MQVwithSHA512KDF", new MQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); + } + } + + public static class MQVwithSHA1CKDF + extends KeyAgreementSpi + { + public MQVwithSHA1CKDF() + { + super("MQVwithSHA1CKDF", new MQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1())); + } + } + + public static class MQVwithSHA224CKDF + extends KeyAgreementSpi + { + public MQVwithSHA224CKDF() + { + super("MQVwithSHA224CKDF", new MQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224())); + } + } + + public static class MQVwithSHA256CKDF + extends KeyAgreementSpi + { + public MQVwithSHA256CKDF() + { + super("MQVwithSHA256CKDF", new MQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256())); + } + } + + public static class MQVwithSHA384CKDF + extends KeyAgreementSpi + { + public MQVwithSHA384CKDF() + { + super("MQVwithSHA384CKDF", new MQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384())); + } + } + + public static class MQVwithSHA512CKDF + extends KeyAgreementSpi + { + public MQVwithSHA512CKDF() + { + super("MQVwithSHA512CKDF", new MQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512())); + } + } */ - // END Android-removed: Unsupported algorithm + // END Android-removed: Unsupported algorithms } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java index 864bf56f..1e426b12 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java @@ -9,6 +9,7 @@ import java.util.Hashtable; import javax.crypto.spec.DHParameterSpec; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.generators.DHBasicKeyPairGenerator; import org.bouncycastle.crypto.generators.DHParametersGenerator; import org.bouncycastle.crypto.params.DHKeyGenerationParameters; @@ -16,6 +17,7 @@ import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.crypto.params.DHPrivateKeyParameters; import org.bouncycastle.crypto.params.DHPublicKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.PrimeCertaintyCalculator; +import org.bouncycastle.jcajce.spec.DHDomainParameterSpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.Integers; @@ -28,7 +30,7 @@ public class KeyPairGeneratorSpi DHKeyGenerationParameters param; DHBasicKeyPairGenerator engine = new DHBasicKeyPairGenerator(); int strength = 2048; - SecureRandom random = new SecureRandom(); + SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); boolean initialised = false; public KeyPairGeneratorSpi() @@ -56,12 +58,28 @@ public class KeyPairGeneratorSpi } DHParameterSpec dhParams = (DHParameterSpec)params; - param = new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL())); - + try + { + param = convertParams(random, dhParams); + } + catch (IllegalArgumentException e) + { + throw new InvalidAlgorithmParameterException(e.getMessage(), e); + } + engine.init(param); initialised = true; } + private DHKeyGenerationParameters convertParams(SecureRandom random, DHParameterSpec dhParams) + { + if (dhParams instanceof DHDomainParameterSpec) + { + return new DHKeyGenerationParameters(random, ((DHDomainParameterSpec)dhParams).getDomainParameters()); + } + return new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL())); + } + public KeyPair generateKeyPair() { if (!initialised) @@ -77,8 +95,8 @@ public class KeyPairGeneratorSpi DHParameterSpec dhParams = BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(strength); if (dhParams != null) - { - param = new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL())); + { + param = convertParams(random, dhParams); } else { diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java index 6a0dffa1..1cc7cb3c 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java @@ -7,6 +7,7 @@ import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.DSAParameterSpec; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.generators.DSAParametersGenerator; import org.bouncycastle.crypto.params.DSAParameterGenerationParameters; @@ -71,7 +72,7 @@ public class AlgorithmParameterGeneratorSpi if (random == null) { - random = new SecureRandom(); + random = CryptoServicesRegistrar.getSecureRandom(); } int certainty = PrimeCertaintyCalculator.getDefaultCertainty(strength); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java index 0fb4bd9e..d19c90ed 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java @@ -21,6 +21,7 @@ import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; +import org.bouncycastle.util.Strings; public class BCDSAPrivateKey implements DSAPrivateKey, PKCS12BagAttributeCarrier @@ -164,4 +165,17 @@ public class BCDSAPrivateKey out.writeObject(dsaSpec.getQ()); out.writeObject(dsaSpec.getG()); } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + BigInteger y = getParams().getG().modPow(x, getParams().getP()); + + buf.append("DSA Private Key [").append(DSAUtil.generateKeyFingerprint(y, getParams())).append("]").append(nl); + buf.append(" Y: ").append(y.toString(16)).append(nl); + + return buf.toString(); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java index 13223cb6..601fddd6 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java @@ -137,8 +137,8 @@ public class BCDSAPublicKey StringBuffer buf = new StringBuffer(); String nl = Strings.lineSeparator(); - buf.append("DSA Public Key").append(nl); - buf.append(" y: ").append(this.getY().toString(16)).append(nl); + buf.append("DSA Public Key [").append(DSAUtil.generateKeyFingerprint(y, getParams())).append("]").append(nl); + buf.append(" Y: ").append(this.getY().toString(16)).append(nl); return buf.toString(); } 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 0384b1c8..8d1653f1 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 @@ -1,6 +1,5 @@ package org.bouncycastle.jcajce.provider.asymmetric.dsa; -import java.io.IOException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.PrivateKey; @@ -10,23 +9,20 @@ import java.security.SignatureException; import java.security.SignatureSpi; import java.security.spec.AlgorithmParameterSpec; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.DSAExt; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.NullDigest; // Android-added: Check DSA keys when generated import org.bouncycastle.crypto.params.DSAKeyParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.signers.DSAEncoding; // Android-removed: Unsupported algorithm // import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import org.bouncycastle.crypto.signers.StandardDSAEncoding; // Android-changed: Use Android digests // import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.crypto.digests.AndroidDigestFactory; @@ -37,12 +33,13 @@ public class DSASigner implements PKCSObjectIdentifiers, X509ObjectIdentifiers { private Digest digest; - private DSA signer; + private DSAExt signer; + private DSAEncoding encoding = StandardDSAEncoding.INSTANCE; private SecureRandom random; protected DSASigner( Digest digest, - DSA signer) + DSAExt signer) { this.digest = digest; this.signer = signer; @@ -111,9 +108,9 @@ public class DSASigner try { - BigInteger[] sig = signer.generateSignature(hash); + BigInteger[] sig = signer.generateSignature(hash); - return derEncode(sig[0], sig[1]); + return encoding.encode(signer.getOrder(), sig[0], sig[1]); } catch (Exception e) { @@ -129,11 +126,11 @@ public class DSASigner digest.doFinal(hash, 0); - BigInteger[] sig; + BigInteger[] sig; try { - sig = derDecode(sigBytes); + sig = encoding.decode(signer.getOrder(), sigBytes); } catch (Exception e) { @@ -172,7 +169,7 @@ public class DSASigner // END Android-added: Check DSA keys when generated /** - * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)"> + * @deprecated replaced with #engineSetParameter(java.security.spec.AlgorithmParameterSpec) */ protected void engineSetParameter( String param, @@ -187,36 +184,7 @@ public class DSASigner protected Object engineGetParameter( String param) { - throw new UnsupportedOperationException("engineSetParameter unsupported"); - } - - private byte[] derEncode( - BigInteger r, - BigInteger s) - throws IOException - { - ASN1Integer[] rs = new ASN1Integer[]{ new ASN1Integer(r), new ASN1Integer(s) }; - return new DERSequence(rs).getEncoded(ASN1Encoding.DER); - } - - private BigInteger[] derDecode( - byte[] encoding) - throws IOException - { - ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); - if (s.size() != 2) - { - throw new IOException("malformed signature"); - } - if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER))) - { - throw new IOException("malformed signature"); - } - - return new BigInteger[]{ - ((ASN1Integer)s.getObjectAt(0)).getValue(), - ((ASN1Integer)s.getObjectAt(1)).getValue() - }; + throw new UnsupportedOperationException("engineGetParameter unsupported"); } static public class stdDSA diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java index d768ae6d..f7ebf959 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java @@ -1,12 +1,12 @@ package org.bouncycastle.jcajce.provider.asymmetric.dsa; +import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.interfaces.DSAParams; import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPublicKey; -import java.security.spec.DSAParameterSpec; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; @@ -15,7 +15,8 @@ import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; -import org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Fingerprint; /** * utility class for converting jce/jca DSA objects @@ -26,11 +27,16 @@ public class DSAUtil public static final ASN1ObjectIdentifier[] dsaOids = { X9ObjectIdentifiers.id_dsa, - // Android-added: Add missing OID for DSA-with-SHA1 - X9ObjectIdentifiers.id_dsa_with_sha1, - OIWObjectIdentifiers.dsaWithSHA1 + OIWObjectIdentifiers.dsaWithSHA1, + X9ObjectIdentifiers.id_dsa_with_sha1 }; + /** + * Return true if the passed in OID could be associated with a DSA key. + * + * @param algOid algorithm OID from a key. + * @return true if it's for a DSA key, false otherwise. + */ public static boolean isDsaOid( ASN1ObjectIdentifier algOid) { @@ -97,4 +103,9 @@ public class DSAUtil throw new InvalidKeyException("can't identify DSA private key."); } + + static String generateKeyFingerprint(BigInteger y, DSAParams params) + { + return new Fingerprint(Arrays.concatenate(y.toByteArray(), params.getP().toByteArray(), params.getQ().toByteArray(), params.getG().toByteArray())).toString(); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java index 7816320d..10b160f4 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java @@ -15,7 +15,17 @@ import java.security.spec.KeySpec; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.params.DSAParameters; +import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; +import org.bouncycastle.crypto.params.DSAPublicKeyParameters; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil; +// import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec; +// import org.bouncycastle.jce.spec.OpenSSHPublicKeySpec; public class KeyFactorySpi extends BaseKeyFactorySpi @@ -41,6 +51,34 @@ public class KeyFactorySpi return new DSAPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()); } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (spec.isAssignableFrom(OpenSSHPublicKeySpec.class) && key instanceof java.security.interfaces.DSAPublicKey) + { + DSAPublicKey k = (DSAPublicKey)key; + try + { + return new OpenSSHPublicKeySpec(OpenSSHPublicKeyUtil.encodePublicKey(new DSAPublicKeyParameters(k.getY(), new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG())))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else if (spec.isAssignableFrom(OpenSSHPrivateKeySpec.class) && key instanceof java.security.interfaces.DSAPrivateKey) + { + DSAPrivateKey k = (DSAPrivateKey)key; + try + { + return new OpenSSHPrivateKeySpec(OpenSSHPrivateKeyUtil.encodePrivateKey(new DSAPrivateKeyParameters(k.getX(), new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG())))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + */ + // END Android-removed: Unsupported algorithms return super.engineGetKeySpec(key, spec); } @@ -99,6 +137,28 @@ public class KeyFactorySpi { return new BCDSAPrivateKey((DSAPrivateKeySpec)keySpec); } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (keySpec instanceof OpenSSHPrivateKeySpec) + { + CipherParameters params = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(((OpenSSHPrivateKeySpec)keySpec).getEncoded()); + if (params instanceof DSAPrivateKeyParameters) + { + return engineGeneratePrivate( + new DSAPrivateKeySpec( + ((DSAPrivateKeyParameters)params).getX(), + ((DSAPrivateKeyParameters)params).getParameters().getP(), + ((DSAPrivateKeyParameters)params).getParameters().getQ(), + ((DSAPrivateKeyParameters)params).getParameters().getG())); + } + else + { + throw new IllegalArgumentException("openssh private key is not dsa privare key"); + } + + } + */ + // END Android-removed: Unsupported algorithms return super.engineGeneratePrivate(keySpec); } @@ -118,12 +178,32 @@ public class KeyFactorySpi throw new InvalidKeySpecException("invalid KeySpec: " + e.getMessage()) { public Throwable getCause() - { - return e; - } + { + return e; + } }; } } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (keySpec instanceof OpenSSHPublicKeySpec) + { + CipherParameters parameters = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded()); + + if (parameters instanceof DSAPublicKeyParameters) + { + return engineGeneratePublic( + new DSAPublicKeySpec(((DSAPublicKeyParameters)parameters).getY(), + ((DSAPublicKeyParameters)parameters).getParameters().getP(), + ((DSAPublicKeyParameters)parameters).getParameters().getQ(), + ((DSAPublicKeyParameters)parameters).getParameters().getG())); + } + + throw new IllegalArgumentException("openssh public key is not dsa public key"); + + } + */ + // END Android-removed: Unsupported algorithms return super.engineGeneratePublic(keySpec); } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java index 366e6dca..a7ed3e06 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java @@ -9,6 +9,7 @@ import java.security.spec.DSAParameterSpec; import java.util.Hashtable; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.generators.DSAKeyPairGenerator; import org.bouncycastle.crypto.generators.DSAParametersGenerator; @@ -18,6 +19,7 @@ import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.PrimeCertaintyCalculator; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.Integers; import org.bouncycastle.util.Properties; @@ -35,7 +37,7 @@ public class KeyPairGeneratorSpi // a sufficiently long digest to work with 2048-bit keys. int strength = 1024; - SecureRandom random = new SecureRandom(); + SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); boolean initialised = false; public KeyPairGeneratorSpi() @@ -52,9 +54,26 @@ public class KeyPairGeneratorSpi throw new InvalidParameterException("strength must be from 512 - 4096 and a multiple of 1024 above 1024"); } - this.strength = strength; - this.random = random; - this.initialised = false; + // Android-added: Treat null SecureRandom as default + if (random == null) { + random = new SecureRandom(); + } + + DSAParameterSpec spec = BouncyCastleProvider.CONFIGURATION.getDSADefaultParameters(strength); + + if (spec != null) + { + param = new DSAKeyGenerationParameters(random, new DSAParameters(spec.getP(), spec.getQ(), spec.getG())); + + engine.init(param); + this.initialised = true; + } + else + { + this.strength = strength; + this.random = random; + this.initialised = false; + } } public void initialize( @@ -68,6 +87,11 @@ public class KeyPairGeneratorSpi } DSAParameterSpec dsaParams = (DSAParameterSpec)params; + // Android-added: Treat null SecureRandom as default + if (random == null) { + random = new SecureRandom(); + } + param = new DSAKeyGenerationParameters(random, new DSAParameters(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG())); engine.init(param); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java index 9f56a55a..7851b256 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java @@ -1,6 +1,7 @@ package org.bouncycastle.jcajce.provider.asymmetric.ec; import java.io.IOException; +import java.math.BigInteger; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; @@ -42,7 +43,9 @@ public class AlgorithmParametersSpi throw new InvalidParameterSpecException("EC curve name not recognized: " + ecGenParameterSpec.getName()); } curveName = ecGenParameterSpec.getName(); - ecParameterSpec = EC5Util.convertToSpec(params); + ECParameterSpec baseSpec = EC5Util.convertToSpec(params); + ecParameterSpec = new ECNamedCurveSpec(curveName, + baseSpec.getCurve(), baseSpec.getGenerator(), baseSpec.getOrder(), BigInteger.valueOf(baseSpec.getCofactor())); } else if (algorithmParameterSpec instanceof ECParameterSpec) { 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 815bcac0..714f9100 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 @@ -32,7 +32,6 @@ import org.bouncycastle.jce.interfaces.ECPointEncoder; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.util.Strings; public class BCECPrivateKey implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder @@ -120,30 +119,27 @@ public class BCECPrivateKey ECParameterSpec spec, ProviderConfiguration configuration) { - ECDomainParameters dp = params.getParameters(); - this.algorithm = algorithm; this.d = params.getD(); this.configuration = configuration; if (spec == null) { + ECDomainParameters dp = params.getParameters(); EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); this.ecSpec = new ECParameterSpec( - ellipticCurve, - new ECPoint( - dp.getG().getAffineXCoord().toBigInteger(), - dp.getG().getAffineYCoord().toBigInteger()), - dp.getN(), - dp.getH().intValue()); + ellipticCurve, + EC5Util.convertPoint(dp.getG()), + dp.getN(), + dp.getH().intValue()); } else { this.ecSpec = spec; } - publicKey = getPublicKeyDetails(pubKey); + this.publicKey = getPublicKeyDetails(pubKey); } public BCECPrivateKey( @@ -153,23 +149,20 @@ public class BCECPrivateKey org.bouncycastle.jce.spec.ECParameterSpec spec, ProviderConfiguration configuration) { - ECDomainParameters dp = params.getParameters(); - this.algorithm = algorithm; this.d = params.getD(); this.configuration = configuration; if (spec == null) { + ECDomainParameters dp = params.getParameters(); EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); this.ecSpec = new ECParameterSpec( - ellipticCurve, - new ECPoint( - dp.getG().getAffineXCoord().toBigInteger(), - dp.getG().getAffineYCoord().toBigInteger()), - dp.getN(), - dp.getH().intValue()); + ellipticCurve, + EC5Util.convertPoint(dp.getG()), + dp.getN(), + dp.getH().intValue()); } else { @@ -180,11 +173,11 @@ public class BCECPrivateKey try { - publicKey = getPublicKeyDetails(pubKey); + this.publicKey = getPublicKeyDetails(pubKey); } catch (Exception e) { - publicKey = null; // not all curves are encodable + this.publicKey = null; // not all curves are encodable } } @@ -370,14 +363,12 @@ public class BCECPrivateKey public String toString() { - StringBuffer buf = new StringBuffer(); - String nl = Strings.lineSeparator(); - - buf.append("EC Private Key").append(nl); - buf.append(" S: ").append(this.d.toString(16)).append(nl); - - return buf.toString(); + return ECUtil.privateKeyToString("EC", d, engineGetSpec()); + } + private org.bouncycastle.math.ec.ECPoint calculateQ(org.bouncycastle.jce.spec.ECParameterSpec spec) + { + return spec.getG().multiply(d).normalize(); } private DERBitString getPublicKeyDetails(BCECPublicKey pub) 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 443c5f63..9236787c 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 @@ -29,7 +29,6 @@ import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jce.interfaces.ECPointEncoder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.util.Strings; public class BCECPublicKey implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder @@ -181,12 +180,10 @@ public class BCECPublicKey private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp) { return new ECParameterSpec( - ellipticCurve, - new ECPoint( - dp.getG().getAffineXCoord().toBigInteger(), - dp.getG().getAffineYCoord().toBigInteger()), - dp.getN(), - dp.getH().intValue()); + ellipticCurve, + EC5Util.convertPoint(dp.getG()), + dp.getN(), + dp.getH().intValue()); } private void populateFromPubKeyInfo(SubjectPublicKeyInfo info) @@ -263,9 +260,7 @@ public class BCECPublicKey public ECPoint getW() { - org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ(); - - return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger()); + return EC5Util.convertPoint(ecPublicKey.getQ()); } public org.bouncycastle.math.ec.ECPoint getQ() @@ -297,16 +292,7 @@ public class BCECPublicKey public String toString() { - StringBuffer buf = new StringBuffer(); - String nl = Strings.lineSeparator(); - org.bouncycastle.math.ec.ECPoint q = ecPublicKey.getQ(); - - buf.append("EC Public Key").append(nl); - buf.append(" X: ").append(q.getAffineXCoord().toBigInteger().toString(16)).append(nl); - buf.append(" Y: ").append(q.getAffineYCoord().toBigInteger().toString(16)).append(nl); - - return buf.toString(); - + return ECUtil.publicKeyToString("EC", ecPublicKey.getQ(), engineGetSpec()); } public void setPointFormat(String style) 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 dd286312..7070df87 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 @@ -16,9 +16,13 @@ import org.bouncycastle.crypto.DerivationFunction; import org.bouncycastle.crypto.agreement.ECDHBasicAgreement; // BEGIN Android-removed: Unsupported algorithms // import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement; +// import org.bouncycastle.crypto.agreement.ECDHCUnifiedAgreement; // import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement; // import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator; +// import org.bouncycastle.crypto.digests.RIPEMD160Digest; // import org.bouncycastle.crypto.generators.KDF2BytesGenerator; +// import org.bouncycastle.crypto.params.ECDHUPrivateParameters; +// import org.bouncycastle.crypto.params.ECDHUPublicParameters; // END Android-removed: Unsupported algorithms import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; @@ -31,6 +35,7 @@ import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; // BEGIN Android-removed: Unsupported algorithms +// import org.bouncycastle.jcajce.spec.DHUParameterSpec; // import org.bouncycastle.jcajce.spec.MQVParameterSpec; // END Android-removed: Unsupported algorithms import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec; @@ -40,11 +45,12 @@ import org.bouncycastle.jce.interfaces.ECPublicKey; // import org.bouncycastle.jce.interfaces.MQVPrivateKey; // import org.bouncycastle.jce.interfaces.MQVPublicKey; // END Android-removed: Unsupported algorithms +import org.bouncycastle.util.Arrays; /** * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363 * both the simple one, and the simple one with cofactors are supported. - * + * <p> * Also, MQV key agreement per SEC-1 */ public class KeyAgreementSpi @@ -52,14 +58,15 @@ public class KeyAgreementSpi { private static final X9IntegerConverter converter = new X9IntegerConverter(); - private String kaAlgorithm; + private String kaAlgorithm; - private ECDomainParameters parameters; - private BasicAgreement agreement; + private ECDomainParameters parameters; + private Object agreement; // Android-removed: Unsupported algorithms // private MQVParameterSpec mqvParameters; - private BigInteger result; + // private DHUParameterSpec dheParameters; + private byte[] result; protected KeyAgreementSpi( String kaAlgorithm, @@ -72,15 +79,30 @@ public class KeyAgreementSpi this.agreement = agreement; } + // BEGIN Android-removed: Unsupported algorithms + /* + protected KeyAgreementSpi( + String kaAlgorithm, + ECDHCUnifiedAgreement agreement, + DerivationFunction kdf) + { + super(kaAlgorithm, kdf); + + this.kaAlgorithm = kaAlgorithm; + this.agreement = agreement; + } + */ + // END Android-removed: Unsupported algorithms + protected byte[] bigIntToBytes( - BigInteger r) + BigInteger r) { return converter.integerToBytes(r, converter.getByteLength(parameters.getCurve())); } protected Key engineDoPhase( - Key key, - boolean lastPhase) + Key key, + boolean lastPhase) throws InvalidKeyException, IllegalStateException { if (parameters == null) @@ -93,7 +115,7 @@ public class KeyAgreementSpi throw new IllegalStateException(kaAlgorithm + " can only be between two parties."); } - CipherParameters pubKey; + CipherParameters pubKey; // BEGIN Android-removed: Unsupported algorithms /* if (agreement instanceof ECMQVBasicAgreement) @@ -118,6 +140,15 @@ public class KeyAgreementSpi pubKey = new MQVPublicParameters(staticKey, ephemKey); } } + else if (agreement instanceof ECDHCUnifiedAgreement) + { + ECPublicKeyParameters staticKey = (ECPublicKeyParameters) + ECUtils.generatePublicKeyParameter((PublicKey)key); + ECPublicKeyParameters ephemKey = (ECPublicKeyParameters) + ECUtils.generatePublicKeyParameter(dheParameters.getOtherPartyEphemeralKey()); + + pubKey = new ECDHUPublicParameters(staticKey, ephemKey); + } else */ // END Android-removed: Unsupported algorithms @@ -133,16 +164,31 @@ public class KeyAgreementSpi try { - result = agreement.calculateAgreement(pubKey); + // BEGIN Android-removed: Unsupported algorithms + /* + if (agreement instanceof BasicAgreement) + { + */ + // END Android-removed: Unsupported algorithms + result = bigIntToBytes(((BasicAgreement)agreement).calculateAgreement(pubKey)); + // BEGIN Android-removed: Unsupported algorithms + /* + } + else + { + result = ((ECDHCUnifiedAgreement)agreement).calculateAgreement(pubKey); + } + */ + // END Android-removed: Unsupported algorithms } catch (final Exception e) { throw new InvalidKeyException("calculation failed: " + e.getMessage()) { public Throwable getCause() - { - return e; - } + { + return e; + } }; } @@ -150,13 +196,14 @@ public class KeyAgreementSpi } protected void engineInit( - Key key, - AlgorithmParameterSpec params, - SecureRandom random) + Key key, + AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { // Android-removed: Unsupported algorithms - // if (params != null && !(params instanceof MQVParameterSpec || params instanceof UserKeyingMaterialSpec)) + // if (params != null && + // !(params instanceof MQVParameterSpec || params instanceof UserKeyingMaterialSpec || params instanceof DHUParameterSpec)) if (params != null && !(params instanceof UserKeyingMaterialSpec)) { throw new InvalidAlgorithmParameterException("No algorithm parameters supported"); @@ -166,15 +213,23 @@ public class KeyAgreementSpi } protected void engineInit( - Key key, - SecureRandom random) + Key key, + SecureRandom random) throws InvalidKeyException { - initFromKey(key, null); + try + { + initFromKey(key, null); + } + catch (InvalidAlgorithmParameterException e) + { + // this should never occur. + throw new InvalidKeyException(e.getMessage()); + } } private void initFromKey(Key key, AlgorithmParameterSpec parameterSpec) - throws InvalidKeyException + throws InvalidKeyException, InvalidAlgorithmParameterException { // BEGIN Android-removed: Unsupported algorithms /* @@ -183,7 +238,7 @@ public class KeyAgreementSpi mqvParameters = null; if (!(key instanceof MQVPrivateKey) && !(parameterSpec instanceof MQVParameterSpec)) { - throw new InvalidKeyException(kaAlgorithm + " key agreement requires " + throw new InvalidAlgorithmParameterException(kaAlgorithm + " key agreement requires " + getSimpleName(MQVParameterSpec.class) + " for initialisation"); } @@ -229,7 +284,38 @@ public class KeyAgreementSpi // TODO Validate that all the keys are using the same parameters? - agreement.init(localParams); + ((ECMQVBasicAgreement)agreement).init(localParams); + } + else if (parameterSpec instanceof DHUParameterSpec) + { + if (!(agreement instanceof ECDHCUnifiedAgreement)) + { + throw new InvalidAlgorithmParameterException(kaAlgorithm + " key agreement cannot be used with " + + getSimpleName(DHUParameterSpec.class)); + } + DHUParameterSpec dheParameterSpec = (DHUParameterSpec)parameterSpec; + ECPrivateKeyParameters staticPrivKey; + ECPrivateKeyParameters ephemPrivKey; + ECPublicKeyParameters ephemPubKey; + + staticPrivKey = (ECPrivateKeyParameters) + ECUtil.generatePrivateKeyParameter((PrivateKey)key); + ephemPrivKey = (ECPrivateKeyParameters) + ECUtil.generatePrivateKeyParameter(dheParameterSpec.getEphemeralPrivateKey()); + + ephemPubKey = null; + if (dheParameterSpec.getEphemeralPublicKey() != null) + { + ephemPubKey = (ECPublicKeyParameters) + ECUtils.generatePublicKeyParameter(dheParameterSpec.getEphemeralPublicKey()); + } + dheParameters = dheParameterSpec; + ukmParameters = dheParameterSpec.getUserKeyingMaterial(); + + ECDHUPrivateParameters localParams = new ECDHUPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey); + this.parameters = staticPrivKey.getParameters(); + + ((ECDHCUnifiedAgreement)agreement).init(localParams); } else */ @@ -240,11 +326,14 @@ public class KeyAgreementSpi throw new InvalidKeyException(kaAlgorithm + " key agreement requires " + getSimpleName(ECPrivateKey.class) + " for initialisation"); } - + if (kdf == null && parameterSpec instanceof UserKeyingMaterialSpec) + { + throw new InvalidAlgorithmParameterException("no KDF specified for UserKeyingMaterialSpec"); + } ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key); this.parameters = privKey.getParameters(); ukmParameters = (parameterSpec instanceof UserKeyingMaterialSpec) ? ((UserKeyingMaterialSpec)parameterSpec).getUserKeyingMaterial() : null; - agreement.init(privKey); + ((BasicAgreement)agreement).init(privKey); } } @@ -254,11 +343,10 @@ public class KeyAgreementSpi return fullName.substring(fullName.lastIndexOf('.') + 1); } - - + protected byte[] calcSecret() { - return bigIntToBytes(result); + return Arrays.clone(result); } public static class DH @@ -290,6 +378,15 @@ public class KeyAgreementSpi } } + public static class DHUC + extends KeyAgreementSpi + { + public DHUC() + { + super("ECCDHU", new ECDHCUnifiedAgreement(), null); + } + } + public static class DHwithSHA1KDF extends KeyAgreementSpi { @@ -372,22 +469,22 @@ public class KeyAgreementSpi } public static class DHwithSHA512KDFAndSharedInfo - extends KeyAgreementSpi - { - public DHwithSHA512KDFAndSharedInfo() - { - super("ECDHwithSHA512KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); - } - } - - public static class CDHwithSHA512KDFAndSharedInfo - extends KeyAgreementSpi - { - public CDHwithSHA512KDFAndSharedInfo() - { - super("ECCDHwithSHA512KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); - } - } + extends KeyAgreementSpi + { + public DHwithSHA512KDFAndSharedInfo() + { + super("ECDHwithSHA512KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); + } + } + + public static class CDHwithSHA512KDFAndSharedInfo + extends KeyAgreementSpi + { + public CDHwithSHA512KDFAndSharedInfo() + { + super("ECCDHwithSHA512KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); + } + } public static class MQVwithSHA1KDFAndSharedInfo extends KeyAgreementSpi @@ -514,6 +611,219 @@ public class KeyAgreementSpi super("ECMQVwithSHA512CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512())); } } - */ - // END Android-removed: Unsupported algorithms + + public static class MQVwithSHA1KDF + extends KeyAgreementSpi + { + public MQVwithSHA1KDF() + { + super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); + } + } + + public static class MQVwithSHA224KDF + extends KeyAgreementSpi + { + public MQVwithSHA224KDF() + { + super("ECMQVwithSHA224KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224())); + } + } + + public static class MQVwithSHA256KDF + extends KeyAgreementSpi + { + public MQVwithSHA256KDF() + { + super("ECMQVwithSHA256KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256())); + } + } + + public static class MQVwithSHA384KDF + extends KeyAgreementSpi + { + public MQVwithSHA384KDF() + { + super("ECMQVwithSHA384KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384())); + } + } + + public static class MQVwithSHA512KDF + extends KeyAgreementSpi + { + public MQVwithSHA512KDF() + { + super("ECMQVwithSHA512KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); + } + } + + public static class DHUwithSHA1CKDF + extends KeyAgreementSpi + { + public DHUwithSHA1CKDF() + { + super("ECCDHUwithSHA1CKDF", new ECDHCUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1())); + } + } + + public static class DHUwithSHA224CKDF + extends KeyAgreementSpi + { + public DHUwithSHA224CKDF() + { + super("ECCDHUwithSHA224CKDF", new ECDHCUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224())); + } + } + + public static class DHUwithSHA256CKDF + extends KeyAgreementSpi + { + public DHUwithSHA256CKDF() + { + super("ECCDHUwithSHA256CKDF", new ECDHCUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256())); + } + } + + public static class DHUwithSHA384CKDF + extends KeyAgreementSpi + { + public DHUwithSHA384CKDF() + { + super("ECCDHUwithSHA384CKDF", new ECDHCUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384())); + } + } + + public static class DHUwithSHA512CKDF + extends KeyAgreementSpi + { + public DHUwithSHA512CKDF() + { + super("ECCDHUwithSHA512CKDF", new ECDHCUnifiedAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512())); + } + } + + public static class DHUwithSHA1KDF + extends KeyAgreementSpi + { + public DHUwithSHA1KDF() + { + super("ECCDHUwithSHA1KDF", new ECDHCUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1())); + } + } + + public static class DHUwithSHA224KDF + extends KeyAgreementSpi + { + public DHUwithSHA224KDF() + { + super("ECCDHUwithSHA224KDF", new ECDHCUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224())); + } + } + + public static class DHUwithSHA256KDF + extends KeyAgreementSpi + { + public DHUwithSHA256KDF() + { + super("ECCDHUwithSHA256KDF", new ECDHCUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256())); + } + } + + public static class DHUwithSHA384KDF + extends KeyAgreementSpi + { + public DHUwithSHA384KDF() + { + super("ECCDHUwithSHA384KDF", new ECDHCUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384())); + } + } + + public static class DHUwithSHA512KDF + extends KeyAgreementSpi + { + public DHUwithSHA512KDF() + { + super("ECCDHUwithSHA512KDF", new ECDHCUnifiedAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512())); + } + } + + /** + * KeyAgreement according to BSI TR-03111 chapter 4.3.1 + * + public static class ECKAEGwithSHA1KDF + extends KeyAgreementSpi + { + public ECKAEGwithSHA1KDF() + { + super("ECKAEGwithSHA1KDF", new ECDHBasicAgreement(), + new KDF2BytesGenerator(DigestFactory.createSHA1())); + } + } + + /** + * KeyAgreement according to BSI TR-03111 chapter 4.3.1 + * + public static class ECKAEGwithRIPEMD160KDF + extends KeyAgreementSpi + { + public ECKAEGwithRIPEMD160KDF() + { + super("ECKAEGwithRIPEMD160KDF", new ECDHBasicAgreement(), + new KDF2BytesGenerator(new RIPEMD160Digest())); + } + } + + /** + * KeyAgreement according to BSI TR-03111 chapter 4.3.1 + * + public static class ECKAEGwithSHA224KDF + extends KeyAgreementSpi + { + public ECKAEGwithSHA224KDF() + { + super("ECKAEGwithSHA224KDF", new ECDHBasicAgreement(), + new KDF2BytesGenerator(DigestFactory.createSHA224())); + } + } + + /** + * KeyAgreement according to BSI TR-03111 chapter 4.3.1 + * + public static class ECKAEGwithSHA256KDF + extends KeyAgreementSpi + { + public ECKAEGwithSHA256KDF() + { + super("ECKAEGwithSHA256KDF", new ECDHBasicAgreement(), + new KDF2BytesGenerator(DigestFactory.createSHA256())); + } + } + + /** + * KeyAgreement according to BSI TR-03111 chapter 4.3.1 + * + public static class ECKAEGwithSHA384KDF + extends KeyAgreementSpi + { + public ECKAEGwithSHA384KDF() + { + super("ECKAEGwithSHA384KDF", new ECDHBasicAgreement(), + new KDF2BytesGenerator(DigestFactory.createSHA384())); + } + } + + /** + * KeyAgreement according to BSI TR-03111 chapter 4.3.1 + * + public static class ECKAEGwithSHA512KDF + extends KeyAgreementSpi + { + public ECKAEGwithSHA512KDF() + { + super("ECKAEGwithSHA512KDF", new ECDHBasicAgreement(), + new KDF2BytesGenerator(DigestFactory.createSHA512())); + } + } + */ + // END Android-removed: Unsupported algorithms } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java index 431b6bd3..19b538a8 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java @@ -12,8 +12,14 @@ import java.security.spec.KeySpec; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi; import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; @@ -22,6 +28,9 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.jce.spec.ECPrivateKeySpec; import org.bouncycastle.jce.spec.ECPublicKeySpec; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec; +// import org.bouncycastle.jce.spec.OpenSSHPublicKeySpec; public class KeyFactorySpi extends BaseKeyFactorySpi @@ -39,7 +48,7 @@ public class KeyFactorySpi } protected Key engineTranslateKey( - Key key) + Key key) throws InvalidKeyException { if (key instanceof ECPublicKey) @@ -55,70 +64,115 @@ public class KeyFactorySpi } protected KeySpec engineGetKeySpec( - Key key, - Class spec) - throws InvalidKeySpecException + Key key, + Class spec) + throws InvalidKeySpecException { - if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey) - { - ECPublicKey k = (ECPublicKey)key; - if (k.getParams() != null) - { - return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams()); - } - else - { - ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); - } - } - else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey) - { - ECPrivateKey k = (ECPrivateKey)key; - - if (k.getParams() != null) - { - return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams()); - } - else - { - ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); - } - } - else if (spec.isAssignableFrom(org.bouncycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey) - { - ECPublicKey k = (ECPublicKey)key; - if (k.getParams() != null) - { - return new org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false)); - } - else - { - ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - return new org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec); - } - } - else if (spec.isAssignableFrom(org.bouncycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey) - { - ECPrivateKey k = (ECPrivateKey)key; - - if (k.getParams() != null) - { - return new org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false)); - } - else - { - ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - return new org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), implicitSpec); - } - } - - return super.engineGetKeySpec(key, spec); + if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey) + { + ECPublicKey k = (ECPublicKey)key; + if (k.getParams() != null) + { + return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams()); + } + else + { + ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + + return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); + } + } + else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey) + { + ECPrivateKey k = (ECPrivateKey)key; + + if (k.getParams() != null) + { + return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams()); + } + else + { + ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + + return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); + } + } + else if (spec.isAssignableFrom(org.bouncycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey) + { + ECPublicKey k = (ECPublicKey)key; + if (k.getParams() != null) + { + return new org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false)); + } + else + { + ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + + return new org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec); + } + } + else if (spec.isAssignableFrom(org.bouncycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey) + { + ECPrivateKey k = (ECPrivateKey)key; + + if (k.getParams() != null) + { + return new org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false)); + } + else + { + ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + + return new org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), implicitSpec); + } + } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (spec.isAssignableFrom(OpenSSHPublicKeySpec.class) && key instanceof ECPublicKey) + { + if (key instanceof BCECPublicKey) + { + BCECPublicKey bcPk = (BCECPublicKey)key; + ECParameterSpec sc = bcPk.getParameters(); + try + { + return new OpenSSHPublicKeySpec( + OpenSSHPublicKeyUtil.encodePublicKey( + new ECPublicKeyParameters(bcPk.getQ(), new ECDomainParameters(sc.getCurve(), sc.getG(), sc.getN(), sc.getH(), sc.getSeed())))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else + { + throw new IllegalArgumentException("invalid key type: " + key.getClass().getName()); + } + } + else if (spec.isAssignableFrom(OpenSSHPrivateKeySpec.class) && key instanceof ECPrivateKey) + { + if (key instanceof BCECPrivateKey) + { + try + { + return new OpenSSHPrivateKeySpec(PrivateKeyInfo.getInstance(key.getEncoded()).parsePrivateKey().toASN1Primitive().getEncoded()); + } + catch (IOException e) + { + throw new IllegalArgumentException("cannot encoded key: " + e.getMessage()); + } + } + else + { + throw new IllegalArgumentException("invalid key type: " + key.getClass().getName()); + } + + } + */ + // END Android-removed: Unsupported algorithms + + return super.engineGetKeySpec(key, spec); } protected PrivateKey engineGeneratePrivate( @@ -133,6 +187,23 @@ public class KeyFactorySpi { return new BCECPrivateKey(algorithm, (java.security.spec.ECPrivateKeySpec)keySpec, configuration); } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (keySpec instanceof OpenSSHPrivateKeySpec) + { + org.bouncycastle.asn1.sec.ECPrivateKey ecKey = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(((OpenSSHPrivateKeySpec)keySpec).getEncoded()); + + try + { + return new BCECPrivateKey(algorithm, new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, ecKey.getParameters()), ecKey), configuration); + } + catch (IOException e) + { + throw new InvalidKeySpecException("bad encoding: " + e.getMessage()); + } + } + */ + // END Android-removed: Unsupported algorithms return super.engineGeneratePrivate(keySpec); } @@ -151,6 +222,26 @@ public class KeyFactorySpi { return new BCECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec, configuration); } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (keySpec instanceof OpenSSHPublicKeySpec) + { + CipherParameters params = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded()); + if (params instanceof ECPublicKeyParameters) + { + ECDomainParameters parameters = ((ECPublicKeyParameters)params).getParameters(); + return engineGeneratePublic( + new ECPublicKeySpec(((ECPublicKeyParameters)params).getQ(), + new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH(), parameters.getSeed()) + )); + } + else + { + throw new IllegalArgumentException("openssh key is not ec public key"); + } + } + */ + // END Android-removed: Unsupported algorithms } catch (Exception e) { @@ -218,6 +309,15 @@ public class KeyFactorySpi super("ECGOST3410", BouncyCastleProvider.CONFIGURATION); } } + + public static class ECGOST3410_2012 + extends KeyFactorySpi + { + public ECGOST3410_2012() + { + super("ECGOST3410-2012", BouncyCastleProvider.CONFIGURATION); + } + } */ // END Android-removed: Unsupported algorithm 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 794ca971..17a2e1d6 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 @@ -14,6 +14,7 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyGenerationParameters; @@ -47,8 +48,7 @@ public abstract class KeyPairGeneratorSpi // 239-bit keys (the Bouncy Castle default) are less widely-supported than 256-bit ones, // so we've changed the default strength to 256 for increased compatibility int strength = 256; - int certainty = 50; - SecureRandom random = new SecureRandom(); + SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); boolean initialised = false; String algorithm; ProviderConfiguration configuration; 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 93f9d162..271f774c 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 @@ -1,44 +1,37 @@ package org.bouncycastle.jcajce.provider.asymmetric.ec; -import java.io.IOException; -import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.PrivateKey; import java.security.PublicKey; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.DSAExt; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.NullDigest; // BEGIN Android-removed: Unsupported algorithms // import org.bouncycastle.crypto.digests.RIPEMD160Digest; // END Android-removed: Unsupported algorithms import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.signers.DSAEncoding; import org.bouncycastle.crypto.signers.ECDSASigner; // BEGIN Android-removed: Unsupported algorithms // import org.bouncycastle.crypto.signers.ECNRSigner; // import org.bouncycastle.crypto.signers.HMacDSAKCalculator; // END Android-removed: Unsupported algorithms +import org.bouncycastle.crypto.signers.PlainDSAEncoding; +import org.bouncycastle.crypto.signers.StandardDSAEncoding; // BEGIN Android-changed: Use Android digests // import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.crypto.digests.AndroidDigestFactory; import org.bouncycastle.jcajce.provider.asymmetric.util.DSABase; -import org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; -import org.bouncycastle.util.Arrays; public class SignatureSpi extends DSABase { - SignatureSpi(Digest digest, DSA signer, DSAEncoder encoder) + SignatureSpi(Digest digest, DSAExt signer, DSAEncoding encoding) { - super(digest, signer, encoder); + super(digest, signer, encoding); } protected void engineInitVerify(PublicKey publicKey) @@ -74,8 +67,8 @@ public class SignatureSpi public ecDSA() { // Android-changed: Use Android digests - // super(DigestFactory.createSHA1(), new ECDSASigner(), new StdDSAEncoder()); - super(AndroidDigestFactory.getSHA1(), new ECDSASigner(), new StdDSAEncoder()); + // super(DigestFactory.createSHA1(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); + super(AndroidDigestFactory.getSHA1(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -86,7 +79,7 @@ public class SignatureSpi { public ecDetDSA() { - super(DigestFactory.createSHA1(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1())), new StdDSAEncoder()); + super(DigestFactory.createSHA1(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1())), StandardDSAEncoding.INSTANCE); } } */ @@ -97,7 +90,7 @@ public class SignatureSpi { public ecDSAnone() { - super(new NullDigest(), new ECDSASigner(), new StdDSAEncoder()); + super(new NullDigest(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -107,8 +100,8 @@ public class SignatureSpi public ecDSA224() { // Android-changed: Use Android digests - // super(DigestFactory.createSHA224(), new ECDSASigner(), new StdDSAEncoder()); - super(AndroidDigestFactory.getSHA224(), new ECDSASigner(), new StdDSAEncoder()); + // super(DigestFactory.createSHA224(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); + super(AndroidDigestFactory.getSHA224(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -119,7 +112,7 @@ public class SignatureSpi { public ecDetDSA224() { - super(DigestFactory.createSHA224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224())), new StdDSAEncoder()); + super(DigestFactory.createSHA224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224())), StandardDSAEncoding.INSTANCE); } } */ @@ -131,8 +124,8 @@ public class SignatureSpi public ecDSA256() { // Android-changed: Use Android digests - // super(DigestFactory.createSHA256(), new ECDSASigner(), new StdDSAEncoder()); - super(AndroidDigestFactory.getSHA256(), new ECDSASigner(), new StdDSAEncoder()); + // super(DigestFactory.createSHA256(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); + super(AndroidDigestFactory.getSHA256(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -143,7 +136,7 @@ public class SignatureSpi { public ecDetDSA256() { - super(DigestFactory.createSHA256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256())), new StdDSAEncoder()); + super(DigestFactory.createSHA256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256())), StandardDSAEncoding.INSTANCE); } } */ @@ -155,8 +148,8 @@ public class SignatureSpi public ecDSA384() { // Android-changed: Use Android digests - // super(DigestFactory.createSHA384(), new ECDSASigner(), new StdDSAEncoder()); - super(AndroidDigestFactory.getSHA384(), new ECDSASigner(), new StdDSAEncoder()); + // super(DigestFactory.createSHA384(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); + super(AndroidDigestFactory.getSHA384(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -167,7 +160,7 @@ public class SignatureSpi { public ecDetDSA384() { - super(DigestFactory.createSHA384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384())), new StdDSAEncoder()); + super(DigestFactory.createSHA384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384())), StandardDSAEncoding.INSTANCE); } } */ @@ -179,8 +172,8 @@ public class SignatureSpi public ecDSA512() { // Android-changed: Use Android digests - // super(DigestFactory.createSHA512(), new ECDSASigner(), new StdDSAEncoder()); - super(AndroidDigestFactory.getSHA512(), new ECDSASigner(), new StdDSAEncoder()); + // super(DigestFactory.createSHA512(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); + super(AndroidDigestFactory.getSHA512(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -191,7 +184,7 @@ public class SignatureSpi { public ecDetDSA512() { - super(DigestFactory.createSHA512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512())), new StdDSAEncoder()); + super(DigestFactory.createSHA512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512())), StandardDSAEncoding.INSTANCE); } } @@ -200,7 +193,7 @@ public class SignatureSpi { public ecDSASha3_224() { - super(DigestFactory.createSHA3_224(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_224(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -209,7 +202,7 @@ public class SignatureSpi { public ecDetDSASha3_224() { - super(DigestFactory.createSHA3_224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224())), new StdDSAEncoder()); + super(DigestFactory.createSHA3_224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224())), StandardDSAEncoding.INSTANCE); } } @@ -218,7 +211,7 @@ public class SignatureSpi { public ecDSASha3_256() { - super(DigestFactory.createSHA3_256(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_256(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -227,7 +220,7 @@ public class SignatureSpi { public ecDetDSASha3_256() { - super(DigestFactory.createSHA3_256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256())), new StdDSAEncoder()); + super(DigestFactory.createSHA3_256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256())), StandardDSAEncoding.INSTANCE); } } @@ -236,7 +229,7 @@ public class SignatureSpi { public ecDSASha3_384() { - super(DigestFactory.createSHA3_384(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_384(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -245,7 +238,7 @@ public class SignatureSpi { public ecDetDSASha3_384() { - super(DigestFactory.createSHA3_384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384())), new StdDSAEncoder()); + super(DigestFactory.createSHA3_384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384())), StandardDSAEncoding.INSTANCE); } } @@ -254,7 +247,7 @@ public class SignatureSpi { public ecDSASha3_512() { - super(DigestFactory.createSHA3_512(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_512(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -263,7 +256,7 @@ public class SignatureSpi { public ecDetDSASha3_512() { - super(DigestFactory.createSHA3_512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512())), new StdDSAEncoder()); + super(DigestFactory.createSHA3_512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512())), StandardDSAEncoding.INSTANCE); } } @@ -272,7 +265,7 @@ public class SignatureSpi { public ecDSARipeMD160() { - super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder()); + super(new RIPEMD160Digest(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -281,7 +274,7 @@ public class SignatureSpi { public ecNR() { - super(DigestFactory.createSHA1(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA1(), new ECNRSigner(), StandardDSAEncoding.INSTANCE); } } @@ -290,7 +283,7 @@ public class SignatureSpi { public ecNR224() { - super(DigestFactory.createSHA224(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA224(), new ECNRSigner(), StandardDSAEncoding.INSTANCE); } } @@ -299,7 +292,7 @@ public class SignatureSpi { public ecNR256() { - super(DigestFactory.createSHA256(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA256(), new ECNRSigner(), StandardDSAEncoding.INSTANCE); } } @@ -308,7 +301,7 @@ public class SignatureSpi { public ecNR384() { - super(DigestFactory.createSHA384(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA384(), new ECNRSigner(), StandardDSAEncoding.INSTANCE); } } @@ -317,7 +310,7 @@ public class SignatureSpi { public ecNR512() { - super(DigestFactory.createSHA512(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA512(), new ECNRSigner(), StandardDSAEncoding.INSTANCE); } } @@ -326,7 +319,7 @@ public class SignatureSpi { public ecCVCDSA() { - super(DigestFactory.createSHA1(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA1(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } @@ -335,7 +328,7 @@ public class SignatureSpi { public ecCVCDSA224() { - super(DigestFactory.createSHA224(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA224(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } @@ -344,7 +337,7 @@ public class SignatureSpi { public ecCVCDSA256() { - super(DigestFactory.createSHA256(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA256(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } @@ -353,7 +346,7 @@ public class SignatureSpi { public ecCVCDSA384() { - super(DigestFactory.createSHA384(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA384(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } @@ -362,7 +355,7 @@ public class SignatureSpi { public ecCVCDSA512() { - super(DigestFactory.createSHA512(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA512(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } @@ -371,115 +364,9 @@ public class SignatureSpi { public ecPlainDSARP160() { - super(new RIPEMD160Digest(), new ECDSASigner(), new PlainDSAEncoder()); + super(new RIPEMD160Digest(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } */ // END Android-removed: Unsupported algorithms - - private static class StdDSAEncoder - implements DSAEncoder - { - public byte[] encode( - BigInteger r, - BigInteger s) - throws IOException - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(new ASN1Integer(r)); - v.add(new ASN1Integer(s)); - - return new DERSequence(v).getEncoded(ASN1Encoding.DER); - } - - public BigInteger[] decode( - byte[] encoding) - throws IOException - { - ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); - if (s.size() != 2) - { - throw new IOException("malformed signature"); - } - if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER))) - { - throw new IOException("malformed signature"); - } - - BigInteger[] sig = new BigInteger[2]; - - sig[0] = ASN1Integer.getInstance(s.getObjectAt(0)).getValue(); - sig[1] = ASN1Integer.getInstance(s.getObjectAt(1)).getValue(); - - return sig; - } - } - - // BEGIN Android-removed: Unsupported algorithms - /* - private static class PlainDSAEncoder - implements DSAEncoder - { - public byte[] encode( - BigInteger r, - BigInteger s) - throws IOException - { - byte[] first = makeUnsigned(r); - byte[] second = makeUnsigned(s); - byte[] res; - - if (first.length > second.length) - { - res = new byte[first.length * 2]; - } - else - { - res = new byte[second.length * 2]; - } - - System.arraycopy(first, 0, res, res.length / 2 - first.length, first.length); - System.arraycopy(second, 0, res, res.length - second.length, second.length); - - return res; - } - - - private byte[] makeUnsigned(BigInteger val) - { - byte[] res = val.toByteArray(); - - if (res[0] == 0) - { - byte[] tmp = new byte[res.length - 1]; - - System.arraycopy(res, 1, tmp, 0, tmp.length); - - return tmp; - } - - return res; - } - - public BigInteger[] decode( - byte[] encoding) - throws IOException - { - BigInteger[] sig = new BigInteger[2]; - - byte[] first = new byte[encoding.length / 2]; - byte[] second = new byte[encoding.length / 2]; - - System.arraycopy(encoding, 0, first, 0, first.length); - System.arraycopy(encoding, first.length, second, 0, second.length); - - sig[0] = new BigInteger(1, first); - sig[1] = new BigInteger(1, second); - - return sig; - } - } - */ - // END Android-removed: Unsupported algorithms -}
\ No newline at end of file +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java index e60c36ae..fc37d6ef 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java @@ -95,7 +95,7 @@ public abstract class AlgorithmParametersSpi { return currentSpec; } - + throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object."); } @@ -203,11 +203,11 @@ public abstract class AlgorithmParametersSpi Class paramSpec) throws InvalidParameterSpecException { - if (paramSpec == PSSParameterSpec.class && currentSpec != null) + if (paramSpec == PSSParameterSpec.class || paramSpec == AlgorithmParameterSpec.class) { return currentSpec; } - + throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object."); } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java index d81d1976..0ac494fb 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java @@ -227,16 +227,15 @@ public class BCRSAPrivateCrtKey StringBuffer buf = new StringBuffer(); String nl = Strings.lineSeparator(); - buf.append("RSA Private CRT Key").append(nl); - buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); - buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl); - buf.append(" private exponent: ").append(this.getPrivateExponent().toString(16)).append(nl); - buf.append(" primeP: ").append(this.getPrimeP().toString(16)).append(nl); - buf.append(" primeQ: ").append(this.getPrimeQ().toString(16)).append(nl); - buf.append(" primeExponentP: ").append(this.getPrimeExponentP().toString(16)).append(nl); - buf.append(" primeExponentQ: ").append(this.getPrimeExponentQ().toString(16)).append(nl); - buf.append(" crtCoefficient: ").append(this.getCrtCoefficient().toString(16)).append(nl); - + buf.append("RSA Private CRT Key [").append( + RSAUtil.generateKeyFingerprint(this.getModulus())).append("]") + .append(",[") + .append(RSAUtil.generateExponentFingerprint(this.getPublicExponent())) + .append("]") + .append(nl); + buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); + buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl); + return buf.toString(); } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java index b82c5f80..f529d9b8 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java @@ -17,6 +17,7 @@ import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; +import org.bouncycastle.util.Strings; public class BCRSAPrivateKey implements RSAPrivateKey, PKCS12BagAttributeCarrier @@ -142,4 +143,16 @@ public class BCRSAPrivateKey { out.defaultWriteObject(); } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + buf.append("RSA Private Key [").append( + RSAUtil.generateKeyFingerprint(this.getModulus())).append("],[]").append(nl); + buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); + + return buf.toString(); + } } diff --git a/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 669cf2ba..dd53dce6 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,10 +1,8 @@ package org.bouncycastle.jcajce.provider.asymmetric.rsa; -import java.io.EOFException; 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; @@ -137,10 +135,14 @@ public class BCRSAPublicKey StringBuffer buf = new StringBuffer(); String nl = Strings.lineSeparator(); - buf.append("RSA Public Key").append(nl); - buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); - buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl); - + buf.append("RSA Public Key [").append(RSAUtil.generateKeyFingerprint(this.getModulus())).append("]") + .append(",[") + .append(RSAUtil.generateExponentFingerprint(this.getPublicExponent())) + .append("]") + .append(nl); + buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); + buf.append("public exponent: ").append(this.getPublicExponent().toString(16)).append(nl); + return buf.toString(); } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java index 5154a201..274f6fac 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java @@ -1,6 +1,5 @@ package org.bouncycastle.jcajce.provider.asymmetric.rsa; -import java.io.ByteArrayOutputStream; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -25,6 +24,7 @@ import javax.crypto.spec.PSource; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.InvalidCipherTextException; // Android-removed: Unsupported algorithm @@ -49,12 +49,12 @@ public class CipherSpi // Was: private final JcaJceHelper helper = new BCJcaJceHelper(); private final JcaJceHelper helper = new DefaultJcaJceHelper(); - private AsymmetricBlockCipher cipher; - private AlgorithmParameterSpec paramSpec; - private AlgorithmParameters engineParams; + private AsymmetricBlockCipher cipher; + private AlgorithmParameterSpec paramSpec; + private AlgorithmParameters engineParams; private boolean publicKeyOnly = false; private boolean privateKeyOnly = false; - private ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + private ErasableOutputStream bOut = new ErasableOutputStream(); public CipherSpi( AsymmetricBlockCipher engine) @@ -350,7 +350,7 @@ public class CipherSpi } else { - param = new ParametersWithRandom(param, new SecureRandom()); + param = new ParametersWithRandom(param, CryptoServicesRegistrar.getSecureRandom()); } } @@ -502,12 +502,11 @@ public class CipherSpi int outputOffset) throws IllegalBlockSizeException, BadPaddingException, ShortBufferException { - // BEGIN Android-added: Throw ShortBufferException when given a short buffer. - if (engineGetOutputSize(inputLen) > output.length - outputOffset) + if (outputOffset + engineGetOutputSize(inputLen) > output.length) { throw new ShortBufferException("output buffer too short for input."); } - // END Android-added: Throw ShortBufferException when given a short buffer. + if (input != null) { bOut.write(input, inputOffset, inputLen); @@ -543,9 +542,7 @@ public class CipherSpi { try { - byte[] bytes = bOut.toByteArray(); - - return cipher.processBlock(bytes, 0, bytes.length); + return cipher.processBlock(bOut.getBuf(), 0, bOut.size()); } catch (InvalidCipherTextException e) { @@ -557,7 +554,7 @@ public class CipherSpi } finally { - bOut.reset(); + bOut.erase(); } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java index 5c2f1df7..8688f7e3 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java @@ -175,15 +175,14 @@ public class DigestSignatureSpi } else if (sig.length == expected.length - 2) // NULL left out { - int sigOffset = sig.length - hash.length - 2; - int expectedOffset = expected.length - hash.length - 2; - expected[1] -= 2; // adjust lengths expected[3] -= 2; + int sigOffset = 4 + expected[3]; + int expectedOffset = sigOffset + 2; int nonEqual = 0; - for (int i = 0; i < hash.length; i++) + for (int i = 0; i < expected.length - expectedOffset; i++) { nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]); } @@ -210,7 +209,7 @@ public class DigestSignatureSpi } /** - * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)"> + * @deprecated replaced with #engineSetParameter(java.security.spec.AlgorithmParameterSpec) */ protected void engineSetParameter( String param, diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java index 80690f7c..89afe5ce 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java @@ -18,8 +18,17 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.pkcs.RSAPrivateKey; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil; +// import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi; import org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec; +// import org.bouncycastle.jce.spec.OpenSSHPublicKeySpec; public class KeyFactorySpi extends BaseKeyFactorySpi @@ -56,6 +65,48 @@ public class KeyFactorySpi k.getPrimeExponentP(), k.getPrimeExponentQ(), k.getCrtCoefficient()); } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (spec.isAssignableFrom(OpenSSHPublicKeySpec.class) && key instanceof RSAPublicKey) + { + try + { + return new OpenSSHPublicKeySpec( + OpenSSHPublicKeyUtil.encodePublicKey( + new RSAKeyParameters( + false, + ((RSAPublicKey)key).getModulus(), + ((RSAPublicKey)key).getPublicExponent()) + ) + ); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else if (spec.isAssignableFrom(OpenSSHPrivateKeySpec.class) && key instanceof RSAPrivateCrtKey) + { + try + { + return new OpenSSHPrivateKeySpec(OpenSSHPrivateKeyUtil.encodePrivateKey(new RSAPrivateCrtKeyParameters( + ((RSAPrivateCrtKey)key).getModulus(), + ((RSAPrivateCrtKey)key).getPublicExponent(), + ((RSAPrivateCrtKey)key).getPrivateExponent(), + ((RSAPrivateCrtKey)key).getPrimeP(), + ((RSAPrivateCrtKey)key).getPrimeQ(), + ((RSAPrivateCrtKey)key).getPrimeExponentP(), + ((RSAPrivateCrtKey)key).getPrimeExponentQ(), + ((RSAPrivateCrtKey)key).getCrtCoefficient() + ))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + */ + // END Android-removed: Unsupported algorithms return super.engineGetKeySpec(key, spec); } @@ -114,8 +165,23 @@ public class KeyFactorySpi { return new BCRSAPrivateKey((RSAPrivateKeySpec)keySpec); } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (keySpec instanceof OpenSSHPrivateKeySpec) + { + CipherParameters parameters = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(((OpenSSHPrivateKeySpec)keySpec).getEncoded()); + + if (parameters instanceof RSAPrivateCrtKeyParameters) + { + return new BCRSAPrivateCrtKey((RSAPrivateCrtKeyParameters)parameters); + } - throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName()); + throw new InvalidKeySpecException("open SSH public key is not RSA private key"); + } + */ + // END Android-removed: Unsupported algorithms + + throw new InvalidKeySpecException("unknown KeySpec type: " + keySpec.getClass().getName()); } protected PublicKey engineGeneratePublic( @@ -126,6 +192,22 @@ public class KeyFactorySpi { return new BCRSAPublicKey((RSAPublicKeySpec)keySpec); } + // BEGIN Android-removed: Unsupported algorithms + /* + else if (keySpec instanceof OpenSSHPublicKeySpec) + { + + CipherParameters parameters = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded()); + if (parameters instanceof RSAKeyParameters) + { + return new BCRSAPublicKey((RSAKeyParameters)parameters); + } + + throw new InvalidKeySpecException("Open SSH public key is not RSA public key"); + + } + */ + // END Android-removed: Unsupported algorithms return super.engineGeneratePublic(keySpec); } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java index a2c96662..3b9d7abc 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java @@ -8,6 +8,7 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.RSAKeyGenParameterSpec; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.generators.RSAKeyPairGenerator; import org.bouncycastle.crypto.params.RSAKeyGenerationParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; @@ -34,7 +35,7 @@ public class KeyPairGeneratorSpi engine = new RSAKeyPairGenerator(); param = new RSAKeyGenerationParameters(defaultPublicExponent, - new SecureRandom(), 2048, PrimeCertaintyCalculator.getDefaultCertainty(2048)); + CryptoServicesRegistrar.getSecureRandom(), 2048, PrimeCertaintyCalculator.getDefaultCertainty(2048)); engine.init(param); } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java index 4943a99b..4d046b8a 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java @@ -1,5 +1,6 @@ package org.bouncycastle.jcajce.provider.asymmetric.rsa; +import java.math.BigInteger; import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; @@ -9,6 +10,7 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.bouncycastle.util.Fingerprint; /** * utility class for converting java.security RSA objects into their @@ -63,4 +65,14 @@ public class RSAUtil return new RSAKeyParameters(true, k.getModulus(), k.getPrivateExponent()); } } + + static String generateKeyFingerprint(BigInteger modulus) + { + return new Fingerprint(modulus.toByteArray()).toString(); + } + + static String generateExponentFingerprint(BigInteger exponent) + { + return new Fingerprint(exponent.toByteArray(), 32).toString(); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java index f285ac55..b449dc59 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java @@ -26,6 +26,7 @@ import org.bouncycastle.crypto.DerivationFunction; // import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator; import org.bouncycastle.crypto.params.DESParameters; import org.bouncycastle.crypto.params.KDFParameters; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Integers; import org.bouncycastle.util.Strings; @@ -81,6 +82,11 @@ public abstract class BaseAgreementSpi keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), i192); keySizes.put(OIWObjectIdentifiers.desCBC.getId(), i64); + // Android-removed: Unsupported algorithms + // keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb.getId(), i256); + // keySizes.put(CryptoProObjectIdentifiers.id_Gost28147_89_None_KeyWrap.getId(), i256); + // keySizes.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_KeyWrap.getId(), i256); + keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA1.getId(), Integers.valueOf(160)); keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA256.getId(), i256); keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA384.getId(), Integers.valueOf(384)); @@ -138,8 +144,8 @@ public abstract class BaseAgreementSpi des.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), "DES"); } - private final String kaAlgorithm; - private final DerivationFunction kdf; + protected final String kaAlgorithm; + protected final DerivationFunction kdf; protected byte[] ukmParameters; @@ -220,8 +226,15 @@ public abstract class BaseAgreementSpi { if (kdf != null) { - throw new UnsupportedOperationException( - "KDF can only be used when algorithm is known"); + byte[] secret = calcSecret(); + try + { + return getSharedSecretBytes(secret, null, secret.length * 8); + } + catch (NoSuchAlgorithmException e) + { + throw new IllegalStateException(e.getMessage()); + } } return calcSecret(); @@ -248,7 +261,6 @@ public abstract class BaseAgreementSpi String algorithm) throws NoSuchAlgorithmException { - byte[] secret = calcSecret(); String algKey = Strings.toUpperCase(algorithm); String oidAlgorithm = algorithm; @@ -259,6 +271,21 @@ public abstract class BaseAgreementSpi int keySize = getKeySize(oidAlgorithm); + byte[] secret = getSharedSecretBytes(calcSecret(), oidAlgorithm, keySize); + + String algName = getAlgorithm(algorithm); + + if (des.containsKey(algName)) + { + DESParameters.setOddParity(secret); + } + + return new SecretKeySpec(secret, algName); + } + + private byte[] getSharedSecretBytes(byte[] secret, String oidAlgorithm, int keySize) + throws NoSuchAlgorithmException + { if (kdf != null) { if (keySize < 0) @@ -271,6 +298,10 @@ public abstract class BaseAgreementSpi /* if (kdf instanceof DHKEKGenerator) { + if (oidAlgorithm == null) + { + throw new NoSuchAlgorithmException("algorithm OID is null"); + } ASN1ObjectIdentifier oid; try { @@ -295,7 +326,9 @@ public abstract class BaseAgreementSpi kdf.generateBytes(keyBytes, 0, keyBytes.length); - secret = keyBytes; + Arrays.clear(secret); + + return keyBytes; } else { @@ -305,18 +338,13 @@ public abstract class BaseAgreementSpi System.arraycopy(secret, 0, keyBytes, 0, keyBytes.length); - secret = keyBytes; - } - } + Arrays.clear(secret); - String algName = getAlgorithm(algorithm); + return keyBytes; + } - if (des.containsKey(algName)) - { - DESParameters.setOddParity(secret); + return secret; } - - return new SecretKeySpec(secret, algName); } protected abstract byte[] calcSecret(); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java index 961e2632..978eef85 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java @@ -1,5 +1,6 @@ package org.bouncycastle.jcajce.provider.asymmetric.util; +import java.io.ByteArrayOutputStream; import java.security.AlgorithmParameters; import java.security.InvalidKeyException; import java.security.Key; @@ -29,6 +30,7 @@ import org.bouncycastle.crypto.Wrapper; import org.bouncycastle.jcajce.util.BCJcaJceHelper; import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; public abstract class BaseCipherSpi extends CipherSpi @@ -230,4 +232,23 @@ public abstract class BaseCipherSpi throw new InvalidKeyException("Unknown key type " + wrappedKeyType); } } + + protected static final class ErasableOutputStream + extends ByteArrayOutputStream + { + public ErasableOutputStream() + { + } + + public byte[] getBuf() + { + return buf; + } + + public void erase() + { + Arrays.fill(this.buf, (byte)0); + reset(); + } + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java index 463de890..28538fdd 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java @@ -7,25 +7,26 @@ import java.security.spec.AlgorithmParameterSpec; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; -import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.DSAExt; import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.signers.DSAEncoding; public abstract class DSABase extends SignatureSpi implements PKCSObjectIdentifiers, X509ObjectIdentifiers { - protected Digest digest; - protected DSA signer; - protected DSAEncoder encoder; + protected Digest digest; + protected DSAExt signer; + protected DSAEncoding encoding; protected DSABase( Digest digest, - DSA signer, - DSAEncoder encoder) + DSAExt signer, + DSAEncoding encoding) { this.digest = digest; this.signer = signer; - this.encoder = encoder; + this.encoding = encoding; } protected void engineUpdate( @@ -47,15 +48,14 @@ public abstract class DSABase protected byte[] engineSign() throws SignatureException { - byte[] hash = new byte[digest.getDigestSize()]; - + byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); try { - BigInteger[] sig = signer.generateSignature(hash); + BigInteger[] sig = signer.generateSignature(hash); - return encoder.encode(sig[0], sig[1]); + return encoding.encode(signer.getOrder(), sig[0], sig[1]); } catch (Exception e) { @@ -67,15 +67,13 @@ public abstract class DSABase byte[] sigBytes) throws SignatureException { - byte[] hash = new byte[digest.getDigestSize()]; - + byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); - BigInteger[] sig; - + BigInteger[] sig; try { - sig = encoder.decode(sigBytes); + sig = encoding.decode(signer.getOrder(), sigBytes); } catch (Exception e) { @@ -92,7 +90,7 @@ public abstract class DSABase } /** - * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)"> + * @deprecated replaced with "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)" */ protected void engineSetParameter( String param, diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java index 4ea0ff93..a4d62415 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java @@ -3,6 +3,9 @@ package org.bouncycastle.jcajce.provider.asymmetric.util; import java.io.IOException; import java.math.BigInteger; +/** + * @deprecated No longer used + */ public interface DSAEncoder { byte[] encode(BigInteger r, BigInteger s) diff --git a/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 d67974b8..91e15b7b 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 @@ -48,12 +48,18 @@ public class EC5Util } // BEGIN Android-removed: Unsupported curves - // X9ECParameters c25519 = CustomNamedCurves.getByName("Curve25519"); - - // customCurves.put(new ECCurve.Fp( - // c25519.getCurve().getField().getCharacteristic(), - // c25519.getCurve().getA().toBigInteger(), - // c25519.getCurve().getB().toBigInteger()), c25519.getCurve()); + /* + X9ECParameters x9_25519 = CustomNamedCurves.getByName("Curve25519"); + ECCurve c_25519 = x9_25519.getCurve(); + + customCurves.put(new ECCurve.Fp( + c_25519.getField().getCharacteristic(), + c_25519.getA().toBigInteger(), + c_25519.getB().toBigInteger(), + c_25519.getOrder(), + c_25519.getCofactor() + ), c_25519); + */ // END Android-removed: Unsupported curves } @@ -146,9 +152,7 @@ public class EC5Util ecSpec = new ECNamedCurveSpec( ECUtil.getCurveName(oid), ellipticCurve, - new ECPoint( - ecP.getG().getAffineXCoord().toBigInteger(), - ecP.getG().getAffineYCoord().toBigInteger()), + convertPoint(ecP.getG()), ecP.getN(), ecP.getH()); } @@ -166,9 +170,7 @@ public class EC5Util { ecSpec = new ECParameterSpec( ellipticCurve, - new ECPoint( - ecP.getG().getAffineXCoord().toBigInteger(), - ecP.getG().getAffineYCoord().toBigInteger()), + convertPoint(ecP.getG()), ecP.getN(), ecP.getH().intValue()); } @@ -176,10 +178,9 @@ public class EC5Util { ecSpec = new ECParameterSpec( ellipticCurve, - new ECPoint( - ecP.getG().getAffineXCoord().toBigInteger(), - ecP.getG().getAffineYCoord().toBigInteger()), - ecP.getN(), 1); // TODO: not strictly correct... need to fix the test data... + convertPoint(ecP.getG()), + ecP.getN(), + 1); // TODO: not strictly correct... need to fix the test data... } } @@ -191,9 +192,17 @@ public class EC5Util { return new ECParameterSpec( convertCurve(domainParameters.getCurve(), null), // JDK 1.5 has trouble with this if it's not null... - new ECPoint( - domainParameters.getG().getAffineXCoord().toBigInteger(), - domainParameters.getG().getAffineYCoord().toBigInteger()), + EC5Util.convertPoint(domainParameters.getG()), + domainParameters.getN(), + domainParameters.getH().intValue()); + } + + public static ECParameterSpec convertToSpec( + ECDomainParameters domainParameters) + { + return new ECParameterSpec( + convertCurve(domainParameters.getCurve(), null), // JDK 1.5 has trouble with this if it's not null... + EC5Util.convertPoint(domainParameters.getG()), domainParameters.getN(), domainParameters.getH().intValue()); } @@ -261,9 +270,7 @@ public class EC5Util return new ECNamedCurveSpec( ((ECNamedCurveParameterSpec)spec).getName(), ellipticCurve, - new ECPoint( - spec.getG().getAffineXCoord().toBigInteger(), - spec.getG().getAffineYCoord().toBigInteger()), + convertPoint(spec.getG()), spec.getN(), spec.getH()); } @@ -271,9 +278,7 @@ public class EC5Util { return new ECParameterSpec( ellipticCurve, - new ECPoint( - spec.getG().getAffineXCoord().toBigInteger(), - spec.getG().getAffineYCoord().toBigInteger()), + convertPoint(spec.getG()), spec.getN(), spec.getH().intValue()); } @@ -285,12 +290,25 @@ public class EC5Util { ECCurve curve = convertCurve(ecSpec.getCurve()); - return new org.bouncycastle.jce.spec.ECParameterSpec( - curve, - convertPoint(curve, ecSpec.getGenerator(), withCompression), - ecSpec.getOrder(), - BigInteger.valueOf(ecSpec.getCofactor()), - ecSpec.getCurve().getSeed()); + if (ecSpec instanceof ECNamedCurveSpec) + { + return new org.bouncycastle.jce.spec.ECNamedCurveParameterSpec( + ((ECNamedCurveSpec)ecSpec).getName(), + curve, + convertPoint(curve, ecSpec.getGenerator(), withCompression), + ecSpec.getOrder(), + BigInteger.valueOf(ecSpec.getCofactor()), + ecSpec.getCurve().getSeed()); + } + else + { + return new org.bouncycastle.jce.spec.ECParameterSpec( + curve, + convertPoint(curve, ecSpec.getGenerator(), withCompression), + ecSpec.getOrder(), + BigInteger.valueOf(ecSpec.getCofactor()), + ecSpec.getCurve().getSeed()); + } } public static org.bouncycastle.math.ec.ECPoint convertPoint( @@ -308,4 +326,13 @@ public class EC5Util { return curve.createPoint(point.getAffineX(), point.getAffineY()); } + + public static ECPoint convertPoint(org.bouncycastle.math.ec.ECPoint point) + { + point = point.normalize(); + + return new ECPoint( + point.getAffineXCoord().toBigInteger(), + point.getAffineYCoord().toBigInteger()); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java index 39ff397c..f0511a6a 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java @@ -8,18 +8,9 @@ import java.util.Enumeration; import java.util.Map; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -// Android-removed: Unsupported algorithms -// import org.bouncycastle.asn1.anssi.ANSSINamedCurves; -// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; -// import org.bouncycastle.asn1.gm.GMNamedCurves; -import org.bouncycastle.asn1.nist.NISTNamedCurves; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.sec.SECNamedCurves; -// Android-removed: Unsupported algorithms -// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.ECNamedCurveTable; -import org.bouncycastle.asn1.x9.X962NamedCurves; import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.ec.CustomNamedCurves; @@ -34,6 +25,11 @@ import org.bouncycastle.jce.interfaces.ECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Fingerprint; +import org.bouncycastle.util.Strings; /** * utility class for converting jce/jca ECDSA, ECDH, and ECDHC @@ -235,9 +231,20 @@ public class ECUtil s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); } - return new ECPrivateKeyParameters( - k.getD(), - new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); + if (k.getParameters() instanceof ECNamedCurveParameterSpec) + { + String name = ((ECNamedCurveParameterSpec)k.getParameters()).getName(); + return new ECPrivateKeyParameters( + k.getD(), + new ECNamedDomainParameters(ECNamedCurveTable.getOID(name), + s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); + } + else + { + return new ECPrivateKeyParameters( + k.getD(), + new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); + } } else if (key instanceof java.security.interfaces.ECPrivateKey) { @@ -297,15 +304,12 @@ public class ECUtil public static ASN1ObjectIdentifier getNamedCurveOid( String curveName) { - String name; + String name = curveName; - if (curveName.indexOf(' ') > 0) - { - name = curveName.substring(curveName.indexOf(' ') + 1); - } - else + int spacePos = name.indexOf(' '); + if (spacePos > 0) { - name = curveName; + name = name.substring(spacePos + 1); } try @@ -314,51 +318,12 @@ public class ECUtil { return new ASN1ObjectIdentifier(name); } - else - { - return lookupOidByName(name); - } } catch (IllegalArgumentException ex) { - return lookupOidByName(name); } - } - private static ASN1ObjectIdentifier lookupOidByName(String name) - { - ASN1ObjectIdentifier oid = X962NamedCurves.getOID(name); - - if (oid == null) - { - oid = SECNamedCurves.getOID(name); - if (oid == null) - { - oid = NISTNamedCurves.getOID(name); - } - // BEGIN Android-removed: Unsupported algorithms - /* - if (oid == null) - { - oid = TeleTrusTNamedCurves.getOID(name); - } - if (oid == null) - { - oid = ECGOST3410NamedCurves.getOID(name); - } - if (oid == null) - { - oid = ANSSINamedCurves.getOID(name); - } - if (oid == null) - { - oid = GMNamedCurves.getOID(name); - } - */ - // END Android-removed: Unsupported algorithms - } - - return oid; + return ECNamedCurveTable.getOID(name); } public static ASN1ObjectIdentifier getNamedCurveOid( @@ -389,27 +354,7 @@ public class ECUtil if (params == null) { - params = X962NamedCurves.getByOID(oid); - if (params == null) - { - params = SECNamedCurves.getByOID(oid); - } - if (params == null) - { - params = NISTNamedCurves.getByOID(oid); - } - // BEGIN Android-removed: Unsupported algorithms - /* - if (params == null) - { - params = TeleTrusTNamedCurves.getByOID(oid); - } - if (params == null) - { - params = GMNamedCurves.getByOID(oid); - } - */ - // END Android-removed: Unsupported algorithms + params = ECNamedCurveTable.getByOID(oid); } return params; @@ -422,27 +367,7 @@ public class ECUtil if (params == null) { - params = X962NamedCurves.getByName(curveName); - if (params == null) - { - params = SECNamedCurves.getByName(curveName); - } - if (params == null) - { - params = NISTNamedCurves.getByName(curveName); - } - // BEGIN Android-removed: Unsupported algorithms - /* - if (params == null) - { - params = TeleTrusTNamedCurves.getByName(curveName); - } - if (params == null) - { - params = GMNamedCurves.getByName(curveName); - } - */ - // END Android-removed: Unsupported algorithms + params = ECNamedCurveTable.getByName(curveName); } return params; @@ -451,29 +376,52 @@ public class ECUtil public static String getCurveName( ASN1ObjectIdentifier oid) { - String name = X962NamedCurves.getName(oid); - - if (name == null) + return ECNamedCurveTable.getName(oid); + } + + public static String privateKeyToString(String algorithm, BigInteger d, org.bouncycastle.jce.spec.ECParameterSpec spec) + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + org.bouncycastle.math.ec.ECPoint q = calculateQ(d, spec); + + buf.append(algorithm); + buf.append(" Private Key [").append(ECUtil.generateKeyFingerprint(q, spec)).append("]").append(nl); + buf.append(" X: ").append(q.getAffineXCoord().toBigInteger().toString(16)).append(nl); + buf.append(" Y: ").append(q.getAffineYCoord().toBigInteger().toString(16)).append(nl); + + return buf.toString(); + } + + private static org.bouncycastle.math.ec.ECPoint calculateQ(BigInteger d, org.bouncycastle.jce.spec.ECParameterSpec spec) + { + return spec.getG().multiply(d).normalize(); + } + + public static String publicKeyToString(String algorithm, org.bouncycastle.math.ec.ECPoint q, org.bouncycastle.jce.spec.ECParameterSpec spec) + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + buf.append(algorithm); + buf.append(" Public Key [").append(ECUtil.generateKeyFingerprint(q, spec)).append("]").append(nl); + buf.append(" X: ").append(q.getAffineXCoord().toBigInteger().toString(16)).append(nl); + buf.append(" Y: ").append(q.getAffineYCoord().toBigInteger().toString(16)).append(nl); + + return buf.toString(); + } + + public static String generateKeyFingerprint(ECPoint publicPoint, org.bouncycastle.jce.spec.ECParameterSpec spec) + { + ECCurve curve = spec.getCurve(); + ECPoint g = spec.getG(); + + if (curve != null) { - name = SECNamedCurves.getName(oid); - if (name == null) - { - name = NISTNamedCurves.getName(oid); - } - // BEGIN Android-removed: Unsupported algorithms - /* - if (name == null) - { - name = TeleTrusTNamedCurves.getName(oid); - } - if (name == null) - { - name = ECGOST3410NamedCurves.getName(oid); - } - */ - // END Android-removed: Unsupported algorithms + return new Fingerprint(Arrays.concatenate(publicPoint.getEncoded(false), curve.getA().getEncoded(), curve.getB().getEncoded(), g.getEncoded(false))).toString(); } - return name; + return new Fingerprint(publicPoint.getEncoded(false)).toString(); } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java index d5608b9e..4b84ddd6 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java @@ -261,7 +261,7 @@ public class CertificateFactory } catch (Exception e) { - throw new ExCertificateException(e); + throw new ExCertificateException("parsing issue: " + e.getMessage(), e); } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java index b72de4cb..98b3a05c 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java @@ -42,8 +42,7 @@ import org.bouncycastle.util.io.pem.PemObject; /** * CertPath implementation for X.509 certificates. - * <br /> - **/ + */ public class PKIXCertPath extends CertPath { 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 dc8930b3..4870cdb0 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 @@ -31,6 +31,7 @@ import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.util.ASN1Dump; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.CRLDistPoint; @@ -269,6 +270,19 @@ class X509CRLObject throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList."); } + if (sigAlgParams != null) + { + try + { + // needs to be called before initVerify(). + X509SignatureUtil.setSignatureParameters(sig, ASN1Primitive.fromByteArray(sigAlgParams)); + } + catch (IOException e) + { + throw new SignatureException("cannot decode signature parameters: " + e.getMessage()); + } + } + sig.initVerify(key); sig.update(this.getTBSCertList()); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java index e293d9f7..e5b05b61 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java @@ -1,5 +1,6 @@ package org.bouncycastle.jcajce.provider.config; +import java.security.spec.DSAParameterSpec; import java.util.Map; import java.util.Set; @@ -13,6 +14,8 @@ public interface ProviderConfiguration DHParameterSpec getDHDefaultParameters(int keySize); + DSAParameterSpec getDSADefaultParameters(int keySize); + Set getAcceptableNamedCurves(); Map getAdditionalECParameters(); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java index 85365b7d..f9ba6df4 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java @@ -8,16 +8,13 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.Key; -import java.security.KeyFactory; import java.security.KeyStoreException; import java.security.KeyStoreSpi; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; -import java.security.Provider; import java.security.PublicKey; import java.security.SecureRandom; -import java.security.Security; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; @@ -38,7 +35,10 @@ import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; import javax.crypto.spec.SecretKeySpec; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.PBEParametersGenerator; import org.bouncycastle.crypto.digests.SHA1Digest; @@ -90,7 +90,7 @@ public class BcKeyStoreSpi protected Hashtable table = new Hashtable(); - protected SecureRandom random = new SecureRandom(); + protected SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); protected int version; @@ -446,9 +446,9 @@ public class BcKeyStoreSpi switch (keyType) { case KEY_PRIVATE: - return helper.createKeyFactory(algorithm).generatePrivate(spec); + return BouncyCastleProvider.getPrivateKey(PrivateKeyInfo.getInstance(enc)); case KEY_PUBLIC: - return helper.createKeyFactory(algorithm).generatePublic(spec); + return BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(enc)); case KEY_SECRET: return helper.createSecretKeyFactory(algorithm).generateSecret(spec); default: @@ -734,7 +734,7 @@ public class BcKeyStoreSpi table.put(alias, new StoreEntry(alias, date, type, b, chain)); break; default: - throw new RuntimeException("Unknown object type in store."); + throw new IOException("Unknown object type in store."); } type = dIn.read(); @@ -786,7 +786,7 @@ public class BcKeyStoreSpi dOut.write(b); break; default: - throw new RuntimeException("Unknown object type in store."); + throw new IOException("Unknown object type in store."); } } @@ -982,7 +982,7 @@ public class BcKeyStoreSpi int iterationCount = dIn.readInt(); - if ((iterationCount < 0) || (iterationCount > 4 * MIN_ITERATIONS)) + if ((iterationCount < 0) || (iterationCount > (MIN_ITERATIONS << 6))) { throw new IOException("Key store corrupted."); } @@ -1051,18 +1051,6 @@ public class BcKeyStoreSpi } } - static Provider getBouncyCastleProvider() - { - if (Security.getProvider("BC") != null) - { - return Security.getProvider("BC"); - } - else - { - return new BouncyCastleProvider(); - } - } - public static class Std extends BcKeyStoreSpi { 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 efeaa9ae..1251ff24 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,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; @@ -18,7 +19,6 @@ import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Principal; import java.security.PrivateKey; -import java.security.Provider; import java.security.PublicKey; import java.security.SecureRandom; import java.security.UnrecoverableKeyException; @@ -68,7 +68,8 @@ import org.bouncycastle.asn1.DERSet; // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; // import org.bouncycastle.asn1.cryptopro.GOST28147Parameters; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; +// import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.AuthenticatedSafe; import org.bouncycastle.asn1.pkcs.CertBag; import org.bouncycastle.asn1.pkcs.ContentInfo; @@ -88,6 +89,7 @@ import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.Digest; // Android-changed: Use Android digests // import org.bouncycastle.crypto.util.DigestFactory; @@ -97,8 +99,7 @@ import org.bouncycastle.jcajce.PKCS12StoreParameter; // Android-removed: Unsupported algorithms // import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; import org.bouncycastle.jcajce.spec.PBKDF2KeySpec; -// Android-changed: Use default provider for JCA algorithms instead of BC -// Was: import org.bouncycastle.jcajce.util.BCJcaJceHelper; +import org.bouncycastle.jcajce.util.BCJcaJceHelper; import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.jce.interfaces.BCKeyStore; @@ -107,6 +108,7 @@ 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.Properties; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; @@ -114,12 +116,14 @@ public class PKCS12KeyStoreSpi extends KeyStoreSpi implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore { + static final String PKCS12_MAX_IT_COUNT_PROPERTY = "org.bouncycastle.pkcs12.max_it_count"; + // Android-changed: Use default provider for JCA algorithms instead of BC // Was: private final JcaJceHelper helper = new BCJcaJceHelper(); private final JcaJceHelper helper = new DefaultJcaJceHelper(); private static final int SALT_SIZE = 20; - private static final int MIN_ITERATIONS = 1024; + private static final int MIN_ITERATIONS = 50 * 1024; private static final DefaultSecretKeyProvider keySizeProvider = new DefaultSecretKeyProvider(); @@ -145,13 +149,17 @@ public class PKCS12KeyStoreSpi static final int KEY_PUBLIC = 1; static final int KEY_SECRET = 2; - protected SecureRandom random = new SecureRandom(); + protected SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); // use of final causes problems with JDK 1.2 compiler private CertificateFactory certFact; private ASN1ObjectIdentifier keyAlgorithm; private ASN1ObjectIdentifier certAlgorithm; + private AlgorithmIdentifier macAlgorithm = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + private int itCount = 2 * MIN_ITERATIONS; + private int saltLength = 20; + private class CertId { byte[] id; @@ -193,7 +201,7 @@ public class PKCS12KeyStoreSpi } public PKCS12KeyStoreSpi( - Provider provider, + JcaJceHelper helper, ASN1ObjectIdentifier keyAlgorithm, ASN1ObjectIdentifier certAlgorithm) { @@ -202,14 +210,7 @@ public class PKCS12KeyStoreSpi try { - if (provider != null) - { - certFact = CertificateFactory.getInstance("X.509", provider); - } - else - { - certFact = CertificateFactory.getInstance("X.509"); - } + certFact = helper.createCertificateFactory("X.509"); } catch (Exception e) { @@ -622,7 +623,7 @@ public class PKCS12KeyStoreSpi PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters()); PBEParameterSpec defParams = new PBEParameterSpec( pbeParams.getIV(), - pbeParams.getIterations().intValue()); + validateIterationCount(pbeParams.getIterations())); Cipher cipher = helper.createCipher(algorithm.getId()); @@ -695,8 +696,6 @@ public class PKCS12KeyStoreSpi if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds)) { PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters()); - PBEKeySpec pbeSpec = new PBEKeySpec(password); - try { PBEParameterSpec defParams = new PBEParameterSpec( @@ -745,17 +744,15 @@ public class PKCS12KeyStoreSpi if (func.isDefaultPrf()) { - key = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme))); + key = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), validateIterationCount(func.getIterationCount()), keySizeProvider.getKeySize(encScheme))); } else { - key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme), func.getPrf())); + key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), validateIterationCount(func.getIterationCount()), 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) { @@ -804,8 +801,17 @@ public class PKCS12KeyStoreSpi bufIn.reset(); ASN1InputStream bIn = new ASN1InputStream(bufIn); - ASN1Sequence obj = (ASN1Sequence)bIn.readObject(); - Pfx bag = Pfx.getInstance(obj); + + Pfx bag; + try + { + bag = Pfx.getInstance(bIn.readObject()); + } + catch (Exception e) + { + throw new IOException(e.getMessage()); + } + ContentInfo info = bag.getAuthSafe(); Vector chain = new Vector(); boolean unmarkedKey = false; @@ -815,15 +821,16 @@ public class PKCS12KeyStoreSpi { MacData mData = bag.getMacData(); DigestInfo dInfo = mData.getMac(); - AlgorithmIdentifier algId = dInfo.getAlgorithmId(); + macAlgorithm = dInfo.getAlgorithmId(); byte[] salt = mData.getSalt(); - int itCount = mData.getIterationCount().intValue(); + itCount = validateIterationCount(mData.getIterationCount()); + saltLength = salt.length; byte[] data = ((ASN1OctetString)info.getContent()).getOctets(); try { - byte[] res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, false, data); + byte[] res = calculatePbeMac(macAlgorithm.getAlgorithm(), salt, itCount, password, false, data); byte[] dig = dInfo.getDigest(); if (!Arrays.constantTimeAreEqual(res, dig)) @@ -834,7 +841,7 @@ public class PKCS12KeyStoreSpi } // Try with incorrect zero length password - res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, true, data); + res = calculatePbeMac(macAlgorithm.getAlgorithm(), salt, itCount, password, true, data); if (!Arrays.constantTimeAreEqual(res, dig)) { @@ -882,7 +889,6 @@ public class PKCS12KeyStoreSpi // // set the attributes on the key // - PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey; String alias = null; ASN1OctetString localId = null; @@ -900,19 +906,23 @@ public class PKCS12KeyStoreSpi { attr = (ASN1Primitive)attrSet.getObjectAt(0); - ASN1Encodable existing = bagAttr.getBagAttribute(aOid); - if (existing != null) + if (privKey instanceof PKCS12BagAttributeCarrier) { - // OK, but the value has to be the same - if (!existing.toASN1Primitive().equals(attr)) + PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey; + ASN1Encodable existing = bagAttr.getBagAttribute(aOid); + if (existing != null) { - throw new IOException( - "attempt to add existing attribute with different value"); + // OK, but the value has to be the same + if (!existing.toASN1Primitive().equals(attr)) + { + throw new IOException( + "attempt to add existing attribute with different value"); + } + } + else + { + bagAttr.setBagAttribute(aOid, attr); } - } - else - { - bagAttr.setBagAttribute(aOid, attr); } } @@ -1222,6 +1232,27 @@ public class PKCS12KeyStoreSpi } } + private int validateIterationCount(BigInteger i) + { + int count = i.intValue(); + + if (count < 0) + { + throw new IllegalStateException("negative iteration count found"); + } + + BigInteger maxValue = Properties.asBigInteger(PKCS12_MAX_IT_COUNT_PROPERTY); + if (maxValue != null) + { + if (maxValue.intValue() < count) + { + throw new IllegalStateException("iteration count " + count + " greater than " + maxValue.intValue()); + } + } + + return count; + } + public void engineStore(LoadStoreParameter param) throws IOException, NoSuchAlgorithmException, CertificateException @@ -1629,8 +1660,7 @@ public class PKCS12KeyStoreSpi // // create the mac // - byte[] mSalt = new byte[20]; - int itCount = MIN_ITERATIONS; + byte[] mSalt = new byte[saltLength]; random.nextBytes(mSalt); @@ -1640,10 +1670,9 @@ public class PKCS12KeyStoreSpi try { - byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data); + byte[] res = calculatePbeMac(macAlgorithm.getAlgorithm(), mSalt, itCount, password, false, data); - AlgorithmIdentifier algId = new AlgorithmIdentifier(id_SHA1, DERNull.INSTANCE); - DigestInfo dInfo = new DigestInfo(algId, res); + DigestInfo dInfo = new DigestInfo(macAlgorithm, res); mData = new MacData(dInfo, mSalt, itCount); } @@ -1720,7 +1749,9 @@ public class PKCS12KeyStoreSpi { public BCPKCS12KeyStore() { - super(new BouncyCastleProvider(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC); + // Android-changed: Use default provider for JCA algorithms instead of BC + // Was: super(new BCJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC); + super(new DefaultJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC); } } @@ -1731,7 +1762,7 @@ public class PKCS12KeyStoreSpi { public BCPKCS12KeyStore3DES() { - super(new BouncyCastleProvider(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC); + super(new BCJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC); } } @@ -1740,7 +1771,7 @@ public class PKCS12KeyStoreSpi { public DefPKCS12KeyStore() { - super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC); + super(new DefaultJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC); } } @@ -1749,7 +1780,7 @@ public class PKCS12KeyStoreSpi { public DefPKCS12KeyStore3DES() { - super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC); + super(new DefaultJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC); } } */ @@ -1822,12 +1853,15 @@ public class PKCS12KeyStoreSpi keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192)); keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256)); + // BEGIN Android-removed: Unsupported algorithms + /* 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)); - // Android-removed: Unsupported algorithms - // keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256)); + keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256)); + */ + // END Android-removed: Unsupported algorithms KEY_SIZES = Collections.unmodifiableMap(keySizes); } 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 e0669d2c..0615fffe 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 @@ -61,8 +61,6 @@ import org.bouncycastle.jcajce.spec.AEADParameterSpec; public final class AES { - private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec"); - private static final Map<String, String> generalAesAttributes = new HashMap<String, String>(); static @@ -1096,18 +1094,4 @@ public final class AES // END Android-removed: Unsupported algorithms } } - - 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/DES.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java index de2e548c..cf7e4188 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java @@ -17,7 +17,10 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.KeyGenerationParameters; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.PasswordConverter; import org.bouncycastle.crypto.engines.DESEngine; // Android-removed: Unsupported algorithms // import org.bouncycastle.crypto.engines.RFC3211WrapEngine; @@ -32,6 +35,8 @@ import org.bouncycastle.crypto.paddings.ISO7816d4Padding; import org.bouncycastle.crypto.params.DESParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.jcajce.PBKDF1Key; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey; import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator; @@ -177,7 +182,7 @@ public final class DES if (random == null) { - random = new SecureRandom(); + random = CryptoServicesRegistrar.getSecureRandom(); } random.nextBytes(iv); @@ -226,7 +231,7 @@ public final class DES { if (uninitialised) { - engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize)); + engine.init(new KeyGenerationParameters(CryptoServicesRegistrar.getSecureRandom(), defaultKeySize)); uninitialised = false; } @@ -329,7 +334,21 @@ public final class DES if (pbeSpec.getSalt() == null) { - return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null); + // BEGIN Android-removed: Unsupported algorithms + /* + if (scheme == PKCS5S1 || scheme == PKCS5S1_UTF8) + { + return new PBKDF1Key(pbeSpec.getPassword(), + scheme == PKCS5S1 ? PasswordConverter.ASCII : PasswordConverter.UTF8); + } + else + { + */ + // END Android-removed: Unsupported algorithms + return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null); + /* + } + */ } if (forCipher) diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java index 9b2e57b4..24785a43 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java @@ -17,6 +17,7 @@ import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.KeyGenerationParameters; import org.bouncycastle.crypto.engines.DESedeEngine; import org.bouncycastle.crypto.engines.DESedeWrapEngine; @@ -176,7 +177,7 @@ public final class DESede { if (uninitialised) { - engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize)); + engine.init(new KeyGenerationParameters(CryptoServicesRegistrar.getSecureRandom(), defaultKeySize)); uninitialised = false; } @@ -278,7 +279,7 @@ public final class DESede if (random == null) { - random = new SecureRandom(); + random = CryptoServicesRegistrar.getSecureRandom(); } random.nextBytes(iv); @@ -463,6 +464,7 @@ public final class DESede provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3KeyFactory"); provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES2KeyFactory"); + provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1ANDDESEDE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES", "PKCS12PBE"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES", "PKCS12PBE"); @@ -471,6 +473,7 @@ public final class DESede provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES3KEY-CBC", "PKCS12PBE"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES2KEY-CBC", "PKCS12PBE"); + provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"); provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.3", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"); provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.4", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC"); provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWithSHAAnd3KeyTripleDES", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GcmSpecUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GcmSpecUtil.java index 5ccc8ff0..a28cf3eb 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GcmSpecUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GcmSpecUtil.java @@ -7,11 +7,12 @@ import java.security.spec.InvalidParameterSpecException; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.cms.GCMParameters; +import org.bouncycastle.jcajce.provider.symmetric.util.ClassUtil; import org.bouncycastle.util.Integers; class GcmSpecUtil { - static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec"); + static final Class gcmSpecClass = ClassUtil.loadClass(GcmSpecUtil.class, "javax.crypto.spec.GCMParameterSpec"); static boolean gcmSpecExists() { @@ -63,16 +64,4 @@ class GcmSpecUtil throw new InvalidParameterSpecException("Cannot process GCMParameterSpec"); } } - - private static Class lookup(String className) - { - try - { - return GcmSpecUtil.class.getClassLoader().loadClass(className); - } - catch (Exception e) - { - return null; - } - } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java index 31c9bda1..8474f869 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java @@ -5,6 +5,8 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidParameterSpecException; import java.security.spec.KeySpec; +import java.util.HashMap; +import java.util.Map; import javax.crypto.SecretKey; import javax.crypto.spec.PBEKeySpec; @@ -15,9 +17,13 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; // Android-removed: Unsupported algorithms // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +// import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PBKDF2Params; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.crypto.CipherParameters; +// Android-removed: Unneeded imports of files we don't include +// import org.bouncycastle.crypto.PasswordConverter; +// import org.bouncycastle.jcajce.PBKDF2Key; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey; import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters; @@ -25,9 +31,28 @@ import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory; import org.bouncycastle.jcajce.provider.symmetric.util.PBE; import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; import org.bouncycastle.jcajce.spec.PBKDF2KeySpec; +import org.bouncycastle.util.Integers; public class PBEPBKDF2 { + private static final Map prfCodes = new HashMap(); + + static + { + // Android-removed: Unsupported algorithm + // prfCodes.put(CryptoProObjectIdentifiers.gostR3411Hmac, Integers.valueOf(PBE.GOST3411)); + prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA1, Integers.valueOf(PBE.SHA1)); + prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA256, Integers.valueOf(PBE.SHA256)); + prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA224, Integers.valueOf(PBE.SHA224)); + prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA384, Integers.valueOf(PBE.SHA384)); + prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA512, Integers.valueOf(PBE.SHA512)); + // Android-remove: Unsupported algorithms + // prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_256, Integers.valueOf(PBE.SHA3_256)); + // prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_224, Integers.valueOf(PBE.SHA3_224)); + // prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_384, Integers.valueOf(PBE.SHA3_384)); + // prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_512, Integers.valueOf(PBE.SHA3_512)); + } + private PBEPBKDF2() { @@ -70,7 +95,7 @@ public class PBEPBKDF2 if (paramSpec == PBEParameterSpec.class) { return new PBEParameterSpec(params.getSalt(), - params.getIterationCount().intValue()); + params.getIterationCount().intValue()); } throw new InvalidParameterSpecException("unknown parameter spec passed to PBKDF2 PBE parameters object."); @@ -85,10 +110,10 @@ public class PBEPBKDF2 throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PBKDF2 PBE parameters algorithm parameters object"); } - PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec; + PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec; this.params = new PBKDF2Params(pbeSpec.getSalt(), - pbeSpec.getIterationCount()); + pbeSpec.getIterationCount()); } protected void engineInit( @@ -182,6 +207,9 @@ public class PBEPBKDF2 if (pbeSpec.getSalt() == null) { + // Android-changed: Throw an exception if the salt is missing + // return new PBKDF2Key(((PBEKeySpec)keySpec).getPassword(), + // scheme == PKCS5S2 ? PasswordConverter.ASCII : PasswordConverter.UTF8); throw new InvalidKeySpecException("missing required salt"); } @@ -231,36 +259,12 @@ public class PBEPBKDF2 private int getDigestCode(ASN1ObjectIdentifier algorithm) throws InvalidKeySpecException { - // BEGIN Android-removed: Unsupported algorithms - /* - if (algorithm.equals(CryptoProObjectIdentifiers.gostR3411Hmac)) - { - return GOST3411; - } - else - */ - // END Android-removed: Unsupported algorithms - if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA1)) - { - return SHA1; - } - else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA256)) - { - return SHA256; - } - else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA224)) + Integer code = (Integer)prfCodes.get(algorithm); + if (code != null) { - return SHA224; + return code.intValue(); } - else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA384)) - { - return SHA384; - } - else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA512)) - { - return SHA512; - } - + throw new InvalidKeySpecException("Invalid KeySpec: unknown PRF algorithm " + algorithm); } } @@ -302,6 +306,7 @@ public class PBEPBKDF2 super("PBKDF2", PKCS5S2_UTF8, SHA384); } } + public static class PBKDF2withSHA512 extends BasePBKDF2 { @@ -311,6 +316,51 @@ public class PBEPBKDF2 } } + public static class PBKDF2withGOST3411 + extends BasePBKDF2 + { + public PBKDF2withGOST3411() + { + super("PBKDF2", PKCS5S2_UTF8, GOST3411); + } + } + + public static class PBKDF2withSHA3_224 + extends BasePBKDF2 + { + public PBKDF2withSHA3_224() + { + super("PBKDF2", PKCS5S2_UTF8, SHA3_224); + } + } + + public static class PBKDF2withSHA3_256 + extends BasePBKDF2 + { + public PBKDF2withSHA3_256() + { + super("PBKDF2", PKCS5S2_UTF8, SHA3_256); + } + } + + public static class PBKDF2withSHA3_384 + extends BasePBKDF2 + { + public PBKDF2withSHA3_384() + { + super("PBKDF2", PKCS5S2_UTF8, SHA3_384); + } + } + + public static class PBKDF2withSHA3_512 + extends BasePBKDF2 + { + public PBKDF2withSHA3_512() + { + super("PBKDF2", PKCS5S2_UTF8, SHA3_512); + } + } + public static class PBKDF2with8BIT extends BasePBKDF2 { @@ -519,6 +569,11 @@ public class PBEPBKDF2 provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA256", PREFIX + "$PBKDF2withSHA256"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA384", PREFIX + "$PBKDF2withSHA384"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA512", PREFIX + "$PBKDF2withSHA512"); + provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-224", PREFIX + "$PBKDF2withSHA3_224"); + provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-256", PREFIX + "$PBKDF2withSHA3_256"); + provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-384", PREFIX + "$PBKDF2withSHA3_384"); + provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-512", PREFIX + "$PBKDF2withSHA3_512"); + provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACGOST3411", PREFIX + "$PBKDF2withGOST3411"); */ // END Android-removed: Bouncy Castle versions of algorithms. // BEGIN Android-added: Android versions of algorithms. diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java index 06693a25..c4248907 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java @@ -15,6 +15,7 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; // Android-removed: Unsupported algorithms // import org.bouncycastle.asn1.pkcs.RC2CBCParameter; // import org.bouncycastle.crypto.CipherKeyGenerator; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.engines.RC2Engine; // Android-removed: Unsupported algorithms // import org.bouncycastle.crypto.engines.RC2WrapEngine; @@ -241,7 +242,7 @@ public final class RC2 if (random == null) { - random = new SecureRandom(); + random = CryptoServicesRegistrar.getSecureRandom(); } random.nextBytes(iv); diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java index a4719729..85113e12 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java @@ -1,5 +1,7 @@ package org.bouncycastle.jcajce.provider.symmetric.util; +import java.security.spec.KeySpec; + import javax.crypto.interfaces.PBEKey; import javax.crypto.spec.PBEKeySpec; @@ -45,6 +47,13 @@ public class BCPBEKey this.param = param; } + public BCPBEKey(String algName, + KeySpec pbeSpec, CipherParameters param) + { + this.algorithm = algName; + this.param = param; + } + public String getAlgorithm() { return algorithm; 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 9e3dafa7..db2f66ce 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 @@ -32,9 +32,12 @@ import org.bouncycastle.asn1.cms.GCMParameters; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.OutputLengthException; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.engines.DSTU7624Engine; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.modes.CCMBlockCipher; @@ -46,6 +49,9 @@ import org.bouncycastle.crypto.modes.CTSBlockCipher; import org.bouncycastle.crypto.modes.GCMBlockCipher; // Android-removed: Unsupported algorithms // import org.bouncycastle.crypto.modes.GOFBBlockCipher; +// import org.bouncycastle.crypto.modes.KCCMBlockCipher; +// import org.bouncycastle.crypto.modes.KCTRBlockCipher; +// import org.bouncycastle.crypto.modes.KGCMBlockCipher; // import org.bouncycastle.crypto.modes.OCBBlockCipher; import org.bouncycastle.crypto.modes.OFBBlockCipher; // Android-removed: Unsupported algorithms @@ -82,7 +88,7 @@ public class BaseBlockCipher extends BaseWrapCipher implements PBE { - private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec"); + private static final Class gcmSpecClass = ClassUtil.loadClass(BaseBlockCipher.class, "javax.crypto.spec.GCMParameterSpec"); // // specs we can handle. @@ -93,10 +99,10 @@ public class BaseBlockCipher // RC2ParameterSpec.class, // RC5ParameterSpec.class, gcmSpecClass, - IvParameterSpec.class, - PBEParameterSpec.class, // Android-removed: Unsupported algorithms // GOST28147ParameterSpec.class + IvParameterSpec.class, + PBEParameterSpec.class }; private BlockCipher baseEngine; @@ -118,20 +124,6 @@ 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) { @@ -189,8 +181,17 @@ public class BaseBlockCipher org.bouncycastle.crypto.BlockCipher engine, int ivLength) { + this(engine, true, ivLength); + } + + protected BaseBlockCipher( + org.bouncycastle.crypto.BlockCipher engine, + boolean fixedIv, + int ivLength) + { baseEngine = engine; + this.fixedIv = fixedIv; this.cipher = new BufferedGenericBlockCipher(engine); this.ivLength = ivLength / 8; } @@ -199,9 +200,18 @@ public class BaseBlockCipher BufferedBlockCipher engine, int ivLength) { + this(engine, true, ivLength); + } + + protected BaseBlockCipher( + BufferedBlockCipher engine, + boolean fixedIv, + int ivLength) + { baseEngine = engine.getUnderlyingCipher(); this.cipher = new BufferedGenericBlockCipher(engine); + this.fixedIv = fixedIv; this.ivLength = ivLength / 8; } @@ -272,11 +282,6 @@ public class BaseBlockCipher try { engineParams = createParametersInstance(name); - // Android-changed: Use IvParameterSpec instead of passing raw bytes. - // The documentation of init() says that a byte array should be decoded - // as ASN.1, and Conscrypt's implementations follow that requirement, - // even though Bouncy Castle's implementations don't. Wrapping it in - // an IvParameterSpec makes the interpretation unambiguous to both. engineParams.init(new IvParameterSpec(ivParam.getIV())); } catch (Exception e) @@ -371,8 +376,21 @@ public class BaseBlockCipher { ivLength = baseEngine.getBlockSize(); fixedIv = false; - cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( - new SICBlockCipher(baseEngine))); + // BEGIN Android-removed: Unsupported algorithms + /* + if (baseEngine instanceof DSTU7624Engine) + { + cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( + new KCTRBlockCipher(baseEngine))); + } + else + { + */ + cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher( + new SICBlockCipher(baseEngine))); + /* + } + */ } // BEGIN Android-removed: Unsupported modes /* @@ -397,8 +415,20 @@ public class BaseBlockCipher } else if (modeName.startsWith("CCM")) { - ivLength = 13; // CCM nonce 7..13 bytes - cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine)); + ivLength = 12; // CCM nonce 7..13 bytes + // BEGIN Android-removed: Unsupported algorithms + /* + if (baseEngine instanceof DSTU7624Engine) + { + cipher = new AEADGenericBlockCipher(new KCCMBlockCipher(baseEngine)); + } + else + { + */ + cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine)); + /* + } + */ } // BEGIN Android-removed: Unsupported modes /* @@ -427,7 +457,19 @@ public class BaseBlockCipher else if (modeName.startsWith("GCM")) { ivLength = baseEngine.getBlockSize(); - cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine)); + // BEGIN Android-removed: Unsupported algorithms + /* + if (baseEngine instanceof DSTU7624Engine) + { + cipher = new AEADGenericBlockCipher(new KGCMBlockCipher(baseEngine)); + } + else + { + */ + cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine)); + /* + } + */ } else { @@ -448,7 +490,7 @@ public class BaseBlockCipher cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher())); } } - else if (paddingName.equals("WITHCTS")) + else if (paddingName.equals("WITHCTS") || paddingName.equals("CTSPADDING") || paddingName.equals("CS3PADDING")) { cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher())); } @@ -868,7 +910,7 @@ public class BaseBlockCipher if (ivRandom == null) { - ivRandom = new SecureRandom(); + ivRandom = CryptoServicesRegistrar.getSecureRandom(); } if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE)) @@ -1345,7 +1387,7 @@ public class BaseBlockCipher private static final Constructor aeadBadTagConstructor; static { - Class aeadBadTagClass = lookup("javax.crypto.AEADBadTagException"); + Class aeadBadTagClass = ClassUtil.loadClass(BaseBlockCipher.class, "javax.crypto.AEADBadTagException"); if (aeadBadTagClass != null) { aeadBadTagConstructor = findExceptionConstructor(aeadBadTagClass); @@ -1450,21 +1492,4 @@ public class BaseBlockCipher } } } - - private static class InvalidKeyOrParametersException - extends InvalidKeyException - { - private final Throwable cause; - - InvalidKeyOrParametersException(String msg, Throwable cause) - { - super(msg); - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } - } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java index 12d2b851..07b330cf 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java @@ -10,6 +10,7 @@ import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.crypto.CipherKeyGenerator; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.KeyGenerationParameters; public class BaseKeyGenerator @@ -58,7 +59,7 @@ public class BaseKeyGenerator { if (random == null) { - random = new SecureRandom(); + random = CryptoServicesRegistrar.getSecureRandom(); } engine.init(new KeyGenerationParameters(random, keySize)); uninitialised = false; @@ -73,7 +74,7 @@ public class BaseKeyGenerator { if (uninitialised) { - engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize)); + engine.init(new KeyGenerationParameters(CryptoServicesRegistrar.getSecureRandom(), defaultKeySize)); uninitialised = false; } 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 45b24bff..29bd6a58 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 @@ -33,7 +33,7 @@ import org.bouncycastle.jcajce.spec.AEADParameterSpec; public class BaseMac extends MacSpi implements PBE { - private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec"); + private static final Class gcmSpecClass = ClassUtil.loadClass(BaseMac.class, "javax.crypto.spec.GCMParameterSpec"); private Mac macEngine; @@ -287,18 +287,4 @@ public class BaseMac return newTable; } - - private static Class lookup(String className) - { - try - { - Class def = BaseBlockCipher.class.getClassLoader().loadClass(className); - - return def; - } - catch (Exception e) - { - return null; - } - } } 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 9795e2da..06e5af0f 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 @@ -20,6 +20,7 @@ import javax.crypto.spec.PBEParameterSpec; // import javax.crypto.spec.RC5ParameterSpec; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.StreamCipher; import org.bouncycastle.crypto.params.KeyParameter; @@ -112,6 +113,38 @@ public class BaseStreamCipher return null; } } + else if (ivParam != null) + { + String name = cipher.getAlgorithmName(); + + if (name.indexOf('/') >= 0) + { + name = name.substring(0, name.indexOf('/')); + } + if (name.startsWith("ChaCha7539")) + { + name = "ChaCha7539"; + } + else if (name.startsWith("Grain")) + { + name = "Grainv1"; + } + else if (name.startsWith("HC")) + { + int endIndex = name.indexOf('-'); + name = name.substring(0, endIndex) + name.substring(endIndex + 1); + } + + try + { + engineParams = createParametersInstance(name); + engineParams.init(new IvParameterSpec(ivParam.getIV())); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } + } } return engineParams; @@ -124,7 +157,7 @@ public class BaseStreamCipher String mode) throws NoSuchAlgorithmException { - if (!mode.equalsIgnoreCase("ECB")) + if (!(mode.equalsIgnoreCase("ECB") || mode.equals("NONE"))) { throw new NoSuchAlgorithmException("can't support mode " + mode); } @@ -233,7 +266,7 @@ public class BaseStreamCipher if (ivRandom == null) { - ivRandom = new SecureRandom(); + ivRandom = CryptoServicesRegistrar.getSecureRandom(); } if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE)) diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java index 58da98e7..4ebb2941 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java @@ -1,8 +1,10 @@ package org.bouncycastle.jcajce.provider.symmetric.util; +import java.io.ByteArrayOutputStream; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; +import java.security.InvalidParameterException; import java.security.Key; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; @@ -34,6 +36,10 @@ import org.bouncycastle.crypto.Wrapper; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.crypto.params.ParametersWithRandom; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.crypto.params.ParametersWithSBox; +// import org.bouncycastle.crypto.params.ParametersWithUKM; +// import org.bouncycastle.jcajce.spec.GOST28147WrapParameterSpec; // Android-changed: Use default provider for JCA algorithms instead of BC // Was: import org.bouncycastle.jcajce.util.BCJcaJceHelper; import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; @@ -50,11 +56,13 @@ public abstract class BaseWrapCipher // private Class[] availableSpecs = { - IvParameterSpec.class, + // Android-removed: Unsupported algorithms + // GOST28147WrapParameterSpec.class, PBEParameterSpec.class, // Android-removed: Unsupported algorithms // RC2ParameterSpec.class, // RC5ParameterSpec.class + IvParameterSpec.class }; protected int pbeType = PKCS12; @@ -69,6 +77,9 @@ public abstract class BaseWrapCipher private int ivSize; private byte[] iv; + private ErasableOutputStream wrapStream = null; + private boolean forWrapping; + // Android-changed: Use default provider for JCA algorithms instead of BC // Was: private final JcaJceHelper helper = new BCJcaJceHelper(); private final JcaJceHelper helper = new DefaultJcaJceHelper(); @@ -115,7 +126,30 @@ public abstract class BaseWrapCipher protected AlgorithmParameters engineGetParameters() { - return null; + if (engineParams == null) + { + if (iv != null) + { + String name = wrapEngine.getAlgorithmName(); + + if (name.indexOf('/') >= 0) + { + name = name.substring(0, name.indexOf('/')); + } + + try + { + engineParams = createParametersInstance(name); + engineParams.init(new IvParameterSpec(iv)); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } + } + } + + return engineParams; } protected final AlgorithmParameters createParametersInstance(String algorithm) @@ -171,15 +205,35 @@ public abstract class BaseWrapCipher if (params instanceof IvParameterSpec) { - IvParameterSpec iv = (IvParameterSpec) params; - param = new ParametersWithIV(param, iv.getIV()); + IvParameterSpec ivSpec = (IvParameterSpec)params; + this.iv = ivSpec.getIV(); + param = new ParametersWithIV(param, iv); } + // BEGIN Android-removed: Unsupported algorithms + /* + if (params instanceof GOST28147WrapParameterSpec) + { + GOST28147WrapParameterSpec spec = (GOST28147WrapParameterSpec) params; + + byte[] sBox = spec.getSBox(); + if (sBox != null) + { + param = new ParametersWithSBox(param, sBox); + } + param = new ParametersWithUKM(param, spec.getUKM()); + } + */ + // END Android-removed: Unsupported algorithms + if (param instanceof KeyParameter && ivSize != 0) { - iv = new byte[ivSize]; - random.nextBytes(iv); - param = new ParametersWithIV(param, iv); + if (opmode == Cipher.WRAP_MODE || opmode == Cipher.ENCRYPT_MODE) + { + iv = new byte[ivSize]; + random.nextBytes(iv); + param = new ParametersWithIV(param, iv); + } } if (random != null) @@ -187,19 +241,37 @@ public abstract class BaseWrapCipher param = new ParametersWithRandom(param, random); } - switch (opmode) + try { - case Cipher.WRAP_MODE: - wrapEngine.init(true, param); - break; - case Cipher.UNWRAP_MODE: - wrapEngine.init(false, param); - break; - case Cipher.ENCRYPT_MODE: - case Cipher.DECRYPT_MODE: - throw new IllegalArgumentException("engine only valid for wrapping"); - default: - System.out.println("eeek!"); + switch (opmode) + { + case Cipher.WRAP_MODE: + wrapEngine.init(true, param); + this.wrapStream = null; + this.forWrapping = true; + break; + case Cipher.UNWRAP_MODE: + wrapEngine.init(false, param); + this.wrapStream = null; + this.forWrapping = false; + break; + case Cipher.ENCRYPT_MODE: + wrapEngine.init(true, param); + this.wrapStream = new ErasableOutputStream(); + this.forWrapping = true; + break; + case Cipher.DECRYPT_MODE: + wrapEngine.init(false, param); + this.wrapStream = new ErasableOutputStream(); + this.forWrapping = false; + break; + default: + throw new InvalidParameterException("Unknown mode parameter passed to init."); + } + } + catch (Exception e) + { + throw new InvalidKeyOrParametersException(e.getMessage(), e); } } @@ -249,7 +321,7 @@ public abstract class BaseWrapCipher } catch (InvalidAlgorithmParameterException e) { - throw new IllegalArgumentException(e.getMessage()); + throw new InvalidKeyOrParametersException(e.getMessage(), e); } } @@ -258,7 +330,14 @@ public abstract class BaseWrapCipher int inputOffset, int inputLen) { - throw new RuntimeException("not supported for wrapping"); + if (wrapStream == null) + { + throw new IllegalStateException("not supported in a wrapping mode"); + } + + wrapStream.write(input, inputOffset, inputLen); + + return null; } protected int engineUpdate( @@ -269,7 +348,14 @@ public abstract class BaseWrapCipher int outputOffset) throws ShortBufferException { - throw new RuntimeException("not supported for wrapping"); + if (wrapStream == null) + { + throw new IllegalStateException("not supported in a wrapping mode"); + } + + wrapStream.write(input, inputOffset, inputLen); + + return 0; } protected byte[] engineDoFinal( @@ -278,7 +364,42 @@ public abstract class BaseWrapCipher int inputLen) throws IllegalBlockSizeException, BadPaddingException { - return null; + if (wrapStream == null) + { + throw new IllegalStateException("not supported in a wrapping mode"); + } + + wrapStream.write(input, inputOffset, inputLen); + + try + { + if (forWrapping) + { + try + { + return wrapEngine.wrap(wrapStream.getBuf(), 0, wrapStream.size()); + } + catch (Exception e) + { + throw new IllegalBlockSizeException(e.getMessage()); + } + } + else + { + try + { + return wrapEngine.unwrap(wrapStream.getBuf(), 0, wrapStream.size()); + } + catch (InvalidCipherTextException e) + { + throw new BadPaddingException(e.getMessage()); + } + } + } + finally + { + wrapStream.erase(); + } } protected int engineDoFinal( @@ -289,7 +410,53 @@ public abstract class BaseWrapCipher int outputOffset) throws IllegalBlockSizeException, BadPaddingException, ShortBufferException { - return 0; + if (wrapStream == null) + { + throw new IllegalStateException("not supported in a wrapping mode"); + } + + wrapStream.write(input, inputOffset, inputLen); + + try + { + byte[] enc; + + if (forWrapping) + { + try + { + enc = wrapEngine.wrap(wrapStream.getBuf(), 0, wrapStream.size()); + } + catch (Exception e) + { + throw new IllegalBlockSizeException(e.getMessage()); + } + } + else + { + try + { + enc = wrapEngine.unwrap(wrapStream.getBuf(), 0, wrapStream.size()); + } + catch (InvalidCipherTextException e) + { + throw new BadPaddingException(e.getMessage()); + } + } + + if (outputOffset + enc.length > output.length) + { + throw new ShortBufferException("output buffer too short for input."); + } + + System.arraycopy(enc, 0, output, outputOffset, enc.length); + + return enc.length; + } + finally + { + wrapStream.erase(); + } } protected byte[] engineWrap( @@ -408,4 +575,39 @@ public abstract class BaseWrapCipher } } + protected static final class ErasableOutputStream + extends ByteArrayOutputStream + { + public ErasableOutputStream() + { + } + + public byte[] getBuf() + { + return buf; + } + + public void erase() + { + Arrays.fill(this.buf, (byte)0); + reset(); + } + } + + protected static class InvalidKeyOrParametersException + extends InvalidKeyException + { + private final Throwable cause; + + InvalidKeyOrParametersException(String msg, Throwable cause) + { + super(msg); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/ClassUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/ClassUtil.java new file mode 100644 index 00000000..37ea08b5 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/ClassUtil.java @@ -0,0 +1,45 @@ +package org.bouncycastle.jcajce.provider.symmetric.util; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +public class ClassUtil +{ + public static Class loadClass(Class sourceClass, final String className) + { + try + { + ClassLoader loader = sourceClass.getClassLoader(); + + if (loader != null) + { + return loader.loadClass(className); + } + else + { + return (Class)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + try + { + return Class.forName(className); + } + catch (Exception e) + { + // ignore - maybe log? + } + + return null; + } + }); + } + } + catch (ClassNotFoundException e) + { + // ignore - maybe log? + } + + return null; + } +} 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 89c21734..fcfd4df6 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 @@ -49,6 +49,10 @@ public interface PBE static final int SHA224 = 7; static final int SHA384 = 8; static final int SHA512 = 9; + static final int SHA3_224 = 10; + static final int SHA3_256 = 11; + static final int SHA3_384 = 12; + static final int SHA3_512 = 13; static final int PKCS5S1 = 0; static final int PKCS5S2 = 1; @@ -142,6 +146,22 @@ public interface PBE // generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA512()); generator = new PKCS5S2ParametersGenerator(AndroidDigestFactory.getSHA512()); break; + // BEGIN Android-removed: Unsupported algorithms + /* + case SHA3_224: + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA3_224()); + break; + case SHA3_256: + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA3_256()); + break; + case SHA3_384: + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA3_384()); + break; + case SHA3_512: + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA3_512()); + break; + */ + // END Android-removed: Unsupported algorithms default: throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption."); } diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java index 448c3527..fc4cf4fb 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java @@ -5,7 +5,18 @@ import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; public abstract class AsymmetricAlgorithmProvider extends AlgorithmProvider -{ +{ + protected void addSignatureAlgorithm( + ConfigurableProvider provider, + String algorithm, + String className, + ASN1ObjectIdentifier oid) + { + provider.addAlgorithm("Signature." + algorithm, className); + provider.addAlgorithm("Alg.Alias.Signature." + oid, algorithm); + provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, algorithm); + } + protected void addSignatureAlgorithm( ConfigurableProvider provider, String digest, diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/spec/DHDomainParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/DHDomainParameterSpec.java new file mode 100644 index 00000000..13b8d451 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/spec/DHDomainParameterSpec.java @@ -0,0 +1,129 @@ +package org.bouncycastle.jcajce.spec; + +import java.math.BigInteger; + +import javax.crypto.spec.DHParameterSpec; + +import org.bouncycastle.crypto.params.DHParameters; +import org.bouncycastle.crypto.params.DHValidationParameters; + +/** + * Extension class for DHParameterSpec that wraps a DHDomainParameters object and provides the q domain parameter. + */ +public class DHDomainParameterSpec + extends DHParameterSpec +{ + private final BigInteger q; + private final BigInteger j; + private final int m; + + private DHValidationParameters validationParameters; + + /** + * Base constructor - use the values in an existing set of domain parameters. + * + * @param domainParameters the Diffie-Hellman domain parameters to wrap. + */ + public DHDomainParameterSpec(DHParameters domainParameters) + { + this(domainParameters.getP(), domainParameters.getQ(), domainParameters.getG(), domainParameters.getJ(), domainParameters.getM(), domainParameters.getL()); + this.validationParameters = domainParameters.getValidationParameters(); + } + + /** + * Minimal constructor for parameters able to be used to verify a public key, or use with MQV. + * + * @param p the prime p defining the Galois field. + * @param g the generator of the multiplicative subgroup of order g. + * @param q specifies the prime factor of p - 1 + */ + public DHDomainParameterSpec(BigInteger p, BigInteger q, BigInteger g) + { + this(p, q, g, null, 0); + } + + /** + * Minimal constructor for parameters able to be used to verify a public key, or use with MQV, and a private value length. + * + * @param p the prime p defining the Galois field. + * @param g the generator of the multiplicative subgroup of order g. + * @param q specifies the prime factor of p - 1 + * @param l the maximum bit length for the private value. + */ + public DHDomainParameterSpec(BigInteger p, BigInteger q, BigInteger g, int l) + { + this(p, q, g, null, l); + } + + /** + * X9.42 parameters with private value length. + * + * @param p the prime p defining the Galois field. + * @param g the generator of the multiplicative subgroup of order g. + * @param q specifies the prime factor of p - 1 + * @param j optionally specifies the value that satisfies the equation p = jq+1 + * @param l the maximum bit length for the private value. + */ + public DHDomainParameterSpec(BigInteger p, BigInteger q, BigInteger g, BigInteger j, int l) + { + this(p, q, g, j, 0, l); + } + + /** + * Base constructor - the full domain parameter set. + * + * @param p the prime p defining the Galois field. + * @param g the generator of the multiplicative subgroup of order g. + * @param q specifies the prime factor of p - 1 + * @param j optionally specifies the value that satisfies the equation p = jq+1 + * @param m the minimum bit length for the private value. + * @param l the maximum bit length for the private value. + */ + public DHDomainParameterSpec(BigInteger p, BigInteger q, BigInteger g, BigInteger j, int m, int l) + { + super(p, g, l); + this.q = q; + this.j = j; + this.m = m; + } + + /** + * Return the Q value for the domain parameter set. + * + * @return the value Q. + */ + public BigInteger getQ() + { + return q; + } + + /** + * Return the J value for the domain parameter set if available. + * + * @return the value J, null otherwise. + */ + public BigInteger getJ() + { + return j; + } + + /** + * Return the minimum bitlength for a private value to be generated from these parameters, 0 if not set. + * + * @return minimum bitlength for private value. + */ + public int getM() + { + return m; + } + + /** + * Return the DHDomainParameters object we represent. + * + * @return the internal DHDomainParameters. + */ + public DHParameters getDomainParameters() + { + return new DHParameters(getP(), getG(), q, m, getL(), j, validationParameters); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java index 25897cf5..892aa00e 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java @@ -13,7 +13,7 @@ public class BCJcaJceHelper { private static volatile Provider bcProvider; - private static Provider getBouncyCastleProvider() + private static synchronized Provider getBouncyCastleProvider() { if (Security.getProvider("BC") != null) { diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java b/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java index 119d8eb5..e20d1f10 100644 --- a/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java @@ -6,6 +6,7 @@ import java.util.Map; import org.bouncycastle.asn1.ASN1ObjectIdentifier; // Android-removed: Unsupported algorithms // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +// import org.bouncycastle.asn1.gm.GMObjectIdentifiers; // import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers; // import org.bouncycastle.asn1.iso.ISOIECObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; @@ -44,6 +45,7 @@ public class MessageDigestUtils digestOidMap.put(NISTObjectIdentifiers.id_sha3_256, "SHA3-256"); digestOidMap.put(NISTObjectIdentifiers.id_sha3_384, "SHA3-384"); digestOidMap.put(NISTObjectIdentifiers.id_sha3_512, "SHA3-512"); + digestOidMap.put(GMObjectIdentifiers.sm3, "SM3"); */ // END Android-removed: Unsupported algorithms } diff --git a/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java b/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java index 22373486..1c63c3b2 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java @@ -66,8 +66,8 @@ import org.bouncycastle.util.Strings; * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} * * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { - * type ATTRIBUTE.&id({IOSet}), - * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type}) + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type}) * } * </pre> * @deprecated use classes in org.bouncycastle.pkcs. diff --git a/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java b/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java index f8a1a6fd..159224f2 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java @@ -31,7 +31,7 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; * * * Handles NetScape certificate request (KEYGEN), these are constructed as: - * <pre><code> + * <pre> * SignedPublicKeyAndChallenge ::= SEQUENCE { * publicKeyAndChallenge PublicKeyAndChallenge, * signatureAlgorithm AlgorithmIdentifier, 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 dfc56d7e..4458fc14 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java @@ -15,8 +15,19 @@ import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; +import org.bouncycastle.jcajce.provider.symmetric.util.ClassUtil; import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +// Android-removed: Unsupported algorithms +// import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; +// import org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceCCA2KeyFactorySpi; +// import org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceKeyFactorySpi; +// import org.bouncycastle.pqc.jcajce.provider.newhope.NHKeyFactorySpi; +// import org.bouncycastle.pqc.jcajce.provider.qtesla.QTESLAKeyFactorySpi; +// import org.bouncycastle.pqc.jcajce.provider.rainbow.RainbowKeyFactorySpi; +// import org.bouncycastle.pqc.jcajce.provider.sphincs.Sphincs256KeyFactorySpi; +// import org.bouncycastle.pqc.jcajce.provider.xmss.XMSSKeyFactorySpi; +// import org.bouncycastle.pqc.jcajce.provider.xmss.XMSSMTKeyFactorySpi; /** * To add the provider at runtime use: @@ -45,7 +56,7 @@ import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; public final class BouncyCastleProvider extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Security Provider v1.57"; + private static String info = "BouncyCastle Security Provider v1.61"; public static final String PROVIDER_NAME = "BC"; @@ -61,7 +72,7 @@ public final class BouncyCastleProvider extends Provider private static final String[] SYMMETRIC_GENERIC = { // Android-changed: Remove unsupported algorithms, add our own version of PBEv2 AlgParams - // "PBEPBKDF2", "TLSKDF" + // "PBEPBKDF1", "PBEPBKDF2", "PBEPKCS12", "TLSKDF", "SCRYPT" "PBEPBKDF2", "PBEPKCS12", "PBES2AlgorithmParameters" }; @@ -77,7 +88,7 @@ public final class BouncyCastleProvider extends Provider // "AES", "ARC4", "ARIA", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede", // "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5", // "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "SM4", "TEA", "Twofish", "Threefish", - // "VMPC", "VMPCKSA3", "XTEA", "XSalsa20", "OpenSSLPBKDF" + // "VMPC", "VMPCKSA3", "XTEA", "XSalsa20", "OpenSSLPBKDF", "DSTU7624", "GOST3412_2015" "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish", }; @@ -98,7 +109,7 @@ public final class BouncyCastleProvider extends Provider private static final String[] ASYMMETRIC_CIPHERS = { // Android-changed: Unsupported algorithms - // "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145", "GM" + // "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145", "GM", "EdEC" "DSA", "DH", "EC", "RSA", }; @@ -110,7 +121,7 @@ public final class BouncyCastleProvider extends Provider { // Android-changed: Unsupported algorithms // "GOST3411", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", - // "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b" + // "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b", "Blake2s", "DSTU7564" "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", }; @@ -140,7 +151,7 @@ public final class BouncyCastleProvider extends Provider */ public BouncyCastleProvider() { - super(PROVIDER_NAME, 1.57, info); + super(PROVIDER_NAME, 1.61, info); AccessController.doPrivileged(new PrivilegedAction() { @@ -172,6 +183,7 @@ public final class BouncyCastleProvider extends Provider /* loadAlgorithms(SECURE_RANDOM_PACKAGE, SECURE_RANDOMS); + loadPQCKeys(); // so we can handle certificates containing them. // // X509Store // @@ -224,24 +236,7 @@ public final class BouncyCastleProvider extends Provider { for (int i = 0; i != names.length; i++) { - Class clazz = null; - try - { - ClassLoader loader = this.getClass().getClassLoader(); - - if (loader != null) - { - clazz = loader.loadClass(packageName + names[i] + "$Mappings"); - } - else - { - clazz = Class.forName(packageName + names[i] + "$Mappings"); - } - } - catch (ClassNotFoundException e) - { - // ignore - } + Class clazz = ClassUtil.loadClass(BouncyCastleProvider.class, packageName + names[i] + "$Mappings"); if (clazz != null) { @@ -258,6 +253,26 @@ public final class BouncyCastleProvider extends Provider } } + // BEGIN Android-removed: Unsupported algorithms + /* + private void loadPQCKeys() + { + addKeyInfoConverter(PQCObjectIdentifiers.sphincs256, new Sphincs256KeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.newHope, new NHKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.xmss, new XMSSKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.xmss_mt, new XMSSMTKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.mcEliece, new McElieceKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.mcElieceCca2, new McElieceCCA2KeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.rainbow, new RainbowKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_I, new QTESLAKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_III_size, new QTESLAKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_III_speed, new QTESLAKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_p_I, new QTESLAKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_p_III, new QTESLAKeyFactorySpi()); + } + */ + // END Android-removed: Unsupported algorithms + public void setParameter(String parameterName, Object parameter) { synchronized (CONFIGURATION) diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java index f89b9fd7..87b69273 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java @@ -1,6 +1,7 @@ package org.bouncycastle.jce.provider; import java.security.Permission; +import java.security.spec.DSAParameterSpec; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -9,10 +10,14 @@ import java.util.Set; import javax.crypto.spec.DHParameterSpec; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.params.DHParameters; +import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import org.bouncycastle.jcajce.provider.config.ProviderConfigurationPermission; +import org.bouncycastle.jcajce.spec.DHDomainParameterSpec; import org.bouncycastle.jce.spec.ECParameterSpec; class BouncyCastleProviderConfiguration @@ -191,6 +196,23 @@ class BouncyCastleProviderConfiguration } } + DHParameters dhParams = CryptoServicesRegistrar.getSizedProperty(CryptoServicesRegistrar.Property.DH_DEFAULT_PARAMS, keySize); + if (dhParams != null) + { + return new DHDomainParameterSpec(dhParams); + } + + return null; + } + + public DSAParameterSpec getDSADefaultParameters(int keySize) + { + DSAParameters dsaParams = CryptoServicesRegistrar.getSizedProperty(CryptoServicesRegistrar.Property.DSA_DEFAULT_PARAMS, keySize); + if (dsaParams != null) + { + return new DSAParameterSpec(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()); + } + return null; } 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 b72a6f44..0f783ec2 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java @@ -237,6 +237,22 @@ class CertPathValidatorUtilities return trust; } + static boolean isIssuerTrustAnchor( + X509Certificate cert, + Set trustAnchors, + String sigProvider) + throws AnnotatedException + { + try + { + return findTrustAnchor(cert, trustAnchors, sigProvider) != null; + } + catch (Exception e) + { + return false; + } + } + static List<PKIXCertStore> getAdditionalStoresFromAltNames( byte[] issuerAlternativeName, Map<GeneralName, PKIXCertStore> altNameCertStoreMap) diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java index a30b2df7..d4fa2852 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java @@ -59,9 +59,9 @@ public class JCEDHPrivateKey PrivateKeyInfo info) throws IOException { - ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters()); + ASN1Sequence seq = ASN1Sequence.getInstance(info.getPrivateKeyAlgorithm().getParameters()); ASN1Integer derX = ASN1Integer.getInstance(info.parsePrivateKey()); - ASN1ObjectIdentifier id = info.getAlgorithmId().getAlgorithm(); + ASN1ObjectIdentifier id = info.getPrivateKeyAlgorithm().getAlgorithm(); this.info = info; this.x = derX.getValue(); diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java index 7d6a50cf..1e99c86f 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java @@ -114,22 +114,19 @@ public class JCEECPrivateKey JCEECPublicKey pubKey, ECParameterSpec spec) { - ECDomainParameters dp = params.getParameters(); - this.algorithm = algorithm; this.d = params.getD(); if (spec == null) { + ECDomainParameters dp = params.getParameters(); EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); this.ecSpec = new ECParameterSpec( - ellipticCurve, - new ECPoint( - dp.getG().getAffineXCoord().toBigInteger(), - dp.getG().getAffineYCoord().toBigInteger()), - dp.getN(), - dp.getH().intValue()); + ellipticCurve, + EC5Util.convertPoint(dp.getG()), + dp.getN(), + dp.getH().intValue()); } else { @@ -145,34 +142,29 @@ public class JCEECPrivateKey JCEECPublicKey pubKey, org.bouncycastle.jce.spec.ECParameterSpec spec) { - ECDomainParameters dp = params.getParameters(); - this.algorithm = algorithm; this.d = params.getD(); if (spec == null) { + ECDomainParameters dp = params.getParameters(); EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); this.ecSpec = new ECParameterSpec( - ellipticCurve, - new ECPoint( - dp.getG().getAffineXCoord().toBigInteger(), - dp.getG().getAffineYCoord().toBigInteger()), - dp.getN(), - dp.getH().intValue()); + ellipticCurve, + EC5Util.convertPoint(dp.getG()), + dp.getN(), + dp.getH().intValue()); } else { EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed()); this.ecSpec = new ECParameterSpec( - ellipticCurve, - new ECPoint( - spec.getG().getAffineXCoord().toBigInteger(), - spec.getG().getAffineYCoord().toBigInteger()), - spec.getN(), - spec.getH().intValue()); + ellipticCurve, + EC5Util.convertPoint(spec.getG()), + spec.getN(), + spec.getH().intValue()); } publicKey = getPublicKeyDetails(pubKey); @@ -212,13 +204,11 @@ public class JCEECPrivateKey EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed()); ecSpec = new ECNamedCurveSpec( - ECGOST3410NamedCurves.getName(oid), - ellipticCurve, - new ECPoint( - gParam.getG().getAffineXCoord().toBigInteger(), - gParam.getG().getAffineYCoord().toBigInteger()), - gParam.getN(), - gParam.getH()); + ECGOST3410NamedCurves.getName(oid), + ellipticCurve, + EC5Util.convertPoint(gParam.getG()), + gParam.getN(), + gParam.getH()); } else */ @@ -227,13 +217,11 @@ public class JCEECPrivateKey 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()); + ECUtil.getCurveName(oid), + ellipticCurve, + EC5Util.convertPoint(ecP.getG()), + ecP.getN(), + ecP.getH()); } } else if (params.isImplicitlyCA()) @@ -247,9 +235,7 @@ public class JCEECPrivateKey this.ecSpec = new ECParameterSpec( ellipticCurve, - new ECPoint( - ecP.getG().getAffineXCoord().toBigInteger(), - ecP.getG().getAffineYCoord().toBigInteger()), + EC5Util.convertPoint(ecP.getG()), 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 654b5e1d..916f6fd8 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java @@ -163,14 +163,12 @@ public class JCEECPublicKey private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp) { return new ECParameterSpec( - ellipticCurve, - new ECPoint( - dp.getG().getAffineXCoord().toBigInteger(), - dp.getG().getAffineYCoord().toBigInteger()), - dp.getN(), - dp.getH().intValue()); + ellipticCurve, + EC5Util.convertPoint(dp.getG()), + dp.getN(), + dp.getH().intValue()); } - + public JCEECPublicKey( ECPublicKey key) { @@ -204,18 +202,14 @@ public class JCEECPublicKey throw new IllegalArgumentException("error recovering public key"); } - byte[] keyEnc = key.getOctets(); - byte[] x = new byte[32]; - byte[] y = new byte[32]; - - for (int i = 0; i != x.length; i++) - { - x[i] = keyEnc[32 - 1 - i]; - } + byte[] keyEnc = key.getOctets(); - for (int i = 0; i != y.length; i++) + byte[] x9Encoding = new byte[65]; + x9Encoding[0] = 0x04; + for (int i = 1; i <= 32; ++i) { - y[i] = keyEnc[64 - 1 - i]; + x9Encoding[i ] = keyEnc[32 - i]; + x9Encoding[i + 32] = keyEnc[64 - i]; } gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters()); @@ -225,16 +219,14 @@ public class JCEECPublicKey ECCurve curve = spec.getCurve(); EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed()); - this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false); + this.q = curve.decodePoint(x9Encoding); ecSpec = new ECNamedCurveSpec( - ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()), - ellipticCurve, - new ECPoint( - spec.getG().getAffineXCoord().toBigInteger(), - spec.getG().getAffineYCoord().toBigInteger()), - spec.getN(), spec.getH()); - + ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()), + ellipticCurve, + EC5Util.convertPoint(spec.getG()), + spec.getN(), + spec.getH()); } else */ @@ -253,13 +245,11 @@ public class JCEECPublicKey ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed()); ecSpec = new ECNamedCurveSpec( - ECUtil.getCurveName(oid), - ellipticCurve, - new ECPoint( - ecP.getG().getAffineXCoord().toBigInteger(), - ecP.getG().getAffineYCoord().toBigInteger()), - ecP.getN(), - ecP.getH()); + ECUtil.getCurveName(oid), + ellipticCurve, + EC5Util.convertPoint(ecP.getG()), + ecP.getN(), + ecP.getH()); } else if (params.isImplicitlyCA()) { @@ -268,18 +258,16 @@ public class JCEECPublicKey } else { - X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); + X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); curve = ecP.getCurve(); ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed()); this.ecSpec = new ECParameterSpec( - ellipticCurve, - new ECPoint( - ecP.getG().getAffineXCoord().toBigInteger(), - ecP.getG().getAffineYCoord().toBigInteger()), - ecP.getN(), - ecP.getH().intValue()); + ellipticCurve, + EC5Util.convertPoint(ecP.getG()), + ecP.getN(), + ecP.getH().intValue()); } DERBitString bits = info.getPublicKeyData(); @@ -448,7 +436,7 @@ public class JCEECPublicKey public ECPoint getW() { - return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger()); + return EC5Util.convertPoint(q); } public org.bouncycastle.math.ec.ECPoint getQ() diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java index dfe9cef5..b9086219 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java @@ -54,7 +54,6 @@ public class PKIXCertPathBuilderSpi { ExtendedPKIXBuilderParameters extPKIX = (ExtendedPKIXBuilderParameters)params; - ; for (Iterator it = extPKIX.getAdditionalStores().iterator(); it.hasNext();) { paramsPKIXBldr.addCertificateStore((PKIXCertStore)it.next()); @@ -187,8 +186,8 @@ public class PKIXCertPathBuilderSpi try { // check whether the issuer of <tbvCert> is a TrustAnchor - if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getBaseParameters().getTrustAnchors(), - pkixParams.getBaseParameters().getSigProvider()) != null) + if (CertPathValidatorUtilities.isIssuerTrustAnchor(tbvCert, pkixParams.getBaseParameters().getTrustAnchors(), + pkixParams.getBaseParameters().getSigProvider())) { // exception message from possibly later tried certification // chains diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java index bd2331ab..16659525 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java @@ -1,8 +1,6 @@ package org.bouncycastle.jce.provider; -// BEGIN Android-added: Blacklist support import java.math.BigInteger; -// END Android-added: Blacklist support import java.security.InvalidAlgorithmParameterException; import java.security.PublicKey; import java.security.cert.CertPath; @@ -10,6 +8,7 @@ import java.security.cert.CertPathParameters; import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorResult; import java.security.cert.CertPathValidatorSpi; +import java.security.cert.CertificateEncodingException; import java.security.cert.PKIXCertPathChecker; import java.security.cert.PKIXCertPathValidatorResult; import java.security.cert.PKIXParameters; @@ -26,6 +25,7 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.TBSCertificate; import org.bouncycastle.jcajce.PKIXExtendedBuilderParameters; import org.bouncycastle.jcajce.PKIXExtendedParameters; import org.bouncycastle.jcajce.util.BCJcaJceHelper; @@ -140,15 +140,17 @@ public class PKIXCertPathValidatorSpi { trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1), paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider()); + + if (trust == null) + { + throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1); + } + + checkCertificate(trust.getTrustedCert()); } catch (AnnotatedException e) { - throw new CertPathValidatorException(e.getMessage(), e, certPath, certs.size() - 1); - } - - if (trust == null) - { - throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1); + throw new CertPathValidatorException(e.getMessage(), e.getUnderlyingException(), certPath, certs.size() - 1); } // RFC 5280 - CRLs must originate from the same trust anchor as the target certificate. @@ -325,6 +327,15 @@ public class PKIXCertPathValidatorSpi cert = (X509Certificate) certs.get(index); boolean verificationAlreadyPerformed = (index == certs.size() - 1); + try + { + checkCertificate(cert); + } + catch (AnnotatedException e) + { + throw new CertPathValidatorException(e.getMessage(), e.getUnderlyingException(), certPath, index); + } + // // 6.1.3 // @@ -344,11 +355,15 @@ public class PKIXCertPathValidatorSpi // // 6.1.4 // - if (i != n) { if (cert != null && cert.getVersion() == 1) { + // we've found the trust anchor at the top of the path, ignore and keep going + if ((i == 1) && cert.equals(trust.getTrustedCert())) + { + continue; + } throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null, certPath, index); } @@ -487,4 +502,20 @@ public class PKIXCertPathValidatorSpi throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index); } + static void checkCertificate(X509Certificate cert) + throws AnnotatedException + { + try + { + TBSCertificate.getInstance(cert.getTBSCertificate()); + } + catch (CertificateEncodingException e) + { + throw new AnnotatedException("unable to process TBSCertificate", e); + } + catch (IllegalArgumentException e) + { + throw new AnnotatedException(e.getMessage()); + } + } } diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java index d67a77ee..1ed22d59 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java @@ -59,7 +59,6 @@ import org.bouncycastle.jcajce.PKIXCertStoreSelector; import org.bouncycastle.jcajce.PKIXExtendedBuilderParameters; import org.bouncycastle.jcajce.PKIXExtendedParameters; import org.bouncycastle.jcajce.util.JcaJceHelper; -import org.bouncycastle.jce.PrincipalUtil; import org.bouncycastle.jce.exception.ExtCertPathValidatorException; import org.bouncycastle.util.Arrays; @@ -2421,8 +2420,11 @@ class RFC3280CertPathUtilities } catch (CertPathValidatorException e) { - throw new ExtCertPathValidatorException("Additional certificate path checker failed.", e, certPath, - index); + throw new ExtCertPathValidatorException(e.getMessage(), e, certPath, index); + } + catch (Exception e) + { + throw new CertPathValidatorException("Additional certificate path checker failed.", e, certPath, index); } } 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 36aa595e..0be2ca90 100644 --- a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java +++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java @@ -7,6 +7,7 @@ import java.security.spec.ECFieldFp; import java.security.spec.ECPoint; import java.security.spec.EllipticCurve; +import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import org.bouncycastle.math.ec.ECAlgorithms; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.field.FiniteField; @@ -46,21 +47,14 @@ public class ECNamedCurveSpec return new ECFieldF2m(poly.getDegree(), ks); } } - - private static ECPoint convertPoint( - org.bouncycastle.math.ec.ECPoint g) - { - g = g.normalize(); - return new ECPoint(g.getAffineXCoord().toBigInteger(), g.getAffineYCoord().toBigInteger()); - } - + public ECNamedCurveSpec( String name, ECCurve curve, org.bouncycastle.math.ec.ECPoint g, BigInteger n) { - super(convertCurve(curve, null), convertPoint(g), n, 1); + super(convertCurve(curve, null), EC5Util.convertPoint(g), n, 1); this.name = name; } @@ -83,7 +77,7 @@ public class ECNamedCurveSpec BigInteger n, BigInteger h) { - super(convertCurve(curve, null), convertPoint(g), n, h.intValue()); + super(convertCurve(curve, null), EC5Util.convertPoint(g), n, h.intValue()); this.name = name; } @@ -108,8 +102,8 @@ public class ECNamedCurveSpec BigInteger h, byte[] seed) { - super(convertCurve(curve, seed), convertPoint(g), n, h.intValue()); - + super(convertCurve(curve, seed), EC5Util.convertPoint(g), n, h.intValue()); + this.name = name; } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java index d1f35c56..e0a55435 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java @@ -19,8 +19,13 @@ public abstract class AbstractECMultiplier implements ECMultiplier * Although the various multipliers ought not to produce invalid output under normal * circumstances, a final check here is advised to guard against fault attacks. */ - return ECAlgorithms.validatePoint(result); + return checkResult(result); } protected abstract ECPoint multiplyPositive(ECPoint p, BigInteger k); + + protected ECPoint checkResult(ECPoint p) + { + return ECAlgorithms.implCheckResult(p); + } } 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 f8bf1eb5..f0b1585d 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java @@ -61,10 +61,10 @@ public class ECAlgorithms ECEndomorphism endomorphism = c.getEndomorphism(); if (endomorphism instanceof GLVEndomorphism) { - return validatePoint(implSumOfMultipliesGLV(imported, ks, (GLVEndomorphism)endomorphism)); + return implCheckResult(implSumOfMultipliesGLV(imported, ks, (GLVEndomorphism)endomorphism)); } - return validatePoint(implSumOfMultiplies(imported, ks)); + return implCheckResult(implSumOfMultiplies(imported, ks)); } public static ECPoint sumOfTwoMultiplies(ECPoint P, BigInteger a, @@ -79,18 +79,18 @@ public class ECAlgorithms ECCurve.AbstractF2m f2mCurve = (ECCurve.AbstractF2m)cp; if (f2mCurve.isKoblitz()) { - return validatePoint(P.multiply(a).add(Q.multiply(b))); + return implCheckResult(P.multiply(a).add(Q.multiply(b))); } } ECEndomorphism endomorphism = cp.getEndomorphism(); if (endomorphism instanceof GLVEndomorphism) { - return validatePoint( + return implCheckResult( implSumOfMultipliesGLV(new ECPoint[]{ P, Q }, new BigInteger[]{ a, b }, (GLVEndomorphism)endomorphism)); } - return validatePoint(implShamirsTrickWNaf(P, a, Q, b)); + return implCheckResult(implShamirsTrickWNaf(P, a, Q, b)); } /* @@ -118,7 +118,7 @@ public class ECAlgorithms ECCurve cp = P.getCurve(); Q = importPoint(cp, Q); - return validatePoint(implShamirsTrickJsf(P, k, Q, l)); + return implCheckResult(implShamirsTrickJsf(P, k, Q, l)); } public static ECPoint importPoint(ECCurve c, ECPoint p) @@ -211,7 +211,28 @@ public class ECAlgorithms { if (!p.isValid()) { - throw new IllegalArgumentException("Invalid point"); + throw new IllegalStateException("Invalid point"); + } + + return p; + } + + public static ECPoint cleanPoint(ECCurve c, ECPoint p) + { + ECCurve cp = p.getCurve(); + if (!c.equals(cp)) + { + throw new IllegalArgumentException("Point must be on the same curve"); + } + + return c.decodePoint(p.getEncoded(false)); + } + + static ECPoint implCheckResult(ECPoint p) + { + if (!p.isValidPartial()) + { + throw new IllegalStateException("Invalid result"); } return p; 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 7f3197bc..7c10c78b 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java @@ -8,6 +8,7 @@ import org.bouncycastle.math.ec.endo.ECEndomorphism; import org.bouncycastle.math.ec.endo.GLVEndomorphism; import org.bouncycastle.math.field.FiniteField; import org.bouncycastle.math.field.FiniteFields; +import org.bouncycastle.math.raw.Nat; import org.bouncycastle.util.BigIntegers; import org.bouncycastle.util.Integers; @@ -173,15 +174,26 @@ public abstract class ECCurve public PreCompInfo getPreCompInfo(ECPoint point, String name) { checkPoint(point); + + Hashtable table; synchronized (point) { - Hashtable table = point.preCompTable; - return table == null ? null : (PreCompInfo)table.get(name); + table = point.preCompTable; + } + + if (null == table) + { + return null; + } + + synchronized (table) + { + return (PreCompInfo)table.get(name); } } /** - * Adds <code>PreCompInfo</code> for a point on this curve, under a given name. Used by + * Compute a <code>PreCompInfo</code> for a point on this curve, under a given name. Used by * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use * by subsequent multiplication. * @@ -189,20 +201,34 @@ public abstract class ECCurve * The <code>ECPoint</code> to store precomputations for. * @param name * A <code>String</code> used to index precomputations of different types. - * @param preCompInfo - * The values precomputed by the <code>ECMultiplier</code>. + * @param callback + * Called to calculate the <code>PreCompInfo</code>. */ - public void setPreCompInfo(ECPoint point, String name, PreCompInfo preCompInfo) + public PreCompInfo precompute(ECPoint point, String name, PreCompCallback callback) { checkPoint(point); + + Hashtable table; synchronized (point) { - Hashtable table = point.preCompTable; + table = point.preCompTable; if (null == table) { point.preCompTable = table = new Hashtable(4); } - table.put(name, preCompInfo); + } + + synchronized (table) + { + PreCompInfo existing = (PreCompInfo)table.get(name); + PreCompInfo result = callback.precompute(existing); + + if (result != existing) + { + table.put(name, result); + } + + return result; } } @@ -220,7 +246,7 @@ public abstract class ECCurve // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates. p = p.normalize(); - return validatePoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression); + return createPoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression); } /** @@ -390,7 +416,7 @@ public abstract class ECCurve BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength); p = decompressPoint(yTilde, X); - if (!p.satisfiesCofactor()) + if (!p.implIsValid(true, true)) { throw new IllegalArgumentException("Invalid point"); } @@ -441,6 +467,61 @@ public abstract class ECCurve return p; } + /** + * Create a cache-safe lookup table for the specified sequence of points. All the points MUST + * belong to this {@link ECCurve} instance, and MUST already be normalized. + */ + public ECLookupTable createCacheSafeLookupTable(final ECPoint[] points, int off, final int len) + { + final int FE_BYTES = (getFieldSize() + 7) >>> 3; + + final byte[] table = new byte[len * FE_BYTES * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + byte[] px = p.getRawXCoord().toBigInteger().toByteArray(); + byte[] py = p.getRawYCoord().toBigInteger().toByteArray(); + + int pxStart = px.length > FE_BYTES ? 1 : 0, pxLen = px.length - pxStart; + int pyStart = py.length > FE_BYTES ? 1 : 0, pyLen = py.length - pyStart; + + System.arraycopy(px, pxStart, table, pos + FE_BYTES - pxLen, pxLen); pos += FE_BYTES; + System.arraycopy(py, pyStart, table, pos + FE_BYTES - pyLen, pyLen); pos += FE_BYTES; + } + } + + return new ECLookupTable() + { + public int getSize() + { + return len; + } + + public ECPoint lookup(int index) + { + byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES]; + int pos = 0; + + for (int i = 0; i < len; ++i) + { + int MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_BYTES; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_BYTES + j] & MASK; + } + + pos += (FE_BYTES * 2); + } + + return createRawPoint(fromBigInteger(new BigInteger(1, x)), fromBigInteger(new BigInteger(1, y)), false); + } + }; + } + protected void checkPoint(ECPoint point) { if (null == point || (this != point.getCurve())) @@ -542,6 +623,9 @@ public abstract class ECCurve BigInteger q, r; ECPoint.Fp infinity; + /** + * @deprecated use constructor taking order/cofactor + */ public Fp(BigInteger q, BigInteger a, BigInteger b) { this(q, a, b, null, null); @@ -553,7 +637,7 @@ public abstract class ECCurve this.q = q; this.r = ECFieldElement.Fp.calculateResidue(q); - this.infinity = new ECPoint.Fp(this, null, null); + this.infinity = new ECPoint.Fp(this, null, null, false); this.a = fromBigInteger(a); this.b = fromBigInteger(b); @@ -562,6 +646,9 @@ public abstract class ECCurve this.coord = FP_DEFAULT_COORDS; } + /** + * @deprecated use constructor taking order/cofactor + */ protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b) { this(q, r, a, b, null, null); @@ -573,7 +660,7 @@ public abstract class ECCurve this.q = q; this.r = r; - this.infinity = new ECPoint.Fp(this, null, null); + this.infinity = new ECPoint.Fp(this, null, null, false); this.a = a; this.b = b; @@ -814,7 +901,7 @@ public abstract class ECCurve * @return the solution for <code>z<sup>2</sup> + z = beta</code> or * <code>null</code> if no solution exists. */ - private ECFieldElement solveQuadraticEquation(ECFieldElement beta) + protected ECFieldElement solveQuadraticEquation(ECFieldElement beta) { if (beta.isZero()) { @@ -928,6 +1015,7 @@ public abstract class ECCurve * @param b The coefficient <code>b</code> in the Weierstrass equation * for non-supersingular elliptic curves over * <code>F<sub>2<sup>m</sup></sub></code>. + * @deprecated use constructor taking order/cofactor */ public F2m( int m, @@ -985,6 +1073,7 @@ public abstract class ECCurve * @param b The coefficient <code>b</code> in the Weierstrass equation * for non-supersingular elliptic curves over * <code>F<sub>2<sup>m</sup></sub></code>. + * @deprecated use constructor taking order/cofactor */ public F2m( int m, @@ -1039,7 +1128,7 @@ public abstract class ECCurve this.order = order; this.cofactor = cofactor; - this.infinity = new ECPoint.F2m(this, null, null); + this.infinity = new ECPoint.F2m(this, null, null, false); this.a = fromBigInteger(a); this.b = fromBigInteger(b); this.coord = F2M_DEFAULT_COORDS; @@ -1056,7 +1145,7 @@ public abstract class ECCurve this.order = order; this.cofactor = cofactor; - this.infinity = new ECPoint.F2m(this, null, null); + this.infinity = new ECPoint.F2m(this, null, null, false); this.a = a; this.b = b; this.coord = F2M_DEFAULT_COORDS; @@ -1145,20 +1234,50 @@ public abstract class ECCurve return k3; } - /** - * @deprecated use {@link #getOrder()} instead - */ - public BigInteger getN() + public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len) { - return this.order; - } + final int FE_LONGS = (m + 63) >>> 6; + final int[] ks = isTrinomial() ? new int[]{ k1 } : new int[]{ k1, k2, k3 }; - /** - * @deprecated use {@link #getCofactor()} instead - */ - public BigInteger getH() - { - return this.cofactor; + final long[] table = new long[len * FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + ((ECFieldElement.F2m)p.getRawXCoord()).x.copyTo(table, pos); pos += FE_LONGS; + ((ECFieldElement.F2m)p.getRawYCoord()).x.copyTo(table, pos); pos += FE_LONGS; + } + } + + return new ECLookupTable() + { + public int getSize() + { + return len; + } + + public ECPoint lookup(int index) + { + long[] x = Nat.create64(FE_LONGS), y = Nat.create64(FE_LONGS); + int pos = 0; + + for (int i = 0; i < len; ++i) + { + long MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_LONGS + j] & MASK; + } + + pos += (FE_LONGS * 2); + } + + return createRawPoint(new ECFieldElement.F2m(m, ks, new LongArray(x)), new ECFieldElement.F2m(m, ks, new LongArray(y)), false); + } + }; } } } 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 18409c09..49d1c2f1 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java @@ -24,6 +24,11 @@ public abstract class ECFieldElement public abstract ECFieldElement invert(); public abstract ECFieldElement sqrt(); + public ECFieldElement() + { + + } + public int bitLength() { return toBigInteger().bitLength(); @@ -84,7 +89,11 @@ public abstract class ECFieldElement return BigIntegers.asUnsignedByteArray((getFieldSize() + 7) / 8, toBigInteger()); } - public static class Fp extends ECFieldElement + public static abstract class AbstractFp extends ECFieldElement + { + } + + public static class Fp extends AbstractFp { BigInteger q, r, x; @@ -491,6 +500,49 @@ public abstract class ECFieldElement } } + public static abstract class AbstractF2m extends ECFieldElement + { + public ECFieldElement halfTrace() + { + int m = this.getFieldSize(); + if ((m & 1) == 0) + { + throw new IllegalStateException("Half-trace only defined for odd m"); + } + + ECFieldElement fe = this; + ECFieldElement ht = fe; + for (int i = 2; i < m; i += 2) + { + fe = fe.squarePow(2); + ht = ht.add(fe); + } + + return ht; + } + + public int trace() + { + int m = this.getFieldSize(); + ECFieldElement fe = this; + ECFieldElement tr = fe; + for (int i = 1; i < m; ++i) + { + fe = fe.square(); + tr = tr.add(fe); + } + if (tr.isZero()) + { + return 0; + } + if (tr.isOne()) + { + return 1; + } + throw new IllegalStateException("Internal error in trace calculation"); + } + } + /** * Class representing the Elements of the finite field * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB) @@ -498,7 +550,7 @@ public abstract class ECFieldElement * basis representations are supported. Gaussian normal basis (GNB) * representation is not supported. */ - public static class F2m extends ECFieldElement + public static class F2m extends AbstractF2m { /** * Indicates gaussian normal basis representation (GNB). Number chosen @@ -533,7 +585,7 @@ public abstract class ECFieldElement /** * The <code>LongArray</code> holding the bits. */ - private LongArray x; + LongArray x; /** * Constructor for PPB. @@ -588,23 +640,7 @@ public abstract class ECFieldElement this.x = new LongArray(x); } - /** - * Constructor for TPB. - * @param m The exponent <code>m</code> of - * <code>F<sub>2<sup>m</sup></sub></code>. - * @param k 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>. - * @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) - { - // Set k1 to k, and set k2 and k3 to 0 - this(m, k, 0, 0, x); - } - - private F2m(int m, int[] ks, LongArray x) + F2m(int m, int[] ks, LongArray x) { this.m = m; this.representation = (ks.length == 1) ? TPB : PPB; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECLookupTable.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECLookupTable.java new file mode 100644 index 00000000..7ff5c6a4 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECLookupTable.java @@ -0,0 +1,7 @@ +package org.bouncycastle.math.ec; + +public interface ECLookupTable +{ + int getSize(); + ECPoint lookup(int index); +} 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 0ea5026c..57dfa339 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java @@ -8,7 +8,7 @@ import java.util.Hashtable; */ public abstract class ECPoint { - protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0]; + protected final static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0]; protected static ECFieldElement[] getInitialZCoords(ECCurve curve) { @@ -64,13 +64,21 @@ public abstract class ECPoint this.zs = zs; } - protected boolean satisfiesCofactor() + protected abstract boolean satisfiesCurveEquation(); + + protected boolean satisfiesOrder() { - BigInteger h = curve.getCofactor(); - return h == null || h.equals(ECConstants.ONE) || !ECAlgorithms.referenceMultiply(this, h).isInfinity(); - } + if (ECConstants.ONE.equals(curve.getCofactor())) + { + return true; + } - protected abstract boolean satisfiesCurveEquation(); + BigInteger n = curve.getOrder(); + + // TODO Require order to be available for all curves + + return n == null || ECAlgorithms.referenceMultiply(this, n).isInfinity(); + } public final ECPoint getDetachedPoint() { @@ -91,33 +99,6 @@ public abstract class ECPoint } /** - * 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 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 @@ -297,28 +278,58 @@ public abstract class ECPoint public boolean isValid() { + return implIsValid(false, true); + } + + boolean isValidPartial() + { + return implIsValid(false, false); + } + + boolean implIsValid(final boolean decompressed, final boolean checkOrder) + { if (isInfinity()) { return true; } - // TODO Sanity-check the field elements - - ECCurve curve = getCurve(); - if (curve != null) + ValidityPrecompInfo validity = (ValidityPrecompInfo)getCurve().precompute(this, ValidityPrecompInfo.PRECOMP_NAME, new PreCompCallback() { - if (!satisfiesCurveEquation()) + public PreCompInfo precompute(PreCompInfo existing) { - return false; - } + ValidityPrecompInfo info = (existing instanceof ValidityPrecompInfo) ? (ValidityPrecompInfo)existing : null; + if (info == null) + { + info = new ValidityPrecompInfo(); + } - if (!satisfiesCofactor()) - { - return false; + if (info.hasFailed()) + { + return info; + } + if (!info.hasCurveEquationPassed()) + { + if (!decompressed && !satisfiesCurveEquation()) + { + info.reportFailed(); + return info; + } + info.reportCurveEquationPassed(); + } + if (checkOrder && !info.hasOrderPassed()) + { + if (!satisfiesOrder()) + { + info.reportFailed(); + return info; + } + info.reportOrderPassed(); + } + return info; } - } + }); - return true; + return !validity.hasFailed(); } public ECPoint scaleX(ECFieldElement scale) @@ -440,6 +451,7 @@ public abstract class ECPoint /** * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} + * @return a byte encoding. */ public byte[] getEncoded() { @@ -602,20 +614,6 @@ public abstract class ECPoint public static class Fp extends AbstractFp { /** - * Create a point which encodes without 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) - { - this(curve, x, y, false); - } - - /** * Create a point that encodes with or without point compression. * * @param curve the curve to use @@ -646,7 +644,7 @@ public abstract class ECPoint protected ECPoint detach() { - return new ECPoint.Fp(null, this.getAffineXCoord(), this.getAffineYCoord()); + return new ECPoint.Fp(null, this.getAffineXCoord(), this.getAffineYCoord(), false); } public ECFieldElement getZCoord(int index) @@ -1423,6 +1421,46 @@ public abstract class ECPoint return lhs.equals(rhs); } + protected boolean satisfiesOrder() + { + BigInteger cofactor = curve.getCofactor(); + if (ECConstants.TWO.equals(cofactor)) + { + /* + * Check that the trace of (X + A) is 0, then there exists a solution to L^2 + L = X + A, + * and so a halving is possible, so this point is the double of another. + */ + ECPoint N = this.normalize(); + ECFieldElement X = N.getAffineXCoord(); + ECFieldElement rhs = X.add(curve.getA()); + return ((ECFieldElement.AbstractF2m)rhs).trace() == 0; + } + if (ECConstants.FOUR.equals(cofactor)) + { + /* + * Solve L^2 + L = X + A to find the half of this point, if it exists (fail if not). + * Generate both possibilities for the square of the half-point's x-coordinate (w), + * and check if Tr(w + A) == 0 for at least one; then a second halving is possible + * (see comments for cofactor 2 above), so this point is four times another. + * + * Note: Tr(x^2) == Tr(x). + */ + ECPoint N = this.normalize(); + ECFieldElement X = N.getAffineXCoord(); + ECFieldElement lambda = ((ECCurve.AbstractF2m)curve).solveQuadraticEquation(X.add(curve.getA())); + if (lambda == null) + { + return false; + } + ECFieldElement w = X.multiply(lambda).add(N.getAffineYCoord()); + ECFieldElement t = w.add(curve.getA()); + return ((ECFieldElement.AbstractF2m)t).trace() == 0 + || ((ECFieldElement.AbstractF2m)(t.add(X))).trace() == 0; + } + + return super.satisfiesOrder(); + } + public ECPoint scaleX(ECFieldElement scale) { if (this.isInfinity()) @@ -1580,18 +1618,6 @@ 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) - { - this(curve, x, y, false); - } - - /** - * @param curve base curve - * @param x x point - * @param y y point * @param withCompression true if encode with point compression. * * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} @@ -1633,7 +1659,7 @@ public abstract class ECPoint protected ECPoint detach() { - return new ECPoint.F2m(null, this.getAffineXCoord(), this.getAffineYCoord()); // earlier JDK + return new ECPoint.F2m(null, this.getAffineXCoord(), this.getAffineYCoord(), false); // earlier JDK } public ECFieldElement getYCoord() diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java index c91de7b1..f3dad929 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java @@ -2,6 +2,8 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; +import org.bouncycastle.math.raw.Nat; + public class FixedPointCombMultiplier extends AbstractECMultiplier { protected ECPoint multiplyPositive(ECPoint p, BigInteger k) @@ -20,38 +22,35 @@ public class FixedPointCombMultiplier extends AbstractECMultiplier throw new IllegalStateException("fixed-point comb doesn't support scalars larger than the curve order"); } - int minWidth = getWidthForCombSize(size); - - FixedPointPreCompInfo info = FixedPointUtil.precompute(p, minWidth); - ECPoint[] lookupTable = info.getPreComp(); + FixedPointPreCompInfo info = FixedPointUtil.precompute(p); + ECLookupTable lookupTable = info.getLookupTable(); int width = info.getWidth(); int d = (size + width - 1) / width; ECPoint R = c.getInfinity(); - int top = d * width - 1; + int fullComb = d * width; + int[] K = Nat.fromBigInteger(fullComb, k); + + int top = fullComb - 1; for (int i = 0; i < d; ++i) { - int index = 0; + int secretIndex = 0; for (int j = top - i; j >= 0; j -= d) { - index <<= 1; - if (k.testBit(j)) - { - index |= 1; - } + int secretBit = K[j >>> 5] >>> (j & 0x1F); + secretIndex ^= secretBit >>> 1; + secretIndex <<= 1; + secretIndex ^= secretBit; } - R = R.twicePlus(lookupTable[index]); + ECPoint add = lookupTable.lookup(secretIndex); + + R = R.twicePlus(add); } return R.add(info.getOffset()); } - - protected int getWidthForCombSize(int combSize) - { - return combSize > 257 ? 6 : 5; - } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointPreCompInfo.java b/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointPreCompInfo.java index 31f5d101..93889e1f 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointPreCompInfo.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointPreCompInfo.java @@ -8,10 +8,9 @@ public class FixedPointPreCompInfo implements PreCompInfo protected ECPoint offset = null; /** - * Array holding the precomputed <code>ECPoint</code>s used for a fixed - * point multiplication. + * Lookup table for the precomputed {@link ECPoint}s used for a fixed point multiplication. */ - protected ECPoint[] preComp = null; + protected ECLookupTable lookupTable = null; /** * The width used for the precomputation. If a larger width precomputation @@ -20,24 +19,24 @@ public class FixedPointPreCompInfo implements PreCompInfo */ protected int width = -1; - public ECPoint getOffset() + public ECLookupTable getLookupTable() { - return offset; + return lookupTable; } - public void setOffset(ECPoint offset) + public void setLookupTable(ECLookupTable lookupTable) { - this.offset = offset; + this.lookupTable = lookupTable; } - public ECPoint[] getPreComp() + public ECPoint getOffset() { - return preComp; + return offset; } - public void setPreComp(ECPoint[] preComp) + public void setOffset(ECPoint offset) { - this.preComp = preComp; + this.offset = offset; } public int getWidth() diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointUtil.java b/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointUtil.java index 93b435c5..6b81d236 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointUtil.java @@ -14,62 +14,74 @@ public class FixedPointUtil public static FixedPointPreCompInfo getFixedPointPreCompInfo(PreCompInfo preCompInfo) { - if ((preCompInfo != null) && (preCompInfo instanceof FixedPointPreCompInfo)) - { - return (FixedPointPreCompInfo)preCompInfo; - } - - return new FixedPointPreCompInfo(); + return (preCompInfo instanceof FixedPointPreCompInfo) ? (FixedPointPreCompInfo)preCompInfo : null; } - public static FixedPointPreCompInfo precompute(ECPoint p, int minWidth) + public static FixedPointPreCompInfo precompute(final ECPoint p) { - ECCurve c = p.getCurve(); - - int n = 1 << minWidth; - FixedPointPreCompInfo info = getFixedPointPreCompInfo(c.getPreCompInfo(p, PRECOMP_NAME)); - ECPoint[] lookupTable = info.getPreComp(); + final ECCurve c = p.getCurve(); - if (lookupTable == null || lookupTable.length < n) + return (FixedPointPreCompInfo)c.precompute(p, PRECOMP_NAME, new PreCompCallback() { - int bits = getCombSize(c); - int d = (bits + minWidth - 1) / minWidth; - - ECPoint[] pow2Table = new ECPoint[minWidth + 1]; - pow2Table[0] = p; - for (int i = 1; i < minWidth; ++i) + public PreCompInfo precompute(PreCompInfo existing) { - pow2Table[i] = pow2Table[i - 1].timesPow2(d); - } + FixedPointPreCompInfo existingFP = (existing instanceof FixedPointPreCompInfo) ? (FixedPointPreCompInfo)existing : null; - // This will be the 'offset' value - pow2Table[minWidth] = pow2Table[0].subtract(pow2Table[1]); + int bits = getCombSize(c); + int minWidth = bits > 250 ? 6 : 5; + int n = 1 << minWidth; - c.normalizeAll(pow2Table); + if (checkExisting(existingFP, n)) + { + return existingFP; + } - lookupTable = new ECPoint[n]; - lookupTable[0] = pow2Table[0]; + int d = (bits + minWidth - 1) / minWidth; - for (int bit = minWidth - 1; bit >= 0; --bit) - { - ECPoint pow2 = pow2Table[bit]; + ECPoint[] pow2Table = new ECPoint[minWidth + 1]; + pow2Table[0] = p; + for (int i = 1; i < minWidth; ++i) + { + pow2Table[i] = pow2Table[i - 1].timesPow2(d); + } - int step = 1 << bit; - for (int i = step; i < n; i += (step << 1)) + // This will be the 'offset' value + pow2Table[minWidth] = pow2Table[0].subtract(pow2Table[1]); + + c.normalizeAll(pow2Table); + + ECPoint[] lookupTable = new ECPoint[n]; + lookupTable[0] = pow2Table[0]; + + for (int bit = minWidth - 1; bit >= 0; --bit) { - lookupTable[i] = lookupTable[i - step].add(pow2); + ECPoint pow2 = pow2Table[bit]; + + int step = 1 << bit; + for (int i = step; i < n; i += (step << 1)) + { + lookupTable[i] = lookupTable[i - step].add(pow2); + } } - } - c.normalizeAll(lookupTable); + c.normalizeAll(lookupTable); - info.setOffset(pow2Table[minWidth]); - info.setPreComp(lookupTable); - info.setWidth(minWidth); + FixedPointPreCompInfo result = new FixedPointPreCompInfo(); + result.setLookupTable(c.createCacheSafeLookupTable(lookupTable, 0, lookupTable.length)); + result.setOffset(pow2Table[minWidth]); + result.setWidth(minWidth); + return result; + } - c.setPreCompInfo(p, PRECOMP_NAME, info); - } + private boolean checkExisting(FixedPointPreCompInfo existingFP, int n) + { + return existingFP != null && checkTable(existingFP.getLookupTable(), n); + } - return info; + private boolean checkTable(ECLookupTable table, int n) + { + return table != null && table.getSize() >= n; + } + }); } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java b/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java index b963118a..b9a1535f 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java @@ -373,6 +373,11 @@ class LongArray implements Cloneable } } + void copyTo(long[] z, int zOff) + { + System.arraycopy(m_ints, 0, z, zOff, m_ints.length); + } + public boolean isOne() { long[] a = m_ints; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompCallback.java b/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompCallback.java new file mode 100644 index 00000000..5cbd8d02 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompCallback.java @@ -0,0 +1,6 @@ +package org.bouncycastle.math.ec; + +public interface PreCompCallback +{ + PreCompInfo precompute(PreCompInfo existing); +} diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ValidityPrecompInfo.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ValidityPrecompInfo.java new file mode 100644 index 00000000..d3a3ce31 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ValidityPrecompInfo.java @@ -0,0 +1,40 @@ +package org.bouncycastle.math.ec; + +class ValidityPrecompInfo implements PreCompInfo +{ + static final String PRECOMP_NAME = "bc_validity"; + + private boolean failed = false; + private boolean curveEquationPassed = false; + private boolean orderPassed = false; + + boolean hasFailed() + { + return failed; + } + + void reportFailed() + { + failed = true; + } + + boolean hasCurveEquationPassed() + { + return curveEquationPassed; + } + + void reportCurveEquationPassed() + { + curveEquationPassed = true; + } + + boolean hasOrderPassed() + { + return orderPassed; + } + + void reportOrderPassed() + { + orderPassed = true; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java index 301b5aee..f383308a 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java @@ -304,12 +304,7 @@ public abstract class WNafUtil public static WNafPreCompInfo getWNafPreCompInfo(PreCompInfo preCompInfo) { - if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo)) - { - return (WNafPreCompInfo)preCompInfo; - } - - return new WNafPreCompInfo(); + return (preCompInfo instanceof WNafPreCompInfo) ? (WNafPreCompInfo)preCompInfo : null; } /** @@ -343,178 +338,214 @@ public abstract class WNafUtil return w + 2; } - public static ECPoint mapPointWithPrecomp(ECPoint p, int width, boolean includeNegated, - ECPointMap pointMap) + public static ECPoint mapPointWithPrecomp(ECPoint p, final int width, final boolean includeNegated, + final ECPointMap pointMap) { - ECCurve c = p.getCurve(); - WNafPreCompInfo wnafPreCompP = precompute(p, width, includeNegated); + final ECCurve c = p.getCurve(); + final WNafPreCompInfo wnafPreCompP = precompute(p, width, includeNegated); ECPoint q = pointMap.map(p); - WNafPreCompInfo wnafPreCompQ = getWNafPreCompInfo(c.getPreCompInfo(q, PRECOMP_NAME)); - - ECPoint twiceP = wnafPreCompP.getTwice(); - if (twiceP != null) + c.precompute(q, PRECOMP_NAME, new PreCompCallback() { - ECPoint twiceQ = pointMap.map(twiceP); - wnafPreCompQ.setTwice(twiceQ); - } + public PreCompInfo precompute(PreCompInfo existing) + { + WNafPreCompInfo result = new WNafPreCompInfo(); - ECPoint[] preCompP = wnafPreCompP.getPreComp(); - ECPoint[] preCompQ = new ECPoint[preCompP.length]; - for (int i = 0; i < preCompP.length; ++i) - { - preCompQ[i] = pointMap.map(preCompP[i]); - } - wnafPreCompQ.setPreComp(preCompQ); + ECPoint twiceP = wnafPreCompP.getTwice(); + if (twiceP != null) + { + ECPoint twiceQ = pointMap.map(twiceP); + result.setTwice(twiceQ); + } - if (includeNegated) - { - ECPoint[] preCompNegQ = new ECPoint[preCompQ.length]; - for (int i = 0; i < preCompNegQ.length; ++i) - { - preCompNegQ[i] = preCompQ[i].negate(); - } - wnafPreCompQ.setPreCompNeg(preCompNegQ); - } + ECPoint[] preCompP = wnafPreCompP.getPreComp(); + ECPoint[] preCompQ = new ECPoint[preCompP.length]; + for (int i = 0; i < preCompP.length; ++i) + { + preCompQ[i] = pointMap.map(preCompP[i]); + } + result.setPreComp(preCompQ); + + if (includeNegated) + { + ECPoint[] preCompNegQ = new ECPoint[preCompQ.length]; + for (int i = 0; i < preCompNegQ.length; ++i) + { + preCompNegQ[i] = preCompQ[i].negate(); + } + result.setPreCompNeg(preCompNegQ); + } - c.setPreCompInfo(q, PRECOMP_NAME, wnafPreCompQ); + return result; + } + }); return q; } - public static WNafPreCompInfo precompute(ECPoint p, int width, boolean includeNegated) + public static WNafPreCompInfo precompute(final ECPoint p, final int width, final boolean includeNegated) { - ECCurve c = p.getCurve(); - WNafPreCompInfo wnafPreCompInfo = getWNafPreCompInfo(c.getPreCompInfo(p, PRECOMP_NAME)); + final ECCurve c = p.getCurve(); - int iniPreCompLen = 0, reqPreCompLen = 1 << Math.max(0, width - 2); - - ECPoint[] preComp = wnafPreCompInfo.getPreComp(); - if (preComp == null) - { - preComp = EMPTY_POINTS; - } - else + return (WNafPreCompInfo)c.precompute(p, PRECOMP_NAME, new PreCompCallback() { - iniPreCompLen = preComp.length; - } + public PreCompInfo precompute(PreCompInfo existing) + { + WNafPreCompInfo existingWNaf = (existing instanceof WNafPreCompInfo) ? (WNafPreCompInfo)existing : null; - if (iniPreCompLen < reqPreCompLen) - { - preComp = resizeTable(preComp, reqPreCompLen); + int reqPreCompLen = 1 << Math.max(0, width - 2); - if (reqPreCompLen == 1) - { - preComp[0] = p.normalize(); - } - else - { - int curPreCompLen = iniPreCompLen; - if (curPreCompLen == 0) + if (checkExisting(existingWNaf, reqPreCompLen, includeNegated)) { - preComp[0] = p; - curPreCompLen = 1; + return existingWNaf; } - ECFieldElement iso = null; + ECPoint[] preComp = null, preCompNeg = null; + ECPoint twiceP = null; + + if (existingWNaf != null) + { + preComp = existingWNaf.getPreComp(); + preCompNeg = existingWNaf.getPreCompNeg(); + twiceP = existingWNaf.getTwice(); + } - if (reqPreCompLen == 2) + int iniPreCompLen = 0; + if (preComp == null) { - preComp[1] = p.threeTimes(); + preComp = EMPTY_POINTS; } else { - ECPoint twiceP = wnafPreCompInfo.getTwice(), last = preComp[curPreCompLen - 1]; - if (twiceP == null) - { - twiceP = preComp[0].twice(); - wnafPreCompInfo.setTwice(twiceP); + iniPreCompLen = preComp.length; + } - /* - * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism - * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This - * also requires scaling the initial point's X, Y coordinates, and reversing the - * isomorphism as part of the subsequent normalization. - * - * NOTE: The correctness of this optimization depends on: - * 1) additions do not use the curve's A, B coefficients. - * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ... - */ - if (!twiceP.isInfinity() && ECAlgorithms.isFpCurve(c) && c.getFieldSize() >= 64) + if (iniPreCompLen < reqPreCompLen) + { + preComp = resizeTable(preComp, reqPreCompLen); + + if (reqPreCompLen == 1) + { + preComp[0] = p.normalize(); + } + else + { + int curPreCompLen = iniPreCompLen; + if (curPreCompLen == 0) { - switch (c.getCoordinateSystem()) - { - case ECCurve.COORD_JACOBIAN: - case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: - case ECCurve.COORD_JACOBIAN_MODIFIED: - { - iso = twiceP.getZCoord(0); - twiceP = c.createPoint(twiceP.getXCoord().toBigInteger(), twiceP.getYCoord() - .toBigInteger()); + preComp[0] = p; + curPreCompLen = 1; + } - ECFieldElement iso2 = iso.square(), iso3 = iso2.multiply(iso); - last = last.scaleX(iso2).scaleY(iso3); + ECFieldElement iso = null; - if (iniPreCompLen == 0) + if (reqPreCompLen == 2) + { + preComp[1] = p.threeTimes(); + } + else + { + ECPoint isoTwiceP = twiceP, last = preComp[curPreCompLen - 1]; + if (isoTwiceP == null) + { + isoTwiceP = preComp[0].twice(); + twiceP = isoTwiceP; + + /* + * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism + * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This + * also requires scaling the initial point's X, Y coordinates, and reversing the + * isomorphism as part of the subsequent normalization. + * + * NOTE: The correctness of this optimization depends on: + * 1) additions do not use the curve's A, B coefficients. + * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ... + */ + if (!twiceP.isInfinity() && ECAlgorithms.isFpCurve(c) && c.getFieldSize() >= 64) { - preComp[0] = last; + switch (c.getCoordinateSystem()) + { + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + iso = twiceP.getZCoord(0); + isoTwiceP = c.createPoint(twiceP.getXCoord().toBigInteger(), twiceP.getYCoord() + .toBigInteger()); + + ECFieldElement iso2 = iso.square(), iso3 = iso2.multiply(iso); + last = last.scaleX(iso2).scaleY(iso3); + + if (iniPreCompLen == 0) + { + preComp[0] = last; + } + break; + } + } } - break; } + + while (curPreCompLen < reqPreCompLen) + { + /* + * Compute the new ECPoints for the precomputation array. The values 1, 3, + * 5, ..., 2^(width-1)-1 times p are computed + */ + preComp[curPreCompLen++] = last = last.add(isoTwiceP); } } - } - while (curPreCompLen < reqPreCompLen) - { /* - * Compute the new ECPoints for the precomputation array. The values 1, 3, - * 5, ..., 2^(width-1)-1 times p are computed + * Having oft-used operands in affine form makes operations faster. */ - preComp[curPreCompLen++] = last = last.add(twiceP); + c.normalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso); } } - /* - * Having oft-used operands in affine form makes operations faster. - */ - c.normalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso); - } - } + if (includeNegated) + { + int pos; + if (preCompNeg == null) + { + pos = 0; + preCompNeg = new ECPoint[reqPreCompLen]; + } + else + { + pos = preCompNeg.length; + if (pos < reqPreCompLen) + { + preCompNeg = resizeTable(preCompNeg, reqPreCompLen); + } + } - wnafPreCompInfo.setPreComp(preComp); + while (pos < reqPreCompLen) + { + preCompNeg[pos] = preComp[pos].negate(); + ++pos; + } + } - if (includeNegated) - { - ECPoint[] preCompNeg = wnafPreCompInfo.getPreCompNeg(); - - int pos; - if (preCompNeg == null) - { - pos = 0; - preCompNeg = new ECPoint[reqPreCompLen]; + WNafPreCompInfo result = new WNafPreCompInfo(); + result.setPreComp(preComp); + result.setPreCompNeg(preCompNeg); + result.setTwice(twiceP); + return result; } - else + + private boolean checkExisting(WNafPreCompInfo existingWNaf, int reqPreCompLen, boolean includeNegated) { - pos = preCompNeg.length; - if (pos < reqPreCompLen) - { - preCompNeg = resizeTable(preCompNeg, reqPreCompLen); - } + return existingWNaf != null + && checkTable(existingWNaf.getPreComp(), reqPreCompLen) + && (!includeNegated || checkTable(existingWNaf.getPreCompNeg(), reqPreCompLen)); } - while (pos < reqPreCompLen) + private boolean checkTable(ECPoint[] table, int reqLen) { - preCompNeg[pos] = preComp[pos].negate(); - ++pos; + return table != null && table.length >= reqLen; } - - wnafPreCompInfo.setPreCompNeg(preCompNeg); - } - - c.setPreCompInfo(p, PRECOMP_NAME, wnafPreCompInfo); - - return wnafPreCompInfo; + }); } private static byte[] trim(byte[] a, int length) 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 7974e1d3..0438e1db 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java @@ -36,7 +36,7 @@ public class WTauNafMultiplier extends AbstractECMultiplier ZTauElement rho = Tnaf.partModReduction(k, m, a, s, mu, (byte)10); - return multiplyWTnaf(p, rho, curve.getPreCompInfo(p, PRECOMP_NAME), a, mu); + return multiplyWTnaf(p, rho, a, mu); } /** @@ -49,8 +49,7 @@ public class WTauNafMultiplier extends AbstractECMultiplier * <code>[τ]</code>-adic NAF. * @return <code>p</code> multiplied by <code>λ</code>. */ - private ECPoint.AbstractF2m multiplyWTnaf(ECPoint.AbstractF2m p, ZTauElement lambda, - PreCompInfo preCompInfo, byte a, byte mu) + private ECPoint.AbstractF2m multiplyWTnaf(ECPoint.AbstractF2m p, ZTauElement lambda, byte a, byte mu) { ZTauElement[] alpha = (a == 0) ? Tnaf.alpha0 : Tnaf.alpha1; @@ -59,7 +58,7 @@ public class WTauNafMultiplier extends AbstractECMultiplier byte[]u = Tnaf.tauAdicWNaf(mu, lambda, Tnaf.WIDTH, BigInteger.valueOf(Tnaf.POW_2_WIDTH), tw, alpha); - return multiplyFromWTnaf(p, u, preCompInfo); + return multiplyFromWTnaf(p, u); } /** @@ -71,24 +70,27 @@ public class WTauNafMultiplier extends AbstractECMultiplier * @param u The the WTNAF of <code>λ</code>.. * @return <code>λ * p</code> */ - private static ECPoint.AbstractF2m multiplyFromWTnaf(ECPoint.AbstractF2m p, byte[] u, PreCompInfo preCompInfo) + private static ECPoint.AbstractF2m multiplyFromWTnaf(final ECPoint.AbstractF2m p, byte[] u) { ECCurve.AbstractF2m curve = (ECCurve.AbstractF2m)p.getCurve(); - byte a = curve.getA().toBigInteger().byteValue(); + final byte a = curve.getA().toBigInteger().byteValue(); - ECPoint.AbstractF2m[] pu; - if ((preCompInfo == null) || !(preCompInfo instanceof WTauNafPreCompInfo)) + WTauNafPreCompInfo preCompInfo = (WTauNafPreCompInfo)curve.precompute(p, PRECOMP_NAME, new PreCompCallback() { - pu = Tnaf.getPreComp(p, a); + public PreCompInfo precompute(PreCompInfo existing) + { + if (existing instanceof WTauNafPreCompInfo) + { + return existing; + } + + WTauNafPreCompInfo result = new WTauNafPreCompInfo(); + result.setPreComp(Tnaf.getPreComp(p, a)); + return result; + } + }); - WTauNafPreCompInfo pre = new WTauNafPreCompInfo(); - pre.setPreComp(pu); - curve.setPreCompInfo(p, PRECOMP_NAME, pre); - } - else - { - pu = ((WTauNafPreCompInfo)preCompInfo).getPreComp(); - } + ECPoint.AbstractF2m[] pu = preCompInfo.getPreComp(); // TODO Include negations in precomp (optionally) and use from here ECPoint.AbstractF2m[] puNeg = new ECPoint.AbstractF2m[pu.length]; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java index b46cba6a..f160ab31 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java @@ -5,7 +5,9 @@ import java.math.BigInteger; import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECLookupTable; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat192; import org.bouncycastle.util.encoders.Hex; public class SecP192K1Curve extends ECCurve.AbstractFp @@ -76,4 +78,49 @@ public class SecP192K1Curve extends ECCurve.AbstractFp { return infinity; } + + public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len) + { + final int FE_INTS = 6; + + final int[] table = new int[len * FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat192.copy(((SecP192K1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS; + Nat192.copy(((SecP192K1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS; + } + } + + return new ECLookupTable() + { + public int getSize() + { + return len; + } + + public ECPoint lookup(int index) + { + int[] x = Nat192.create(), y = Nat192.create(); + int pos = 0; + + for (int i = 0; i < len; ++i) + { + int MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_INTS + j] & MASK; + } + + pos += (FE_INTS * 2); + } + + return createRawPoint(new SecP192K1FieldElement(x), new SecP192K1FieldElement(y), false); + } + }; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java index 642c44cd..39e62afa 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java @@ -7,7 +7,7 @@ import org.bouncycastle.math.raw.Mod; import org.bouncycastle.math.raw.Nat192; import org.bouncycastle.util.Arrays; -public class SecP192K1FieldElement extends ECFieldElement +public class SecP192K1FieldElement extends ECFieldElement.AbstractFp { public static final BigInteger Q = SecP192K1Curve.q; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java index be67100a..a43a5966 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java @@ -4,7 +4,9 @@ import java.math.BigInteger; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECLookupTable; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat192; import org.bouncycastle.util.encoders.Hex; public class SecP192R1Curve extends ECCurve.AbstractFp @@ -77,4 +79,49 @@ public class SecP192R1Curve extends ECCurve.AbstractFp { return infinity; } + + public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len) + { + final int FE_INTS = 6; + + final int[] table = new int[len * FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat192.copy(((SecP192R1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS; + Nat192.copy(((SecP192R1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS; + } + } + + return new ECLookupTable() + { + public int getSize() + { + return len; + } + + public ECPoint lookup(int index) + { + int[] x = Nat192.create(), y = Nat192.create(); + int pos = 0; + + for (int i = 0; i < len; ++i) + { + int MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_INTS + j] & MASK; + } + + pos += (FE_INTS * 2); + } + + return createRawPoint(new SecP192R1FieldElement(x), new SecP192R1FieldElement(y), false); + } + }; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java index 68c8080d..15fdcd63 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java @@ -7,7 +7,7 @@ import org.bouncycastle.math.raw.Mod; import org.bouncycastle.math.raw.Nat192; import org.bouncycastle.util.Arrays; -public class SecP192R1FieldElement extends ECFieldElement +public class SecP192R1FieldElement extends ECFieldElement.AbstractFp { public static final BigInteger Q = SecP192R1Curve.q; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java index ad733da6..6b28be79 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java @@ -5,7 +5,9 @@ import java.math.BigInteger; import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECLookupTable; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat224; import org.bouncycastle.util.encoders.Hex; public class SecP224K1Curve extends ECCurve.AbstractFp @@ -75,4 +77,49 @@ public class SecP224K1Curve extends ECCurve.AbstractFp { return infinity; } + + public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len) + { + final int FE_INTS = 7; + + final int[] table = new int[len * FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat224.copy(((SecP224K1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS; + Nat224.copy(((SecP224K1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS; + } + } + + return new ECLookupTable() + { + public int getSize() + { + return len; + } + + public ECPoint lookup(int index) + { + int[] x = Nat224.create(), y = Nat224.create(); + int pos = 0; + + for (int i = 0; i < len; ++i) + { + int MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_INTS + j] & MASK; + } + + pos += (FE_INTS * 2); + } + + return createRawPoint(new SecP224K1FieldElement(x), new SecP224K1FieldElement(y), false); + } + }; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java index 8285a4e9..2093a061 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java @@ -7,7 +7,7 @@ import org.bouncycastle.math.raw.Mod; import org.bouncycastle.math.raw.Nat224; import org.bouncycastle.util.Arrays; -public class SecP224K1FieldElement extends ECFieldElement +public class SecP224K1FieldElement extends ECFieldElement.AbstractFp { public static final BigInteger Q = SecP224K1Curve.q; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java index c8443299..febb323c 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java @@ -4,7 +4,9 @@ import java.math.BigInteger; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECLookupTable; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat224; import org.bouncycastle.util.encoders.Hex; public class SecP224R1Curve extends ECCurve.AbstractFp @@ -77,4 +79,49 @@ public class SecP224R1Curve extends ECCurve.AbstractFp { return infinity; } + + public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len) + { + final int FE_INTS = 7; + + final int[] table = new int[len * FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat224.copy(((SecP224R1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS; + Nat224.copy(((SecP224R1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS; + } + } + + return new ECLookupTable() + { + public int getSize() + { + return len; + } + + public ECPoint lookup(int index) + { + int[] x = Nat224.create(), y = Nat224.create(); + int pos = 0; + + for (int i = 0; i < len; ++i) + { + int MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_INTS + j] & MASK; + } + + pos += (FE_INTS * 2); + } + + return createRawPoint(new SecP224R1FieldElement(x), new SecP224R1FieldElement(y), false); + } + }; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java index 4a28f3d0..ed2334a7 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java @@ -8,7 +8,7 @@ import org.bouncycastle.math.raw.Nat; import org.bouncycastle.math.raw.Nat224; import org.bouncycastle.util.Arrays; -public class SecP224R1FieldElement extends ECFieldElement +public class SecP224R1FieldElement extends ECFieldElement.AbstractFp { public static final BigInteger Q = SecP224R1Curve.q; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java index 9b885764..6235381e 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java @@ -5,7 +5,9 @@ import java.math.BigInteger; import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECLookupTable; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat256; import org.bouncycastle.util.encoders.Hex; public class SecP256K1Curve extends ECCurve.AbstractFp @@ -75,4 +77,49 @@ public class SecP256K1Curve extends ECCurve.AbstractFp { return infinity; } + + public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len) + { + final int FE_INTS = 8; + + final int[] table = new int[len * FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.copy(((SecP256K1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS; + Nat256.copy(((SecP256K1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS; + } + } + + return new ECLookupTable() + { + public int getSize() + { + return len; + } + + public ECPoint lookup(int index) + { + int[] x = Nat256.create(), y = Nat256.create(); + int pos = 0; + + for (int i = 0; i < len; ++i) + { + int MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_INTS + j] & MASK; + } + + pos += (FE_INTS * 2); + } + + return createRawPoint(new SecP256K1FieldElement(x), new SecP256K1FieldElement(y), false); + } + }; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java index 467b17f5..30bca2e3 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java @@ -7,7 +7,7 @@ import org.bouncycastle.math.raw.Mod; import org.bouncycastle.math.raw.Nat256; import org.bouncycastle.util.Arrays; -public class SecP256K1FieldElement extends ECFieldElement +public class SecP256K1FieldElement extends ECFieldElement.AbstractFp { public static final BigInteger Q = SecP256K1Curve.q; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java index 5ff6a38d..7d7b51d5 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java @@ -4,7 +4,9 @@ import java.math.BigInteger; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECLookupTable; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat256; import org.bouncycastle.util.encoders.Hex; public class SecP256R1Curve extends ECCurve.AbstractFp @@ -77,4 +79,49 @@ public class SecP256R1Curve extends ECCurve.AbstractFp { return infinity; } + + public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len) + { + final int FE_INTS = 8; + + final int[] table = new int[len * FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat256.copy(((SecP256R1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS; + Nat256.copy(((SecP256R1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS; + } + } + + return new ECLookupTable() + { + public int getSize() + { + return len; + } + + public ECPoint lookup(int index) + { + int[] x = Nat256.create(), y = Nat256.create(); + int pos = 0; + + for (int i = 0; i < len; ++i) + { + int MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_INTS + j] & MASK; + } + + pos += (FE_INTS * 2); + } + + return createRawPoint(new SecP256R1FieldElement(x), new SecP256R1FieldElement(y), false); + } + }; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java index 1e04f4b9..cea1af78 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java @@ -16,7 +16,7 @@ public class SecP256R1Field 0xFFFFFFFF, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0x00000001, 0xFFFFFFFE, 0x00000002, 0xFFFFFFFE }; private static final int P7 = 0xFFFFFFFF; - private static final int PExt15 = 0xFFFFFFFF; + private static final int PExt15s1 = 0xFFFFFFFE >>> 1; public static void add(int[] x, int[] y, int[] z) { @@ -30,7 +30,7 @@ public class SecP256R1Field public static void addExt(int[] xx, int[] yy, int[] zz) { int c = Nat.add(16, xx, yy, zz); - if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt))) + if (c != 0 || ((zz[15] >>> 1) >= PExt15s1 && Nat.gte(16, zz, PExt))) { Nat.subFrom(16, PExt, zz); } @@ -78,7 +78,7 @@ public class SecP256R1Field public static void multiplyAddToExt(int[] x, int[] y, int[] zz) { int c = Nat256.mulAddTo(x, y, zz); - if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt))) + if (c != 0 || ((zz[15] >>> 1) >= PExt15s1 && Nat.gte(16, zz, PExt))) { Nat.subFrom(16, PExt, zz); } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java index be250d10..6be46f24 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java @@ -7,7 +7,7 @@ import org.bouncycastle.math.raw.Mod; import org.bouncycastle.math.raw.Nat256; import org.bouncycastle.util.Arrays; -public class SecP256R1FieldElement extends ECFieldElement +public class SecP256R1FieldElement extends ECFieldElement.AbstractFp { public static final BigInteger Q = SecP256R1Curve.q; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java index 27cbcdb2..7a5603d2 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java @@ -4,7 +4,9 @@ import java.math.BigInteger; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECLookupTable; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat; import org.bouncycastle.util.encoders.Hex; public class SecP384R1Curve extends ECCurve.AbstractFp @@ -77,4 +79,49 @@ public class SecP384R1Curve extends ECCurve.AbstractFp { return infinity; } + + public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len) + { + final int FE_INTS = 12; + + final int[] table = new int[len * FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat.copy(FE_INTS, ((SecP384R1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS; + Nat.copy(FE_INTS, ((SecP384R1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS; + } + } + + return new ECLookupTable() + { + public int getSize() + { + return len; + } + + public ECPoint lookup(int index) + { + int[] x = Nat.create(FE_INTS), y = Nat.create(FE_INTS); + int pos = 0; + + for (int i = 0; i < len; ++i) + { + int MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_INTS + j] & MASK; + } + + pos += (FE_INTS * 2); + } + + return createRawPoint(new SecP384R1FieldElement(x), new SecP384R1FieldElement(y), false); + } + }; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java index 24e585d8..3116b443 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java @@ -7,7 +7,7 @@ import org.bouncycastle.math.raw.Mod; import org.bouncycastle.math.raw.Nat; import org.bouncycastle.util.Arrays; -public class SecP384R1FieldElement extends ECFieldElement +public class SecP384R1FieldElement extends ECFieldElement.AbstractFp { public static final BigInteger Q = SecP384R1Curve.q; diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java index 16691b10..267defcf 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java @@ -4,7 +4,9 @@ import java.math.BigInteger; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECLookupTable; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat; import org.bouncycastle.util.encoders.Hex; public class SecP521R1Curve extends ECCurve.AbstractFp @@ -77,4 +79,49 @@ public class SecP521R1Curve extends ECCurve.AbstractFp { return infinity; } + + public ECLookupTable createCacheSafeLookupTable(ECPoint[] points, int off, final int len) + { + final int FE_INTS = 17; + + final int[] table = new int[len * FE_INTS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + Nat.copy(FE_INTS, ((SecP521R1FieldElement)p.getRawXCoord()).x, 0, table, pos); pos += FE_INTS; + Nat.copy(FE_INTS, ((SecP521R1FieldElement)p.getRawYCoord()).x, 0, table, pos); pos += FE_INTS; + } + } + + return new ECLookupTable() + { + public int getSize() + { + return len; + } + + public ECPoint lookup(int index) + { + int[] x = Nat.create(FE_INTS), y = Nat.create(FE_INTS); + int pos = 0; + + for (int i = 0; i < len; ++i) + { + int MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_INTS + j] & MASK; + } + + pos += (FE_INTS * 2); + } + + return createRawPoint(new SecP521R1FieldElement(x), new SecP521R1FieldElement(y), false); + } + }; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java index ce9b6392..5cf30fc0 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java @@ -7,7 +7,7 @@ import org.bouncycastle.math.raw.Mod; import org.bouncycastle.math.raw.Nat; import org.bouncycastle.util.Arrays; -public class SecP521R1FieldElement extends ECFieldElement +public class SecP521R1FieldElement extends ECFieldElement.AbstractFp { public static final BigInteger Q = SecP521R1Curve.q; diff --git a/bcprov/src/main/java/org/bouncycastle/math/package.html b/bcprov/src/main/java/org/bouncycastle/math/package.html new file mode 100644 index 00000000..0e6088d8 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/math/package.html @@ -0,0 +1,5 @@ +<html> +<body bgcolor="#ffffff"> +The Bouncy Castle math package. +</body> +</html> diff --git a/bcprov/src/main/java/org/bouncycastle/math/raw/Interleave.java b/bcprov/src/main/java/org/bouncycastle/math/raw/Interleave.java new file mode 100644 index 00000000..85f4f6d6 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/math/raw/Interleave.java @@ -0,0 +1,177 @@ +package org.bouncycastle.math.raw; + +public class Interleave +{ + private static final long M32 = 0x55555555L; + private static final long M64 = 0x5555555555555555L; + private static final long M64R = 0xAAAAAAAAAAAAAAAAL; + + /* + * 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. + * + * NOTE: All entries are positive so sign-extension is not an issue. + */ +// private static final short[] INTERLEAVE2_TABLE = new short[] +// { +// 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 +// }; + + public static int expand8to16(int x) + { + x &= 0xFF; + x = (x | (x << 4)) & 0x0F0F; + x = (x | (x << 2)) & 0x3333; + x = (x | (x << 1)) & 0x5555; + return x; + } + + public static int expand16to32(int x) + { + x &= 0xFFFF; + x = (x | (x << 8)) & 0x00FF00FF; + x = (x | (x << 4)) & 0x0F0F0F0F; + x = (x | (x << 2)) & 0x33333333; + x = (x | (x << 1)) & 0x55555555; + return x; + } + + public static long expand32to64(int x) + { + // "shuffle" low half to even bits and high half to odd bits + int t; + t = (x ^ (x >>> 8)) & 0x0000FF00; x ^= (t ^ (t << 8)); + t = (x ^ (x >>> 4)) & 0x00F000F0; x ^= (t ^ (t << 4)); + t = (x ^ (x >>> 2)) & 0x0C0C0C0C; x ^= (t ^ (t << 2)); + t = (x ^ (x >>> 1)) & 0x22222222; x ^= (t ^ (t << 1)); + + return ((x >>> 1) & M32) << 32 | (x & M32); + } + + public static void expand64To128(long x, long[] z, int zOff) + { + // "shuffle" low half to even bits and high half to odd bits + long t; + t = (x ^ (x >>> 16)) & 0x00000000FFFF0000L; x ^= (t ^ (t << 16)); + t = (x ^ (x >>> 8)) & 0x0000FF000000FF00L; x ^= (t ^ (t << 8)); + t = (x ^ (x >>> 4)) & 0x00F000F000F000F0L; x ^= (t ^ (t << 4)); + t = (x ^ (x >>> 2)) & 0x0C0C0C0C0C0C0C0CL; x ^= (t ^ (t << 2)); + t = (x ^ (x >>> 1)) & 0x2222222222222222L; x ^= (t ^ (t << 1)); + + z[zOff ] = (x ) & M64; + z[zOff + 1] = (x >>> 1) & M64; + } + + public static void expand64To128Rev(long x, long[] z, int zOff) + { + // "shuffle" low half to even bits and high half to odd bits + long t; + t = (x ^ (x >>> 16)) & 0x00000000FFFF0000L; x ^= (t ^ (t << 16)); + t = (x ^ (x >>> 8)) & 0x0000FF000000FF00L; x ^= (t ^ (t << 8)); + t = (x ^ (x >>> 4)) & 0x00F000F000F000F0L; x ^= (t ^ (t << 4)); + t = (x ^ (x >>> 2)) & 0x0C0C0C0C0C0C0C0CL; x ^= (t ^ (t << 2)); + t = (x ^ (x >>> 1)) & 0x2222222222222222L; x ^= (t ^ (t << 1)); + + z[zOff ] = (x ) & M64R; + z[zOff + 1] = (x << 1) & M64R; + } + + public static int shuffle(int x) + { + // "shuffle" low half to even bits and high half to odd bits + int t; + t = (x ^ (x >>> 8)) & 0x0000FF00; x ^= (t ^ (t << 8)); + t = (x ^ (x >>> 4)) & 0x00F000F0; x ^= (t ^ (t << 4)); + t = (x ^ (x >>> 2)) & 0x0C0C0C0C; x ^= (t ^ (t << 2)); + t = (x ^ (x >>> 1)) & 0x22222222; x ^= (t ^ (t << 1)); + return x; + } + + public static long shuffle(long x) + { + // "shuffle" low half to even bits and high half to odd bits + long t; + t = (x ^ (x >>> 16)) & 0x00000000FFFF0000L; x ^= (t ^ (t << 16)); + t = (x ^ (x >>> 8)) & 0x0000FF000000FF00L; x ^= (t ^ (t << 8)); + t = (x ^ (x >>> 4)) & 0x00F000F000F000F0L; x ^= (t ^ (t << 4)); + t = (x ^ (x >>> 2)) & 0x0C0C0C0C0C0C0C0CL; x ^= (t ^ (t << 2)); + t = (x ^ (x >>> 1)) & 0x2222222222222222L; x ^= (t ^ (t << 1)); + return x; + } + + public static int shuffle2(int x) + { + // "shuffle" (twice) low half to even bits and high half to odd bits + int t; + t = (x ^ (x >>> 7)) & 0x00AA00AA; x ^= (t ^ (t << 7)); + t = (x ^ (x >>> 14)) & 0x0000CCCC; x ^= (t ^ (t << 14)); + t = (x ^ (x >>> 4)) & 0x00F000F0; x ^= (t ^ (t << 4)); + t = (x ^ (x >>> 8)) & 0x0000FF00; x ^= (t ^ (t << 8)); + return x; + } + + public static int unshuffle(int x) + { + // "unshuffle" even bits to low half and odd bits to high half + int t; + t = (x ^ (x >>> 1)) & 0x22222222; x ^= (t ^ (t << 1)); + t = (x ^ (x >>> 2)) & 0x0C0C0C0C; x ^= (t ^ (t << 2)); + t = (x ^ (x >>> 4)) & 0x00F000F0; x ^= (t ^ (t << 4)); + t = (x ^ (x >>> 8)) & 0x0000FF00; x ^= (t ^ (t << 8)); + return x; + } + + public static long unshuffle(long x) + { + // "unshuffle" even bits to low half and odd bits to high half + long t; + t = (x ^ (x >>> 1)) & 0x2222222222222222L; x ^= (t ^ (t << 1)); + t = (x ^ (x >>> 2)) & 0x0C0C0C0C0C0C0C0CL; x ^= (t ^ (t << 2)); + t = (x ^ (x >>> 4)) & 0x00F000F000F000F0L; x ^= (t ^ (t << 4)); + t = (x ^ (x >>> 8)) & 0x0000FF000000FF00L; x ^= (t ^ (t << 8)); + t = (x ^ (x >>> 16)) & 0x00000000FFFF0000L; x ^= (t ^ (t << 16)); + return x; + } + + public static int unshuffle2(int x) + { + // "unshuffle" (twice) even bits to low half and odd bits to high half + int t; + t = (x ^ (x >>> 8)) & 0x0000FF00; x ^= (t ^ (t << 8)); + t = (x ^ (x >>> 4)) & 0x00F000F0; x ^= (t ^ (t << 4)); + t = (x ^ (x >>> 14)) & 0x0000CCCC; x ^= (t ^ (t << 14)); + t = (x ^ (x >>> 7)) & 0x00AA00AA; x ^= (t ^ (t << 7)); + return x; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat.java b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat.java index 6b77f8fa..d9482cf7 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat.java +++ b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat.java @@ -194,6 +194,41 @@ public abstract class Nat return c == 0 ? 0 : incAt(len, z, zOff, 1); } + public static int cadd(int len, int mask, int[] x, int[] y, int[] z) + { + long MASK = -(mask & 1) & M; + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[i] & M) + (y[i] & MASK); + z[i] = (int)c; + c >>>= 32; + } + return (int)c; + } + + public static void cmov(int len, int mask, int[] x, int xOff, int[] z, int zOff) + { + mask = -(mask & 1); + + for (int i = 0; i < len; ++i) + { + int z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + z_i ^= (diff & mask); + z[zOff + i] = z_i; + } + +// final int half = 0x55555555, rest = half << (-mask); +// +// for (int i = 0; i < len; ++i) +// { +// int z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; +// z_i ^= (diff & half); +// z_i ^= (diff & rest); +// z[zOff + i] = z_i; +// } + } + public static int[] copy(int len, int[] x) { int[] z = new int[len]; @@ -206,6 +241,11 @@ public abstract class Nat System.arraycopy(x, 0, z, 0, len); } + public static void copy(int len, int[] x, int xOff, int[] z, int zOff) + { + System.arraycopy(x, xOff, z, zOff, len); + } + public static int[] create(int len) { return new int[len]; @@ -216,6 +256,19 @@ public abstract class Nat return new long[len]; } + public static int csub(int len, int mask, int[] x, int[] y, int[] z) + { + long MASK = -(mask & 1) & M; + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[i] & M) - (y[i] & MASK); + z[i] = (int)c; + c >>= 32; + } + return (int)c; + } + public static int dec(int len, int[] z) { for (int i = 0; i < len; ++i) @@ -441,6 +494,16 @@ public abstract class Nat } } + public static void mul(int[] x, int xOff, int xLen, int[] y, int yOff, int yLen, int[] zz, int zzOff) + { + zz[zzOff + yLen] = mulWord(yLen, x[xOff], y, yOff, zz, zzOff); + + for (int i = 1; i < xLen; ++i) + { + zz[zzOff + i + yLen] = mulWordAddTo(yLen, x[xOff + i], y, yOff, zz, zzOff + i); + } + } + public static int mulAddTo(int len, int[] x, int[] y, int[] zz) { long zc = 0; diff --git a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java index 12db01bc..ffe74d70 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java +++ b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java @@ -144,6 +144,16 @@ public abstract class Nat192 z[5] = x[5]; } + public static void copy(int[] x, int xOff, int[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + z[zOff + 4] = x[xOff + 4]; + z[zOff + 5] = x[xOff + 5]; + } + public static void copy64(long[] x, long[] z) { z[0] = x[0]; @@ -151,6 +161,13 @@ public abstract class Nat192 z[2] = x[2]; } + public static void copy64(long[] x, int xOff, long[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + } + public static int[] create() { return new int[6]; diff --git a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java index 9ff107c1..59be1f51 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java +++ b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java @@ -215,6 +215,17 @@ public abstract class Nat224 z[6] = x[6]; } + public static void copy(int[] x, int xOff, int[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + z[zOff + 4] = x[xOff + 4]; + z[zOff + 5] = x[xOff + 5]; + z[zOff + 6] = x[xOff + 6]; + } + public static int[] create() { return new int[7]; diff --git a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java index 726bae35..f7d80b3a 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java +++ b/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java @@ -238,6 +238,18 @@ public abstract class Nat256 z[7] = x[7]; } + public static void copy(int[] x, int xOff, int[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + z[zOff + 4] = x[xOff + 4]; + z[zOff + 5] = x[xOff + 5]; + z[zOff + 6] = x[xOff + 6]; + z[zOff + 7] = x[xOff + 7]; + } + public static void copy64(long[] x, long[] z) { z[0] = x[0]; @@ -246,6 +258,14 @@ public abstract class Nat256 z[3] = x[3]; } + public static void copy64(long[] x, int xOff, long[] z, int zOff) + { + z[zOff + 0] = x[xOff + 0]; + z[zOff + 1] = x[xOff + 1]; + z[zOff + 2] = x[xOff + 2]; + z[zOff + 3] = x[xOff + 3]; + } + public static int[] create() { return new int[8]; diff --git a/bcprov/src/main/java/org/bouncycastle/util/Arrays.java b/bcprov/src/main/java/org/bouncycastle/util/Arrays.java index 6873117a..c48ae757 100644 --- a/bcprov/src/main/java/org/bouncycastle/util/Arrays.java +++ b/bcprov/src/main/java/org/bouncycastle/util/Arrays.java @@ -8,11 +8,21 @@ import java.util.NoSuchElementException; */ public final class Arrays { - private Arrays() + private Arrays() { // static class, hide constructor } + public static boolean areAllZeroes(byte[] buf, int off, int len) + { + int bits = 0; + for (int i = 0; i < len; ++i) + { + bits |= buf[off + i]; + } + return bits == 0; + } + public static boolean areEqual( boolean[] a, boolean[] b) @@ -135,36 +145,37 @@ public final class Arrays /** * A constant time equals comparison - does not terminate early if - * test will fail. + * test will fail. For best results always pass the expected value + * as the first parameter. * - * @param a first array - * @param b second array + * @param expected first array + * @param supplied second array * @return true if arrays equal, false otherwise. */ public static boolean constantTimeAreEqual( - byte[] a, - byte[] b) + byte[] expected, + byte[] supplied) { - if (a == b) + if (expected == supplied) { return true; } - if (a == null || b == null) + if (expected == null || supplied == null) { return false; } - if (a.length != b.length) + if (expected.length != supplied.length) { - return false; + return !Arrays.constantTimeAreEqual(expected, expected); } int nonEqual = 0; - for (int i = 0; i != a.length; i++) + for (int i = 0; i != expected.length; i++) { - nonEqual |= (a[i] ^ b[i]); + nonEqual |= (expected[i] ^ supplied[i]); } return nonEqual == 0; @@ -335,6 +346,18 @@ public final class Arrays } public static void fill( + byte[] array, + int start, + int finish, + byte value) + { + for (int i = start; i < finish; i++) + { + array[i] = value; + } + } + + public static void fill( char[] array, char value) { @@ -355,7 +378,7 @@ public final class Arrays } public static void fill( - short[] array, + short[] array, short value) { for (int i = 0; i < array.length; i++) @@ -373,7 +396,63 @@ public final class Arrays array[i] = value; } } - + + public static void fill( + byte[] array, + int out, + byte value) + { + if(out < array.length) + { + for (int i = out; i < array.length; i++) + { + array[i] = value; + } + } + } + + public static void fill( + int[] array, + int out, + int value) + { + if(out < array.length) + { + for (int i = out; i < array.length; i++) + { + array[i] = value; + } + } + } + + public static void fill( + short[] array, + int out, + short value) + { + if(out < array.length) + { + for (int i = out; i < array.length; i++) + { + array[i] = value; + } + } + } + + public static void fill( + long[] array, + int out, + long value) + { + if(out < array.length) + { + for (int i = out; i < array.length; i++) + { + array[i] = value; + } + } + } + public static int hashCode(byte[] data) { if (data == null) @@ -681,9 +760,9 @@ public final class Arrays return null; } long[] copy = new long[data.length]; - + System.arraycopy(data, 0, copy, 0, data.length); - + return copy; } @@ -1126,7 +1205,7 @@ public final class Arrays int p1 = 0, p2 = a.length; byte[] result = new byte[p2]; - + while (--p2 >= 0) { result[p2] = a[p1++]; @@ -1196,4 +1275,20 @@ public final class Arrays throw new UnsupportedOperationException("Cannot remove element from an Array."); } } + + /** + * Fill input array by zeros + * + * @param array input array + */ + public static void clear(byte[] array) + { + if (array != null) + { + for (int i = 0; i < array.length; i++) + { + array[i] = 0; + } + } + } } diff --git a/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java b/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java index f7f7e68b..a118ba5a 100644 --- a/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java +++ b/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java @@ -8,8 +8,13 @@ import java.security.SecureRandom; */ public final class BigIntegers { + public static final BigInteger ZERO = BigInteger.valueOf(0); + public static final BigInteger ONE = BigInteger.valueOf(1); + + private static final BigInteger TWO = BigInteger.valueOf(2); + private static final BigInteger THREE = BigInteger.valueOf(3); + private static final int MAX_ITERATIONS = 1000; - private static final BigInteger ZERO = BigInteger.valueOf(0); /** * Return the passed in value as an unsigned byte array. @@ -92,7 +97,7 @@ public final class BigIntegers for (int i = 0; i < MAX_ITERATIONS; ++i) { - BigInteger x = new BigInteger(max.bitLength(), random); + BigInteger x = createRandomBigInteger(max.bitLength(), random); if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0) { return x; @@ -100,7 +105,7 @@ public final class BigIntegers } // fall back to a faster (restricted) method - return new BigInteger(max.subtract(min).bitLength() - 1, random).add(min); + return createRandomBigInteger(max.subtract(min).bitLength() - 1, random).add(min); } public static BigInteger fromUnsignedByteArray(byte[] buf) @@ -118,4 +123,81 @@ public final class BigIntegers } return new BigInteger(1, mag); } + + public static int getUnsignedByteLength(BigInteger n) + { + return (n.bitLength() + 7) / 8; + } + + /** + * Return a positive BigInteger in the range of 0 to 2**bitLength - 1. + * + * @param bitLength maximum bit length for the generated BigInteger. + * @param random a source of randomness. + * @return a positive BigInteger + */ + public static BigInteger createRandomBigInteger(int bitLength, SecureRandom random) + { + return new BigInteger(1, createRandom(bitLength, random)); + } + + /** + * Return a prime number candidate of the specified bit length. + * + * @param bitLength bit length for the generated BigInteger. + * @param random a source of randomness. + * @return a positive BigInteger of numBits length + */ + public static BigInteger createRandomPrime(int bitLength, int certainty, SecureRandom random) + { + if (bitLength < 2) + { + throw new IllegalArgumentException("bitLength < 2"); + } + + BigInteger rv; + + if (bitLength == 2) + { + return (random.nextInt() < 0) ? TWO : THREE; + } + + do + { + byte[] base = createRandom(bitLength, random); + + int xBits = 8 * base.length - bitLength; + byte lead = (byte)(1 << (7 - xBits)); + + // ensure top and bottom bit set + base[0] |= lead; + base[base.length - 1] |= 0x01; + + rv = new BigInteger(1, base); + } + while (!rv.isProbablePrime(certainty)); + + return rv; + } + + private static byte[] createRandom(int bitLength, SecureRandom random) + throws IllegalArgumentException + { + if (bitLength < 1) + { + throw new IllegalArgumentException("bitLength must be at least 1"); + } + + int nBytes = (bitLength + 7) / 8; + + byte[] rv = new byte[nBytes]; + + random.nextBytes(rv); + + // strip off any excess bits in the MSB + int xBits = 8 * nBytes - bitLength; + rv[0] &= (byte)(255 >>> xBits); + + return rv; + } } diff --git a/bcprov/src/main/java/org/bouncycastle/util/Fingerprint.java b/bcprov/src/main/java/org/bouncycastle/util/Fingerprint.java new file mode 100644 index 00000000..d190ea6a --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/util/Fingerprint.java @@ -0,0 +1,180 @@ +package org.bouncycastle.util; + +// Android-changed: Use Android digests +// import org.bouncycastle.crypto.digests.SHA512tDigest; +// import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.AndroidDigestFactory; + +/** + * Basic 20 byte finger print class. + */ +public class Fingerprint +{ + private static char[] encodingTable = + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + private final byte[] fingerprint; + + /** + * Base constructor - use SHAKE-256 (160 bits). This is the recommended one as it is also + * produced by the FIPS API. + * + * @param source original data to calculate the fingerprint from. + */ + public Fingerprint(byte[] source) + { + this(source, 160); + } + + /** + * Constructor with length - use SHAKE-256 (bitLength bits). This is the recommended one as it is also + * produced by the FIPS API. + * + * @param source original data to calculate the fingerprint from. + */ + public Fingerprint(byte[] source, int bitLength) + { + this.fingerprint = calculateFingerprint(source, bitLength); + } + + // BEGIN Android-removed: Unsupported algorithms + /* + /** + * Base constructor - for backwards compatibility. + * + * @param source original data to calculate the fingerprint from. + * @param useSHA512t use the old SHA512/160 calculation. + * @deprecated use the SHAKE only version. + * + public Fingerprint(byte[] source, boolean useSHA512t) + { + if (useSHA512t) + { + this.fingerprint = calculateFingerprintSHA512_160(source); + } + else + { + this.fingerprint = calculateFingerprint(source); + } + } + */ + // END Android-removed: Unsupported algorithms + + public byte[] getFingerprint() + { + return Arrays.clone(fingerprint); + } + + public String toString() + { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i != fingerprint.length; i++) + { + if (i > 0) + { + sb.append(":"); + } + sb.append(encodingTable[(fingerprint[i] >>> 4) & 0xf]); + sb.append(encodingTable[fingerprint[i] & 0x0f]); + } + + return sb.toString(); + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + if (o instanceof Fingerprint) + { + return Arrays.areEqual(((Fingerprint)o).fingerprint, fingerprint); + } + + return false; + } + + public int hashCode() + { + return Arrays.hashCode(fingerprint); + } + + /** + * Return a byte array containing a calculated fingerprint for the passed in input data. + * This calculation is compatible with the BC FIPS API. + * + * @param input data to base the fingerprint on. + * @return a byte array containing a 160 bit fingerprint. + */ + public static byte[] calculateFingerprint(byte[] input) + { + return calculateFingerprint(input, 160); + } + + /* + /** + * Return a byte array containing a calculated fingerprint for the passed in input data. + * This calculation is compatible with the BC FIPS API. + * + * @param input data to base the fingerprint on. + * @param bitLength bit length of finger print to be produced. + * @return a byte array containing a 20 byte fingerprint. + */ + public static byte[] calculateFingerprint(byte[] input, int bitLength) + { + if (bitLength % 8 != 0) + { + throw new IllegalArgumentException("bitLength must be a multiple of 8"); + } + + // Android-changed: Use SHA-256 instead of SHAKE-256, since we don't support SHAKE + // SHAKEDigest digest = new SHAKEDigest(256); + Digest digest = AndroidDigestFactory.getSHA256(); + + digest.update(input, 0, input.length); + + byte[] rv = new byte[bitLength / 8]; + + // Android-changed: Hash and truncate since SHA-256 doesn't support variable length output + // + // digest.doFinal(rv, 0, bitLength / 8); + byte[] untruncated = new byte[32]; + digest.doFinal(untruncated, 0); + if ((bitLength / 8) >= 32) { + return untruncated; + } + + System.arraycopy(untruncated, 0, rv, 0, rv.length); + + return rv; + } + + // BEGIN Android-removed: Unsupported algorithms + /** + * Return a byte array containing a calculated fingerprint for the passed in input data. + * The fingerprint is based on SHA512/160. + * + * @param input data to base the fingerprint on. + * @return a byte array containing a 20 byte fingerprint. + * @deprecated use the SHAKE based version. + * + public static byte[] calculateFingerprintSHA512_160(byte[] input) + { + SHA512tDigest digest = new SHA512tDigest(160); + + digest.update(input, 0, input.length); + + byte[] rv = new byte[digest.getDigestSize()]; + + digest.doFinal(rv, 0); + + return rv; + } + */ + // END Android-removed: Unsupported algorithms +} diff --git a/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java b/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java index 8af1709e..8f57263f 100644 --- a/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java +++ b/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java @@ -118,7 +118,7 @@ public class IPAddress * * @param address the IP address as a String. * - * @return true if a valid IPv4 address, false otherwise + * @return true if a valid IPv6 address, false otherwise */ public static boolean isValidIPv6( String address) diff --git a/bcprov/src/main/java/org/bouncycastle/util/Pack.java b/bcprov/src/main/java/org/bouncycastle/util/Pack.java index 82b02ea5..44b0b278 100644 --- a/bcprov/src/main/java/org/bouncycastle/util/Pack.java +++ b/bcprov/src/main/java/org/bouncycastle/util/Pack.java @@ -211,6 +211,15 @@ public abstract class Pack } } + public static void littleEndianToLong(byte[] bs, int bsOff, long[] ns, int nsOff, int nsLen) + { + for (int i = 0; i < nsLen; ++i) + { + ns[nsOff + i] = littleEndianToLong(bs, bsOff); + bsOff += 8; + } + } + public static byte[] longToLittleEndian(long n) { byte[] bs = new byte[8]; @@ -239,4 +248,13 @@ public abstract class Pack off += 8; } } + + public static void longToLittleEndian(long[] ns, int nsOff, int nsLen, byte[] bs, int bsOff) + { + for (int i = 0; i < nsLen; ++i) + { + longToLittleEndian(ns[nsOff + i], bs, bsOff); + bsOff += 8; + } + } } diff --git a/bcprov/src/main/java/org/bouncycastle/util/Properties.java b/bcprov/src/main/java/org/bouncycastle/util/Properties.java index e533b586..c472d187 100644 --- a/bcprov/src/main/java/org/bouncycastle/util/Properties.java +++ b/bcprov/src/main/java/org/bouncycastle/util/Properties.java @@ -1,10 +1,13 @@ package org.bouncycastle.util; +import java.math.BigInteger; import java.security.AccessControlException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.StringTokenizer; @@ -13,24 +16,31 @@ import java.util.StringTokenizer; */ public class Properties { - public static boolean isOverrideSet(final String propertyName) + private Properties() + { + + } + + private static final ThreadLocal threadProperties = new ThreadLocal(); + + /** + * Return whether a particular override has been set to true. + * + * @param propertyName the property name for the override. + * @return true if the property is set to "true", false otherwise. + */ + public static boolean isOverrideSet(String propertyName) { try { - return "true".equals(AccessController.doPrivileged(new PrivilegedAction() + String p = fetchProperty(propertyName); + + if (p != null) { - // JDK 1.4 compatibility - public Object run() - { - String value = System.getProperty(propertyName); - if (value == null) - { - return null; - } + return "true".equals(Strings.toLowerCase(p)); + } - return Strings.toLowerCase(value); - } - })); + return false; } catch (AccessControlException e) { @@ -38,10 +48,78 @@ public class Properties } } - public static Set<String> asKeySet(final String propertyName) + /** + * Enable the specified override property for the current thread only. + * + * @param propertyName the property name for the override. + * @param enable true if the override should be enabled, false if it should be disabled. + * @return true if the override was already set, false otherwise. + */ + public static boolean setThreadOverride(String propertyName, boolean enable) + { + boolean isSet = isOverrideSet(propertyName); + + Map localProps = (Map)threadProperties.get(); + if (localProps == null) + { + localProps = new HashMap(); + } + + localProps.put(propertyName, enable ? "true" : "false"); + + threadProperties.set(localProps); + + return isSet; + } + + /** + * Enable the specified override property in the current thread only. + * + * @param propertyName the property name for the override. + * @return true if the override set true in thread local, false otherwise. + */ + public static boolean removeThreadOverride(String propertyName) + { + boolean isSet = isOverrideSet(propertyName); + + Map localProps = (Map)threadProperties.get(); + if (localProps == null) + { + return false; + } + + localProps.remove(propertyName); + + if (localProps.isEmpty()) + { + threadProperties.remove(); + } + else + { + threadProperties.set(localProps); + } + + return isSet; + } + + public static BigInteger asBigInteger(String propertyName) + { + String p = fetchProperty(propertyName); + + if (p != null) + { + return new BigInteger(p); + } + + return null; + } + + public static Set<String> asKeySet(String propertyName) { Set<String> set = new HashSet<String>(); - String p = System.getProperty(propertyName); + + String p = fetchProperty(propertyName); + if (p != null) { StringTokenizer sTok = new StringTokenizer(p, ","); @@ -50,6 +128,24 @@ public class Properties set.add(Strings.toLowerCase(sTok.nextToken()).trim()); } } + return Collections.unmodifiableSet(set); } + + private static String fetchProperty(final String propertyName) + { + return (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + Map localProps = (Map)threadProperties.get(); + if (localProps != null) + { + return localProps.get(propertyName); + } + + return System.getProperty(propertyName); + } + }); + } } diff --git a/bcprov/src/main/java/org/bouncycastle/util/Strings.java b/bcprov/src/main/java/org/bouncycastle/util/Strings.java index a42830b3..bda9d9a6 100644 --- a/bcprov/src/main/java/org/bouncycastle/util/Strings.java +++ b/bcprov/src/main/java/org/bouncycastle/util/Strings.java @@ -8,6 +8,8 @@ import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Vector; +import org.bouncycastle.util.encoders.UTF8; + /** * String utilities. */ @@ -17,105 +19,41 @@ public final class Strings static { - try - { - LINE_SEPARATOR = AccessController.doPrivileged(new PrivilegedAction<String>() - { - public String run() - { - // the easy way - return System.getProperty("line.separator"); - } - }); - - } - catch (Exception e) - { - try - { - // the harder way - LINE_SEPARATOR = String.format("%n"); - } - catch (Exception ef) - { - LINE_SEPARATOR = "\n"; // we're desperate use this... - } - } - } - - public static String fromUTF8ByteArray(byte[] bytes) - { - int i = 0; - int length = 0; - - while (i < bytes.length) + try { - length++; - if ((bytes[i] & 0xf0) == 0xf0) - { - // surrogate pair - length++; - i += 4; - } - else if ((bytes[i] & 0xe0) == 0xe0) + LINE_SEPARATOR = AccessController.doPrivileged(new PrivilegedAction<String>() { - i += 3; - } - else if ((bytes[i] & 0xc0) == 0xc0) - { - i += 2; - } - else - { - i += 1; - } - } - - char[] cs = new char[length]; - - i = 0; - length = 0; + public String run() + { + // the easy way + return System.getProperty("line.separator"); + } + }); - while (i < bytes.length) + } + catch (Exception e) { - char ch; - - if ((bytes[i] & 0xf0) == 0xf0) - { - int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i + 1] & 0x3F) << 12) | ((bytes[i + 2] & 0x3F) << 6) | (bytes[i + 3] & 0x3F); - int U = codePoint - 0x10000; - char W1 = (char)(0xD800 | (U >> 10)); - char W2 = (char)(0xDC00 | (U & 0x3FF)); - cs[length++] = W1; - ch = W2; - i += 4; - } - else if ((bytes[i] & 0xe0) == 0xe0) + try { - ch = (char)(((bytes[i] & 0x0f) << 12) - | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f)); - i += 3; + // the harder way + LINE_SEPARATOR = String.format("%n"); } - else if ((bytes[i] & 0xd0) == 0xd0) - { - ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f)); - i += 2; - } - else if ((bytes[i] & 0xc0) == 0xc0) - { - ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f)); - i += 2; - } - else + catch (Exception ef) { - ch = (char)(bytes[i] & 0xff); - i += 1; + LINE_SEPARATOR = "\n"; // we're desperate use this... } - - cs[length++] = ch; } + } - return new String(cs); + public static String fromUTF8ByteArray(byte[] bytes) + { + char[] chars = new char[bytes.length]; + int len = UTF8.transcodeToUTF16(bytes, chars); + if (len < 0) + { + throw new IllegalArgumentException("Invalid UTF-8 input"); + } + return new String(chars, 0, len); } public static byte[] toUTF8ByteArray(String string) @@ -263,6 +201,7 @@ public final class Strings return bytes; } + public static byte[] toByteArray(String string) { byte[] bytes = new byte[string.length()]; @@ -401,4 +340,6 @@ public final class Strings return strs; } } + + } diff --git a/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java b/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java index 4216674a..645b151c 100644 --- a/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java +++ b/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java @@ -149,11 +149,27 @@ public class Base64Encoder end--; } + + // empty data! + if (end == 0) + { + return 0; + } - int i = off; - int finish = end - 4; - - i = nextI(data, i, finish); + int i = 0; + int finish = end; + + while (finish > off && i != 4) + { + if (!ignore((char)data[finish - 1])) + { + i++; + } + + finish--; + } + + i = nextI(data, off, finish); while (i < finish) { @@ -185,8 +201,13 @@ public class Base64Encoder i = nextI(data, i, finish); } - outLen += decodeLastBlock(out, (char)data[end - 4], (char)data[end - 3], (char)data[end - 2], (char)data[end - 1]); - + int e0 = nextI(data, i, end); + int e1 = nextI(data, e0 + 1, end); + int e2 = nextI(data, e1 + 1, end); + int e3 = nextI(data, e2 + 1, end); + + outLen += decodeLastBlock(out, (char)data[e0], (char)data[e1], (char)data[e2], (char)data[e3]); + return outLen; } @@ -224,11 +245,27 @@ public class Base64Encoder end--; } + + // empty data! + if (end == 0) + { + return 0; + } int i = 0; - int finish = end - 4; + int finish = end; + + while (finish > 0 && i != 4) + { + if (!ignore(data.charAt(finish - 1))) + { + i++; + } + + finish--; + } - i = nextI(data, i, finish); + i = nextI(data, 0, finish); while (i < finish) { @@ -260,8 +297,13 @@ public class Base64Encoder i = nextI(data, i, finish); } - length += decodeLastBlock(out, data.charAt(end - 4), data.charAt(end - 3), data.charAt(end - 2), data.charAt(end - 1)); + int e0 = nextI(data, i, end); + int e1 = nextI(data, e0 + 1, end); + int e2 = nextI(data, e1 + 1, end); + int e3 = nextI(data, e2 + 1, end); + length += decodeLastBlock(out, data.charAt(e0), data.charAt(e1), data.charAt(e2), data.charAt(e3)); + return length; } diff --git a/bcprov/src/main/java/org/bouncycastle/util/encoders/UTF8.java b/bcprov/src/main/java/org/bouncycastle/util/encoders/UTF8.java new file mode 100644 index 00000000..e64e443c --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/util/encoders/UTF8.java @@ -0,0 +1,156 @@ +package org.bouncycastle.util.encoders; + +/** + * Utilities for working with UTF-8 encodings. + * + * Decoding of UTF-8 is based on a presentation by Bob Steagall at CppCon2018 (see + * https://github.com/BobSteagall/CppCon2018). It uses a Deterministic Finite Automaton (DFA) to + * recognize and decode multi-byte code points. + */ +public class UTF8 +{ + // Constants for the categorization of code units + private static final byte C_ILL = 0; //- C0..C1, F5..FF ILLEGAL octets that should never appear in a UTF-8 sequence + private static final byte C_CR1 = 1; //- 80..8F Continuation range 1 + private static final byte C_CR2 = 2; //- 90..9F Continuation range 2 + private static final byte C_CR3 = 3; //- A0..BF Continuation range 3 + private static final byte C_L2A = 4; //- C2..DF Leading byte range A / 2-byte sequence + private static final byte C_L3A = 5; //- E0 Leading byte range A / 3-byte sequence + private static final byte C_L3B = 6; //- E1..EC, EE..EF Leading byte range B / 3-byte sequence + private static final byte C_L3C = 7; //- ED Leading byte range C / 3-byte sequence + private static final byte C_L4A = 8; //- F0 Leading byte range A / 4-byte sequence + private static final byte C_L4B = 9; //- F1..F3 Leading byte range B / 4-byte sequence + private static final byte C_L4C = 10; //- F4 Leading byte range C / 4-byte sequence +// private static final byte C_ASC = 11; //- 00..7F ASCII leading byte range + + // Constants for the states of a DFA + private static final byte S_ERR = -2; //- Error state + private static final byte S_END = -1; //- End (or Accept) state + private static final byte S_CS1 = 0x00; //- Continuation state 1 + private static final byte S_CS2 = 0x10; //- Continuation state 2 + private static final byte S_CS3 = 0x20; //- Continuation state 3 + private static final byte S_P3A = 0x30; //- Partial 3-byte sequence state A + private static final byte S_P3B = 0x40; //- Partial 3-byte sequence state B + private static final byte S_P4A = 0x50; //- Partial 4-byte sequence state A + private static final byte S_P4B = 0x60; //- Partial 4-byte sequence state B + + private static final short[] firstUnitTable = new short[128]; + private static final byte[] transitionTable = new byte[S_P4B + 16]; + + private static void fill(byte[] table, int first, int last, byte b) + { + for (int i = first; i <= last; ++i) + { + table[i] = b; + } + } + + static + { + byte[] categories = new byte[128]; + fill(categories, 0x00, 0x0F, C_CR1); + fill(categories, 0x10, 0x1F, C_CR2); + fill(categories, 0x20, 0x3F, C_CR3); + fill(categories, 0x40, 0x41, C_ILL); + fill(categories, 0x42, 0x5F, C_L2A); + fill(categories, 0x60, 0x60, C_L3A); + fill(categories, 0x61, 0x6C, C_L3B); + fill(categories, 0x6D, 0x6D, C_L3C); + fill(categories, 0x6E, 0x6F, C_L3B); + fill(categories, 0x70, 0x70, C_L4A); + fill(categories, 0x71, 0x73, C_L4B); + fill(categories, 0x74, 0x74, C_L4C); + fill(categories, 0x75, 0x7F, C_ILL); + + fill(transitionTable, 0, transitionTable.length - 1, S_ERR); + fill(transitionTable, S_CS1 + 0x8, S_CS1 + 0xB, S_END); + fill(transitionTable, S_CS2 + 0x8, S_CS2 + 0xB, S_CS1); + fill(transitionTable, S_CS3 + 0x8, S_CS3 + 0xB, S_CS2); + fill(transitionTable, S_P3A + 0xA, S_P3A + 0xB, S_CS1); + fill(transitionTable, S_P3B + 0x8, S_P3B + 0x9, S_CS1); + fill(transitionTable, S_P4A + 0x9, S_P4A + 0xB, S_CS2); + fill(transitionTable, S_P4B + 0x8, S_P4B + 0x8, S_CS2); + + byte[] firstUnitMasks = { 0x00, 0x00, 0x00, 0x00, 0x1F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07 }; + byte[] firstUnitTransitions = { S_ERR, S_ERR, S_ERR, S_ERR, S_CS1, S_P3A, S_CS2, S_P3B, S_P4A, S_CS3, S_P4B }; + + for (int i = 0x00; i < 0x80; ++i) + { + byte category = categories[i]; + + int codePoint = i & firstUnitMasks[category]; + byte state = firstUnitTransitions[category]; + + firstUnitTable[i] = (short)((codePoint << 8) | state); + } + } + + /** + * Transcode a UTF-8 encoding into a UTF-16 representation. In the general case the output + * {@code utf16} array should be at least as long as the input {@code utf8} one to handle + * arbitrary inputs. The number of output UTF-16 code units is returned, or -1 if any errors are + * encountered (in which case an arbitrary amount of data may have been written into the output + * array). Errors that will be detected are malformed UTF-8, including incomplete, truncated or + * "overlong" encodings, and unmappable code points. In particular, no unmatched surrogates will + * be produced. An error will also result if {@code utf16} is found to be too small to store the + * complete output. + * + * @param utf8 + * A non-null array containing a well-formed UTF-8 encoding. + * @param utf16 + * A non-null array, at least as long as the {@code utf8} array in order to ensure + * the output will fit. + * @return The number of UTF-16 code units written to {@code utf16} (beginning from index 0), or + * else -1 if the input was either malformed or encoded any unmappable characters, or if + * the {@code utf16} is too small. + */ + public static int transcodeToUTF16(byte[] utf8, char[] utf16) + { + int i = 0, j = 0; + + while (i < utf8.length) + { + byte codeUnit = utf8[i++]; + if (codeUnit >= 0) + { + if (j >= utf16.length) { return -1; } + + utf16[j++] = (char)codeUnit; + continue; + } + + short first = firstUnitTable[codeUnit & 0x7F]; + int codePoint = first >>> 8; + byte state = (byte)first; + + while (state >= 0) + { + if (i >= utf8.length) { return -1; } + + codeUnit = utf8[i++]; + codePoint = (codePoint << 6) | (codeUnit & 0x3F); + state = transitionTable[state + ((codeUnit & 0xFF) >>> 4)]; + } + + if (state == S_ERR) { return -1; } + + if (codePoint <= 0xFFFF) + { + if (j >= utf16.length) { return -1; } + + // Code points from U+D800 to U+DFFF are caught by the DFA + utf16[j++] = (char)codePoint; + } + else + { + if (j >= utf16.length - 1) { return -1; } + + // Code points above U+10FFFF are caught by the DFA + utf16[j++] = (char)(0xD7C0 + (codePoint >>> 10)); + utf16[j++] = (char)(0xDC00 | (codePoint & 0x3FF)); + } + } + + return j; + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java index 3045b4d0..be9090d9 100644 --- a/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java +++ b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java @@ -22,6 +22,12 @@ public class PemReader super(reader); } + /** + * Read the next PEM object as a blob of raw data with header information. + * + * @return the next object in the stream, null if no objects left. + * @throws IOException in case of a parse error. + */ public PemObject readPemObject() throws IOException { diff --git a/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java b/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java index 952f7754..50a292b2 100644 --- a/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java +++ b/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java @@ -1,8 +1,5 @@ package org.bouncycastle.x509; -import org.bouncycastle.util.Selector; -import org.bouncycastle.util.Store; - import java.security.InvalidAlgorithmParameterException; import java.security.cert.CertSelector; import java.security.cert.CertStore; @@ -16,6 +13,9 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import org.bouncycastle.util.Selector; +import org.bouncycastle.util.Store; + /** * This class extends the PKIXParameters with a validity model parameter. * @@ -286,7 +286,7 @@ public class ExtendedPKIXParameters * * @param store The store to add. * @see #getStores() - * @deprectaed use addStore(). + * @deprecated use addStore(). */ public void addAdditionalStore(Store store) { diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java b/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java index 2486d208..63ed8ab0 100644 --- a/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java +++ b/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java @@ -7,7 +7,7 @@ import java.security.cert.X509CRL; import java.security.cert.X509CRLSelector; import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Selector; import org.bouncycastle.x509.extension.X509ExtensionUtil; @@ -100,7 +100,7 @@ public class X509CRLStoreSelector try { byte[] bytes = crl - .getExtensionValue(X509Extensions.DeltaCRLIndicator.getId()); + .getExtensionValue(Extension.deltaCRLIndicator.getId()); if (bytes != null) { dci = ASN1Integer.getInstance(X509ExtensionUtil @@ -139,7 +139,7 @@ public class X509CRLStoreSelector if (issuingDistributionPointEnabled) { byte[] idp = crl - .getExtensionValue(X509Extensions.IssuingDistributionPoint + .getExtensionValue(Extension.issuingDistributionPoint .getId()); if (issuingDistributionPoint == null) { diff --git a/bcprov/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java b/bcprov/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java index 2e4d14d3..0779d1aa 100644 --- a/bcprov/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java +++ b/bcprov/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java @@ -16,13 +16,19 @@ import org.bouncycastle.asn1.ASN1String; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.X509Extension; import org.bouncycastle.util.Integers; +/** + * @deprecated use org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils + */ public class X509ExtensionUtil { + /** + * @deprecated use org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils.parseExtensionValue() + */ public static ASN1Primitive fromExtensionValue( byte[] encodedValue) throws IOException @@ -32,18 +38,24 @@ public class X509ExtensionUtil return ASN1Primitive.fromByteArray(octs.getOctets()); } + /** + * @deprecated use org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils.getIssuerAlternativeNames() + */ public static Collection getIssuerAlternativeNames(X509Certificate cert) throws CertificateParsingException { - byte[] extVal = cert.getExtensionValue(X509Extension.issuerAlternativeName.getId()); + byte[] extVal = cert.getExtensionValue(Extension.issuerAlternativeName.getId()); return getAlternativeNames(extVal); } + /** + * @deprecated use org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils.getSubjectAlternativeNames() + */ public static Collection getSubjectAlternativeNames(X509Certificate cert) throws CertificateParsingException { - byte[] extVal = cert.getExtensionValue(X509Extension.subjectAlternativeName.getId()); + byte[] extVal = cert.getExtensionValue(Extension.subjectAlternativeName.getId()); return getAlternativeNames(extVal); } |