Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2013-11-26 10:36:34 +0400
committerDavid Hook <dgh@cryptoworkshop.com>2013-11-26 10:36:34 +0400
commit34305551ef1e15fa1dd42d6ffd6fde76495e4ae1 (patch)
treebf642fb72d40e80d92bf2d5bdbe09e46bc33147f /core/src/main/jdk1.1
parenteee8e20597c3d4c22908e1fa1cf380e6fbcb75be (diff)
updates
Diffstat (limited to 'core/src/main/jdk1.1')
-rw-r--r--core/src/main/jdk1.1/org/bouncycastle/asn1/x500/style/BCStyle.java481
-rw-r--r--core/src/main/jdk1.1/org/bouncycastle/asn1/x500/style/RFC4519Style.java380
-rw-r--r--core/src/main/jdk1.1/org/bouncycastle/crypto/digests/SkeinEngine.java817
-rw-r--r--core/src/main/jdk1.1/org/bouncycastle/crypto/engines/NullEngine.java96
-rw-r--r--core/src/main/jdk1.1/org/bouncycastle/crypto/signers/RSADigestSigner.java238
5 files changed, 2012 insertions, 0 deletions
diff --git a/core/src/main/jdk1.1/org/bouncycastle/asn1/x500/style/BCStyle.java b/core/src/main/jdk1.1/org/bouncycastle/asn1/x500/style/BCStyle.java
new file mode 100644
index 00000000..15e3c2a7
--- /dev/null
+++ b/core/src/main/jdk1.1/org/bouncycastle/asn1/x500/style/BCStyle.java
@@ -0,0 +1,481 @@
+package org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1GeneralizedTime;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERPrintableString;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.X500NameStyle;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+
+public class BCStyle
+ implements X500NameStyle
+{
+ /**
+ * country code - StringType(SIZE(2))
+ */
+ public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6");
+
+ /**
+ * organization - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10");
+
+ /**
+ * organizational unit name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11");
+
+ /**
+ * Title
+ */
+ public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12");
+
+ /**
+ * common name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3");
+
+ /**
+ * device serial number name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5");
+
+ /**
+ * street - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9");
+
+ /**
+ * device serial number name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier SERIALNUMBER = SN;
+
+ /**
+ * locality name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7");
+
+ /**
+ * state, or province name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8");
+
+ /**
+ * Naming attributes of type X520name
+ */
+ public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4");
+ public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42");
+ public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43");
+ public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44");
+ public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45");
+
+ /**
+ * businessCategory - DirectoryString(SIZE(1..128)
+ */
+ public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier(
+ "2.5.4.15");
+
+ /**
+ * postalCode - DirectoryString(SIZE(1..40)
+ */
+ public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier(
+ "2.5.4.17");
+
+ /**
+ * dnQualifier - DirectoryString(SIZE(1..64)
+ */
+ public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier(
+ "2.5.4.46");
+
+ /**
+ * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+ */
+ public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier(
+ "2.5.4.65");
+
+
+ /**
+ * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+ */
+ public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier(
+ "1.3.6.1.5.5.7.9.1");
+
+ /**
+ * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
+ */
+ public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier(
+ "1.3.6.1.5.5.7.9.2");
+
+ /**
+ * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
+ */
+ public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier(
+ "1.3.6.1.5.5.7.9.3");
+
+ /**
+ * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+ * codes only
+ */
+ public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier(
+ "1.3.6.1.5.5.7.9.4");
+
+ /**
+ * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166
+ * codes only
+ */
+ public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier(
+ "1.3.6.1.5.5.7.9.5");
+
+
+ /**
+ * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+ */
+ public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14");
+
+ /**
+ * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+ * DirectoryString(SIZE(1..30))
+ */
+ public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16");
+
+ /**
+ * RFC 2256 dmdName
+ */
+ public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54");
+
+ /**
+ * id-at-telephoneNumber
+ */
+ public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber;
+
+ /**
+ * id-at-name
+ */
+ public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name;
+
+ /**
+ * 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.
+ */
+ public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;
+
+ /**
+ * more from PKCS#9
+ */
+ public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;
+ public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;
+
+ /**
+ * email address in Verisign certificates
+ */
+ public static final ASN1ObjectIdentifier E = EmailAddress;
+
+ /*
+ * others...
+ */
+ public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25");
+
+ /**
+ * LDAP User id.
+ */
+ public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1");
+
+ /**
+ * default look up table translating OID values into their common symbols following
+ * the convention in RFC 2253 with a few extras
+ */
+ private static final Hashtable DefaultSymbols = new Hashtable();
+
+ /**
+ * look up table translating common symbols into their OIDS.
+ */
+ private static final Hashtable DefaultLookUp = new Hashtable();
+
+ static
+ {
+ DefaultSymbols.put(C, "C");
+ DefaultSymbols.put(O, "O");
+ DefaultSymbols.put(T, "T");
+ DefaultSymbols.put(OU, "OU");
+ DefaultSymbols.put(CN, "CN");
+ DefaultSymbols.put(L, "L");
+ DefaultSymbols.put(ST, "ST");
+ DefaultSymbols.put(SN, "SERIALNUMBER");
+ DefaultSymbols.put(EmailAddress, "E");
+ DefaultSymbols.put(DC, "DC");
+ DefaultSymbols.put(UID, "UID");
+ DefaultSymbols.put(STREET, "STREET");
+ DefaultSymbols.put(SURNAME, "SURNAME");
+ DefaultSymbols.put(GIVENNAME, "GIVENNAME");
+ DefaultSymbols.put(INITIALS, "INITIALS");
+ DefaultSymbols.put(GENERATION, "GENERATION");
+ DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress");
+ DefaultSymbols.put(UnstructuredName, "unstructuredName");
+ DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier");
+ DefaultSymbols.put(DN_QUALIFIER, "DN");
+ DefaultSymbols.put(PSEUDONYM, "Pseudonym");
+ DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress");
+ DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth");
+ DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship");
+ DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence");
+ DefaultSymbols.put(GENDER, "Gender");
+ DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth");
+ DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth");
+ DefaultSymbols.put(POSTAL_CODE, "PostalCode");
+ DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory");
+ DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber");
+ DefaultSymbols.put(NAME, "Name");
+
+ DefaultLookUp.put("c", C);
+ DefaultLookUp.put("o", O);
+ DefaultLookUp.put("t", T);
+ DefaultLookUp.put("ou", OU);
+ DefaultLookUp.put("cn", CN);
+ DefaultLookUp.put("l", L);
+ DefaultLookUp.put("st", ST);
+ DefaultLookUp.put("sn", SN);
+ DefaultLookUp.put("serialnumber", SN);
+ DefaultLookUp.put("street", STREET);
+ DefaultLookUp.put("emailaddress", E);
+ DefaultLookUp.put("dc", DC);
+ DefaultLookUp.put("e", E);
+ DefaultLookUp.put("uid", UID);
+ DefaultLookUp.put("surname", SURNAME);
+ DefaultLookUp.put("givenname", GIVENNAME);
+ DefaultLookUp.put("initials", INITIALS);
+ DefaultLookUp.put("generation", GENERATION);
+ DefaultLookUp.put("unstructuredaddress", UnstructuredAddress);
+ DefaultLookUp.put("unstructuredname", UnstructuredName);
+ DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER);
+ DefaultLookUp.put("dn", DN_QUALIFIER);
+ DefaultLookUp.put("pseudonym", PSEUDONYM);
+ DefaultLookUp.put("postaladdress", POSTAL_ADDRESS);
+ DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH);
+ DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP);
+ DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE);
+ DefaultLookUp.put("gender", GENDER);
+ DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH);
+ DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH);
+ DefaultLookUp.put("postalcode", POSTAL_CODE);
+ DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY);
+ DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER);
+ DefaultLookUp.put("name", NAME);
+ }
+
+ /**
+ * Singleton instance.
+ */
+ public static final X500NameStyle INSTANCE = new BCStyle();
+
+ protected Hashtable defaultLookUp;
+ protected Hashtable defaultSymbols;
+
+ protected BCStyle()
+ {
+ defaultSymbols = copyHashTable(DefaultSymbols);
+ defaultLookUp = copyHashTable(DefaultLookUp);
+ }
+
+ public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
+ {
+ if (value.length() != 0 && value.charAt(0) == '#')
+ {
+ try
+ {
+ return IETFUtils.valueFromHexString(value, 1);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("can't recode value for oid " + oid.getId());
+ }
+ }
+ else
+ {
+ if (value.length() != 0 && value.charAt(0) == '\\')
+ {
+ value = value.substring(1);
+ }
+ if (oid.equals(EmailAddress) || oid.equals(DC))
+ {
+ return new DERIA5String(value);
+ }
+ else if (oid.equals(DATE_OF_BIRTH)) // accept time string as well as # (for compatibility)
+ {
+ return new ASN1GeneralizedTime(value);
+ }
+ else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER)
+ || oid.equals(TELEPHONE_NUMBER))
+ {
+ return new DERPrintableString(value);
+ }
+ }
+
+ return new DERUTF8String(value);
+ }
+
+ public String oidToDisplayName(ASN1ObjectIdentifier oid)
+ {
+ return (String)DefaultSymbols.get(oid);
+ }
+
+ public String[] oidToAttrNames(ASN1ObjectIdentifier oid)
+ {
+ return IETFUtils.findAttrNamesForOID(oid, defaultLookUp);
+ }
+
+ public ASN1ObjectIdentifier attrNameToOID(String attrName)
+ {
+ return IETFUtils.decodeAttrName(attrName, defaultLookUp);
+ }
+
+ public boolean areEqual(X500Name name1, X500Name name2)
+ {
+ RDN[] rdns1 = name1.getRDNs();
+ RDN[] rdns2 = name2.getRDNs();
+
+ if (rdns1.length != rdns2.length)
+ {
+ return false;
+ }
+
+ boolean reverse = false;
+
+ if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null)
+ {
+ reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward
+ }
+
+ for (int i = 0; i != rdns1.length; i++)
+ {
+ if (!foundMatch(reverse, rdns1[i], rdns2))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs)
+ {
+ if (reverse)
+ {
+ for (int i = possRDNs.length - 1; i >= 0; i--)
+ {
+ if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
+ {
+ possRDNs[i] = null;
+ return true;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i != possRDNs.length; i++)
+ {
+ if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
+ {
+ possRDNs[i] = null;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected boolean rdnAreEqual(RDN rdn1, RDN rdn2)
+ {
+ return IETFUtils.rDNAreEqual(rdn1, rdn2);
+ }
+
+ public RDN[] fromString(String dirName)
+ {
+ return IETFUtils.rDNsFromString(dirName, this);
+ }
+
+ public int calculateHashCode(X500Name name)
+ {
+ int hashCodeValue = 0;
+ RDN[] rdns = name.getRDNs();
+
+ // this needs to be order independent, like equals
+ for (int i = 0; i != rdns.length; i++)
+ {
+ if (rdns[i].isMultiValued())
+ {
+ AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
+
+ for (int j = 0; j != atv.length; j++)
+ {
+ hashCodeValue ^= atv[j].getType().hashCode();
+ hashCodeValue ^= calcHashCode(atv[j].getValue());
+ }
+ }
+ else
+ {
+ hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
+ hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
+ }
+ }
+
+ return hashCodeValue;
+ }
+
+ private int calcHashCode(ASN1Encodable enc)
+ {
+ String value = IETFUtils.valueToString(enc);
+
+ value = IETFUtils.canonicalize(value);
+
+ return value.hashCode();
+ }
+
+ public String toString(X500Name name)
+ {
+ StringBuffer buf = new StringBuffer();
+ boolean first = true;
+
+ RDN[] rdns = name.getRDNs();
+
+ for (int i = 0; i < rdns.length; i++)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append(',');
+ }
+
+ IETFUtils.appendRDN(buf, rdns[i], defaultSymbols);
+ }
+
+ return buf.toString();
+ }
+
+ private static Hashtable copyHashTable(Hashtable paramsMap)
+ {
+ Hashtable newTable = new Hashtable();
+
+ Enumeration keys = paramsMap.keys();
+ while (keys.hasMoreElements())
+ {
+ Object key = keys.nextElement();
+ newTable.put(key, paramsMap.get(key));
+ }
+
+ return newTable;
+ }
+}
diff --git a/core/src/main/jdk1.1/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/core/src/main/jdk1.1/org/bouncycastle/asn1/x500/style/RFC4519Style.java
new file mode 100644
index 00000000..e5ff6a11
--- /dev/null
+++ b/core/src/main/jdk1.1/org/bouncycastle/asn1/x500/style/RFC4519Style.java
@@ -0,0 +1,380 @@
+package org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERPrintableString;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.X500NameStyle;
+
+public class RFC4519Style
+ implements X500NameStyle
+{
+ public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15");
+ public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6");
+ public static final ASN1ObjectIdentifier cn = new ASN1ObjectIdentifier("2.5.4.3");
+ public static final ASN1ObjectIdentifier dc = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25");
+ public static final ASN1ObjectIdentifier description = new ASN1ObjectIdentifier("2.5.4.13");
+ public static final ASN1ObjectIdentifier destinationIndicator = new ASN1ObjectIdentifier("2.5.4.27");
+ public static final ASN1ObjectIdentifier distinguishedName = new ASN1ObjectIdentifier("2.5.4.49");
+ public static final ASN1ObjectIdentifier dnQualifier = new ASN1ObjectIdentifier("2.5.4.46");
+ public static final ASN1ObjectIdentifier enhancedSearchGuide = new ASN1ObjectIdentifier("2.5.4.47");
+ public static final ASN1ObjectIdentifier facsimileTelephoneNumber = new ASN1ObjectIdentifier("2.5.4.23");
+ public static final ASN1ObjectIdentifier generationQualifier = new ASN1ObjectIdentifier("2.5.4.44");
+ public static final ASN1ObjectIdentifier givenName = new ASN1ObjectIdentifier("2.5.4.42");
+ public static final ASN1ObjectIdentifier houseIdentifier = new ASN1ObjectIdentifier("2.5.4.51");
+ public static final ASN1ObjectIdentifier initials = new ASN1ObjectIdentifier("2.5.4.43");
+ public static final ASN1ObjectIdentifier internationalISDNNumber = new ASN1ObjectIdentifier("2.5.4.25");
+ public static final ASN1ObjectIdentifier l = new ASN1ObjectIdentifier("2.5.4.7");
+ public static final ASN1ObjectIdentifier member = new ASN1ObjectIdentifier("2.5.4.31");
+ public static final ASN1ObjectIdentifier name = new ASN1ObjectIdentifier("2.5.4.41");
+ public static final ASN1ObjectIdentifier o = new ASN1ObjectIdentifier("2.5.4.10");
+ public static final ASN1ObjectIdentifier ou = new ASN1ObjectIdentifier("2.5.4.11");
+ public static final ASN1ObjectIdentifier owner = new ASN1ObjectIdentifier("2.5.4.32");
+ public static final ASN1ObjectIdentifier physicalDeliveryOfficeName = new ASN1ObjectIdentifier("2.5.4.19");
+ public static final ASN1ObjectIdentifier postalAddress = new ASN1ObjectIdentifier("2.5.4.16");
+ public static final ASN1ObjectIdentifier postalCode = new ASN1ObjectIdentifier("2.5.4.17");
+ public static final ASN1ObjectIdentifier postOfficeBox = new ASN1ObjectIdentifier("2.5.4.18");
+ public static final ASN1ObjectIdentifier preferredDeliveryMethod = new ASN1ObjectIdentifier("2.5.4.28");
+ public static final ASN1ObjectIdentifier registeredAddress = new ASN1ObjectIdentifier("2.5.4.26");
+ public static final ASN1ObjectIdentifier roleOccupant = new ASN1ObjectIdentifier("2.5.4.33");
+ public static final ASN1ObjectIdentifier searchGuide = new ASN1ObjectIdentifier("2.5.4.14");
+ public static final ASN1ObjectIdentifier seeAlso = new ASN1ObjectIdentifier("2.5.4.34");
+ public static final ASN1ObjectIdentifier serialNumber = new ASN1ObjectIdentifier("2.5.4.5");
+ public static final ASN1ObjectIdentifier sn = new ASN1ObjectIdentifier("2.5.4.4");
+ public static final ASN1ObjectIdentifier st = new ASN1ObjectIdentifier("2.5.4.8");
+ public static final ASN1ObjectIdentifier street = new ASN1ObjectIdentifier("2.5.4.9");
+ public static final ASN1ObjectIdentifier telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20");
+ public static final ASN1ObjectIdentifier teletexTerminalIdentifier = new ASN1ObjectIdentifier("2.5.4.22");
+ public static final ASN1ObjectIdentifier telexNumber = new ASN1ObjectIdentifier("2.5.4.21");
+ public static final ASN1ObjectIdentifier title = new ASN1ObjectIdentifier("2.5.4.12");
+ public static final ASN1ObjectIdentifier uid = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1");
+ public static final ASN1ObjectIdentifier uniqueMember = new ASN1ObjectIdentifier("2.5.4.50");
+ public static final ASN1ObjectIdentifier userPassword = new ASN1ObjectIdentifier("2.5.4.35");
+ public static final ASN1ObjectIdentifier x121Address = new ASN1ObjectIdentifier("2.5.4.24");
+ public static final ASN1ObjectIdentifier x500UniqueIdentifier = new ASN1ObjectIdentifier("2.5.4.45");
+
+ /**
+ * default look up table translating OID values into their common symbols following
+ * the convention in RFC 2253 with a few extras
+ */
+ private static final Hashtable DefaultSymbols = new Hashtable();
+
+ /**
+ * look up table translating common symbols into their OIDS.
+ */
+ private static final Hashtable DefaultLookUp = new Hashtable();
+
+ static
+ {
+ DefaultSymbols.put(businessCategory, "businessCategory");
+ DefaultSymbols.put(c, "c");
+ DefaultSymbols.put(cn, "cn");
+ DefaultSymbols.put(dc, "dc");
+ DefaultSymbols.put(description, "description");
+ DefaultSymbols.put(destinationIndicator, "destinationIndicator");
+ DefaultSymbols.put(distinguishedName, "distinguishedName");
+ DefaultSymbols.put(dnQualifier, "dnQualifier");
+ DefaultSymbols.put(enhancedSearchGuide, "enhancedSearchGuide");
+ DefaultSymbols.put(facsimileTelephoneNumber, "facsimileTelephoneNumber");
+ DefaultSymbols.put(generationQualifier, "generationQualifier");
+ DefaultSymbols.put(givenName, "givenName");
+ DefaultSymbols.put(houseIdentifier, "houseIdentifier");
+ DefaultSymbols.put(initials, "initials");
+ DefaultSymbols.put(internationalISDNNumber, "internationalISDNNumber");
+ DefaultSymbols.put(l, "l");
+ DefaultSymbols.put(member, "member");
+ DefaultSymbols.put(name, "name");
+ DefaultSymbols.put(o, "o");
+ DefaultSymbols.put(ou, "ou");
+ DefaultSymbols.put(owner, "owner");
+ DefaultSymbols.put(physicalDeliveryOfficeName, "physicalDeliveryOfficeName");
+ DefaultSymbols.put(postalAddress, "postalAddress");
+ DefaultSymbols.put(postalCode, "postalCode");
+ DefaultSymbols.put(postOfficeBox, "postOfficeBox");
+ DefaultSymbols.put(preferredDeliveryMethod, "preferredDeliveryMethod");
+ DefaultSymbols.put(registeredAddress, "registeredAddress");
+ DefaultSymbols.put(roleOccupant, "roleOccupant");
+ DefaultSymbols.put(searchGuide, "searchGuide");
+ DefaultSymbols.put(seeAlso, "seeAlso");
+ DefaultSymbols.put(serialNumber, "serialNumber");
+ DefaultSymbols.put(sn, "sn");
+ DefaultSymbols.put(st, "st");
+ DefaultSymbols.put(street, "street");
+ DefaultSymbols.put(telephoneNumber, "telephoneNumber");
+ DefaultSymbols.put(teletexTerminalIdentifier, "teletexTerminalIdentifier");
+ DefaultSymbols.put(telexNumber, "telexNumber");
+ DefaultSymbols.put(title, "title");
+ DefaultSymbols.put(uid, "uid");
+ DefaultSymbols.put(uniqueMember, "uniqueMember");
+ DefaultSymbols.put(userPassword, "userPassword");
+ DefaultSymbols.put(x121Address, "x121Address");
+ DefaultSymbols.put(x500UniqueIdentifier, "x500UniqueIdentifier");
+
+ DefaultLookUp.put("businesscategory", businessCategory);
+ DefaultLookUp.put("c", c);
+ DefaultLookUp.put("cn", cn);
+ DefaultLookUp.put("dc", dc);
+ DefaultLookUp.put("description", description);
+ DefaultLookUp.put("destinationindicator", destinationIndicator);
+ DefaultLookUp.put("distinguishedname", distinguishedName);
+ DefaultLookUp.put("dnqualifier", dnQualifier);
+ DefaultLookUp.put("enhancedsearchguide", enhancedSearchGuide);
+ DefaultLookUp.put("facsimiletelephonenumber", facsimileTelephoneNumber);
+ DefaultLookUp.put("generationqualifier", generationQualifier);
+ DefaultLookUp.put("givenname", givenName);
+ DefaultLookUp.put("houseidentifier", houseIdentifier);
+ DefaultLookUp.put("initials", initials);
+ DefaultLookUp.put("internationalisdnnumber", internationalISDNNumber);
+ DefaultLookUp.put("l", l);
+ DefaultLookUp.put("member", member);
+ DefaultLookUp.put("name", name);
+ DefaultLookUp.put("o", o);
+ DefaultLookUp.put("ou", ou);
+ DefaultLookUp.put("owner", owner);
+ DefaultLookUp.put("physicaldeliveryofficename", physicalDeliveryOfficeName);
+ DefaultLookUp.put("postaladdress", postalAddress);
+ DefaultLookUp.put("postalcode", postalCode);
+ DefaultLookUp.put("postofficebox", postOfficeBox);
+ DefaultLookUp.put("preferreddeliverymethod", preferredDeliveryMethod);
+ DefaultLookUp.put("registeredaddress", registeredAddress);
+ DefaultLookUp.put("roleoccupant", roleOccupant);
+ DefaultLookUp.put("searchguide", searchGuide);
+ DefaultLookUp.put("seealso", seeAlso);
+ DefaultLookUp.put("serialnumber", serialNumber);
+ DefaultLookUp.put("sn", sn);
+ DefaultLookUp.put("st", st);
+ DefaultLookUp.put("street", street);
+ DefaultLookUp.put("telephonenumber", telephoneNumber);
+ DefaultLookUp.put("teletexterminalidentifier", teletexTerminalIdentifier);
+ DefaultLookUp.put("telexnumber", telexNumber);
+ DefaultLookUp.put("title", title);
+ DefaultLookUp.put("uid", uid);
+ DefaultLookUp.put("uniquemember", uniqueMember);
+ DefaultLookUp.put("userpassword", userPassword);
+ DefaultLookUp.put("x121address", x121Address);
+ DefaultLookUp.put("x500uniqueidentifier", x500UniqueIdentifier);
+
+ // TODO: need to add correct matching for equality comparisons.
+ }
+
+ /**
+ * Singleton instance.
+ */
+ public static final X500NameStyle INSTANCE = new RFC4519Style();
+
+ protected Hashtable defaultLookUp;
+ protected Hashtable defaultSymbols;
+
+ protected RFC4519Style()
+ {
+ defaultSymbols = copyHashTable(DefaultSymbols);
+ defaultLookUp = copyHashTable(DefaultLookUp);
+ }
+
+ public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
+ {
+ if (value.length() != 0 && value.charAt(0) == '#')
+ {
+ try
+ {
+ return IETFUtils.valueFromHexString(value, 1);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("can't recode value for oid " + oid.getId());
+ }
+ }
+ else
+ {
+ if (value.length() != 0 && value.charAt(0) == '\\')
+ {
+ value = value.substring(1);
+ }
+ if (oid.equals(dc))
+ {
+ return new DERIA5String(value);
+ }
+ else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier)
+ || oid.equals(telephoneNumber))
+ {
+ return new DERPrintableString(value);
+ }
+ }
+
+ return new DERUTF8String(value);
+ }
+
+ public String oidToDisplayName(ASN1ObjectIdentifier oid)
+ {
+ return (String)DefaultSymbols.get(oid);
+ }
+
+ public String[] oidToAttrNames(ASN1ObjectIdentifier oid)
+ {
+ return IETFUtils.findAttrNamesForOID(oid, defaultLookUp);
+ }
+
+ public ASN1ObjectIdentifier attrNameToOID(String attrName)
+ {
+ return IETFUtils.decodeAttrName(attrName, defaultLookUp);
+ }
+
+ public boolean areEqual(X500Name name1, X500Name name2)
+ {
+ RDN[] rdns1 = name1.getRDNs();
+ RDN[] rdns2 = name2.getRDNs();
+
+ if (rdns1.length != rdns2.length)
+ {
+ return false;
+ }
+
+ boolean reverse = false;
+
+ if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null)
+ {
+ reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward
+ }
+
+ for (int i = 0; i != rdns1.length; i++)
+ {
+ if (!foundMatch(reverse, rdns1[i], rdns2))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs)
+ {
+ if (reverse)
+ {
+ for (int i = possRDNs.length - 1; i >= 0; i--)
+ {
+ if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
+ {
+ possRDNs[i] = null;
+ return true;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i != possRDNs.length; i++)
+ {
+ if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
+ {
+ possRDNs[i] = null;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected boolean rdnAreEqual(RDN rdn1, RDN rdn2)
+ {
+ return IETFUtils.rDNAreEqual(rdn1, rdn2);
+ }
+
+ // parse backwards
+ public RDN[] fromString(String dirName)
+ {
+ RDN[] tmp = IETFUtils.rDNsFromString(dirName, this);
+ RDN[] res = new RDN[tmp.length];
+
+ for (int i = 0; i != tmp.length; i++)
+ {
+ res[res.length - i - 1] = tmp[i];
+ }
+
+ return res;
+ }
+
+ public int calculateHashCode(X500Name name)
+ {
+ int hashCodeValue = 0;
+ RDN[] rdns = name.getRDNs();
+
+ // this needs to be order independent, like equals
+ for (int i = 0; i != rdns.length; i++)
+ {
+ if (rdns[i].isMultiValued())
+ {
+ AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
+
+ for (int j = 0; j != atv.length; j++)
+ {
+ hashCodeValue ^= atv[j].getType().hashCode();
+ hashCodeValue ^= calcHashCode(atv[j].getValue());
+ }
+ }
+ else
+ {
+ hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
+ hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
+ }
+ }
+
+ return hashCodeValue;
+ }
+
+ private int calcHashCode(ASN1Encodable enc)
+ {
+ String value = IETFUtils.valueToString(enc);
+
+ value = IETFUtils.canonicalize(value);
+
+ return value.hashCode();
+ }
+
+ // convert in reverse
+ public String toString(X500Name name)
+ {
+ StringBuffer buf = new StringBuffer();
+ boolean first = true;
+
+ RDN[] rdns = name.getRDNs();
+
+ for (int i = rdns.length - 1; i >= 0; i--)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append(',');
+ }
+
+ IETFUtils.appendRDN(buf, rdns[i], defaultSymbols);
+ }
+
+ return buf.toString();
+ }
+
+ private static Hashtable copyHashTable(Hashtable paramsMap)
+ {
+ Hashtable newTable = new Hashtable();
+
+ Enumeration keys = paramsMap.keys();
+ while (keys.hasMoreElements())
+ {
+ Object key = keys.nextElement();
+ newTable.put(key, paramsMap.get(key));
+ }
+
+ return newTable;
+ }
+}
diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/digests/SkeinEngine.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/digests/SkeinEngine.java
new file mode 100644
index 00000000..5bfee7e6
--- /dev/null
+++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/digests/SkeinEngine.java
@@ -0,0 +1,817 @@
+package org.bouncycastle.crypto.digests;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.engines.ThreefishEngine;
+import org.bouncycastle.crypto.macs.SkeinMac;
+import org.bouncycastle.crypto.params.SkeinParameters;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Memoable;
+
+/**
+ * Implementation of the Skein family of parameterised hash functions in 256, 512 and 1024 bit block
+ * sizes, based on the {@link ThreefishEngine Threefish} tweakable block cipher.
+ * <p/>
+ * This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3
+ * competition in October 2010.
+ * <p/>
+ * Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+ * Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+ * <p/>
+ * This implementation is the basis for {@link SkeinDigest} and {@link SkeinMac}, implementing the
+ * parameter based configuration system that allows Skein to be adapted to multiple applications. <br>
+ * Initialising the engine with {@link SkeinParameters} allows standard and arbitrary parameters to
+ * be applied during the Skein hash function.
+ * <p/>
+ * Implemented:
+ * <ul>
+ * <li>256, 512 and 1024 bit internal states.</li>
+ * <li>Full 96 bit input length.</li>
+ * <li>Parameters defined in the Skein specification, and arbitrary other pre and post message
+ * parameters.</li>
+ * <li>Arbitrary output size in 1 byte intervals.</li>
+ * </ul>
+ * <p/>
+ * Not implemented:
+ * <ul>
+ * <li>Sub-byte length input (bit padding).</li>
+ * <li>Tree hashing.</li>
+ * </ul>
+ *
+ * @see SkeinParameters
+ */
+public class SkeinEngine
+ implements Memoable
+{
+ /**
+ * 256 bit block size - Skein 256
+ */
+ public static final int SKEIN_256 = ThreefishEngine.BLOCKSIZE_256;
+ /**
+ * 512 bit block size - Skein 512
+ */
+ public static final int SKEIN_512 = ThreefishEngine.BLOCKSIZE_512;
+ /**
+ * 1024 bit block size - Skein 1024
+ */
+ public static final int SKEIN_1024 = ThreefishEngine.BLOCKSIZE_1024;
+
+ // Minimal at present, but more complex when tree hashing is implemented
+ private static class Configuration
+ {
+ private byte[] bytes = new byte[32];
+
+ public Configuration(long outputSizeBits)
+ {
+ // 0..3 = ASCII SHA3
+ bytes[0] = (byte)'S';
+ bytes[1] = (byte)'H';
+ bytes[2] = (byte)'A';
+ bytes[3] = (byte)'3';
+
+ // 4..5 = version number in LSB order
+ bytes[4] = 1;
+ bytes[5] = 0;
+
+ // 8..15 = output length
+ ThreefishEngine.wordToBytes(outputSizeBits, bytes, 8);
+ }
+
+ public byte[] getBytes()
+ {
+ return bytes;
+ }
+
+ }
+
+ public static class Parameter
+ {
+ private int type;
+ private byte[] value;
+
+ public Parameter(int type, byte[] value)
+ {
+ this.type = type;
+ this.value = value;
+ }
+
+ public int getType()
+ {
+ return type;
+ }
+
+ public byte[] getValue()
+ {
+ return value;
+ }
+
+ }
+
+ /**
+ * The parameter type for the Skein key.
+ */
+ private static final int PARAM_TYPE_KEY = 0;
+
+ /**
+ * The parameter type for the Skein configuration block.
+ */
+ private static final int PARAM_TYPE_CONFIG = 4;
+
+ /**
+ * The parameter type for the message.
+ */
+ private static final int PARAM_TYPE_MESSAGE = 48;
+
+ /**
+ * The parameter type for the output transformation.
+ */
+ private static final int PARAM_TYPE_OUTPUT = 63;
+
+ /**
+ * Precalculated UBI(CFG) states for common state/output combinations without key or other
+ * pre-message params.
+ */
+ private static final Hashtable INITIAL_STATES = new Hashtable();
+
+ static
+ {
+ // From Appendix C of the Skein 1.3 NIST submission
+ initialState(SKEIN_256, 128, new long[]{
+ 0xe1111906964d7260L,
+ 0x883daaa77c8d811cL,
+ 0x10080df491960f7aL,
+ 0xccf7dde5b45bc1c2L});
+
+ initialState(SKEIN_256, 160, new long[]{
+ 0x1420231472825e98L,
+ 0x2ac4e9a25a77e590L,
+ 0xd47a58568838d63eL,
+ 0x2dd2e4968586ab7dL});
+
+ initialState(SKEIN_256, 224, new long[]{
+ 0xc6098a8c9ae5ea0bL,
+ 0x876d568608c5191cL,
+ 0x99cb88d7d7f53884L,
+ 0x384bddb1aeddb5deL});
+
+ initialState(SKEIN_256, 256, new long[]{
+ 0xfc9da860d048b449L,
+ 0x2fca66479fa7d833L,
+ 0xb33bc3896656840fL,
+ 0x6a54e920fde8da69L});
+
+ initialState(SKEIN_512, 128, new long[]{
+ 0xa8bc7bf36fbf9f52L,
+ 0x1e9872cebd1af0aaL,
+ 0x309b1790b32190d3L,
+ 0xbcfbb8543f94805cL,
+ 0x0da61bcd6e31b11bL,
+ 0x1a18ebead46a32e3L,
+ 0xa2cc5b18ce84aa82L,
+ 0x6982ab289d46982dL});
+
+ initialState(SKEIN_512, 160, new long[]{
+ 0x28b81a2ae013bd91L,
+ 0xc2f11668b5bdf78fL,
+ 0x1760d8f3f6a56f12L,
+ 0x4fb747588239904fL,
+ 0x21ede07f7eaf5056L,
+ 0xd908922e63ed70b8L,
+ 0xb8ec76ffeccb52faL,
+ 0x01a47bb8a3f27a6eL});
+
+ initialState(SKEIN_512, 224, new long[]{
+ 0xccd0616248677224L,
+ 0xcba65cf3a92339efL,
+ 0x8ccd69d652ff4b64L,
+ 0x398aed7b3ab890b4L,
+ 0x0f59d1b1457d2bd0L,
+ 0x6776fe6575d4eb3dL,
+ 0x99fbc70e997413e9L,
+ 0x9e2cfccfe1c41ef7L});
+
+ initialState(SKEIN_512, 384, new long[]{
+ 0xa3f6c6bf3a75ef5fL,
+ 0xb0fef9ccfd84faa4L,
+ 0x9d77dd663d770cfeL,
+ 0xd798cbf3b468fddaL,
+ 0x1bc4a6668a0e4465L,
+ 0x7ed7d434e5807407L,
+ 0x548fc1acd4ec44d6L,
+ 0x266e17546aa18ff8L});
+
+ initialState(SKEIN_512, 512, new long[]{
+ 0x4903adff749c51ceL,
+ 0x0d95de399746df03L,
+ 0x8fd1934127c79bceL,
+ 0x9a255629ff352cb1L,
+ 0x5db62599df6ca7b0L,
+ 0xeabe394ca9d5c3f4L,
+ 0x991112c71a75b523L,
+ 0xae18a40b660fcc33L});
+ }
+
+ private static void initialState(int blockSize, int outputSize, long[] state)
+ {
+ INITIAL_STATES.put(variantIdentifier(blockSize / 8, outputSize / 8), state);
+ }
+
+ private static Integer variantIdentifier(int blockSizeBytes, int outputSizeBytes)
+ {
+ return new Integer((outputSizeBytes << 16) | blockSizeBytes);
+ }
+
+ private static class UbiTweak
+ {
+ /**
+ * Point at which position might overflow long, so switch to add with carry logic
+ */
+ private static final long LOW_RANGE = Long.MAX_VALUE - Integer.MAX_VALUE;
+
+ /**
+ * Bit 127 = final
+ */
+ private static final long T1_FINAL = 1L << 63;
+
+ /**
+ * Bit 126 = first
+ */
+ private static final long T1_FIRST = 1L << 62;
+
+ /**
+ * UBI uses a 128 bit tweak
+ */
+ private long tweak[] = new long[2];
+
+ /**
+ * Whether 64 bit position exceeded
+ */
+ private boolean extendedPosition;
+
+ public UbiTweak()
+ {
+ reset();
+ }
+
+ public void reset(UbiTweak tweak)
+ {
+ this.tweak = Arrays.clone(tweak.tweak, this.tweak);
+ this.extendedPosition = tweak.extendedPosition;
+ }
+
+ public void reset()
+ {
+ tweak[0] = 0;
+ tweak[1] = 0;
+ extendedPosition = false;
+ setFirst(true);
+ }
+
+ public void setType(int type)
+ {
+ // Bits 120..125 = type
+ tweak[1] = (tweak[1] & 0xFFFFFFC000000000L) | ((type & 0x3FL) << 56);
+ }
+
+ public int getType()
+ {
+ return (int)((tweak[1] >>> 56) & 0x3FL);
+ }
+
+ public void setFirst(boolean first)
+ {
+ if (first)
+ {
+ tweak[1] |= T1_FIRST;
+ }
+ else
+ {
+ tweak[1] &= ~T1_FIRST;
+ }
+ }
+
+ public boolean isFirst()
+ {
+ return ((tweak[1] & T1_FIRST) != 0);
+ }
+
+ public void setFinal(boolean last)
+ {
+ if (last)
+ {
+ tweak[1] |= T1_FINAL;
+ }
+ else
+ {
+ tweak[1] &= ~T1_FINAL;
+ }
+ }
+
+ public boolean isFinal()
+ {
+ return ((tweak[1] & T1_FINAL) != 0);
+ }
+
+ /**
+ * Advances the position in the tweak by the specified value.
+ */
+ public void advancePosition(int advance)
+ {
+ // Bits 0..95 = position
+ if (extendedPosition)
+ {
+ long[] parts = new long[3];
+ parts[0] = tweak[0] & 0xFFFFFFFFL;
+ parts[1] = (tweak[0] >>> 32) & 0xFFFFFFFFL;
+ parts[2] = tweak[1] & 0xFFFFFFFFL;
+
+ long carry = advance;
+ for (int i = 0; i < parts.length; i++)
+ {
+ carry += parts[i];
+ parts[i] = carry;
+ carry >>>= 32;
+ }
+ tweak[0] = ((parts[1] & 0xFFFFFFFFL) << 32) | (parts[0] & 0xFFFFFFFFL);
+ tweak[1] = (tweak[1] & 0xFFFFFFFF00000000L) | (parts[2] & 0xFFFFFFFFL);
+ }
+ else
+ {
+ long position = tweak[0];
+ position += advance;
+ tweak[0] = position;
+ if (position > LOW_RANGE)
+ {
+ extendedPosition = true;
+ }
+ }
+ }
+
+ public long[] getWords()
+ {
+ return tweak;
+ }
+
+ public String toString()
+ {
+ return getType() + " first: " + isFirst() + ", final: " + isFinal();
+ }
+
+ }
+
+ /**
+ * The Unique Block Iteration chaining mode.
+ */
+ // TODO: This might be better as methods...
+ private class UBI
+ {
+ private final UbiTweak tweak = new UbiTweak();
+
+ /**
+ * Buffer for the current block of message data
+ */
+ private byte[] currentBlock;
+
+ /**
+ * Offset into the current message block
+ */
+ private int currentOffset;
+
+ /**
+ * Buffer for message words for feedback into encrypted block
+ */
+ private long[] message;
+
+ public UBI(int blockSize)
+ {
+ currentBlock = new byte[blockSize];
+ message = new long[currentBlock.length / 8];
+ }
+
+ public void reset(UBI ubi)
+ {
+ currentBlock = Arrays.clone(ubi.currentBlock, currentBlock);
+ currentOffset = ubi.currentOffset;
+ message = Arrays.clone(ubi.message, this.message);
+ tweak.reset(ubi.tweak);
+ }
+
+ public void reset(int type)
+ {
+ tweak.reset();
+ tweak.setType(type);
+ currentOffset = 0;
+ }
+
+ public void update(byte[] value, int offset, int len, long[] output)
+ {
+ /*
+ * Buffer complete blocks for the underlying Threefish cipher, only flushing when there
+ * are subsequent bytes (last block must be processed in doFinal() with final=true set).
+ */
+ int copied = 0;
+ while (len > copied)
+ {
+ if (currentOffset == currentBlock.length)
+ {
+ processBlock(output);
+ tweak.setFirst(false);
+ currentOffset = 0;
+ }
+
+ int toCopy = Math.min((len - copied), currentBlock.length - currentOffset);
+ System.arraycopy(value, offset + copied, currentBlock, currentOffset, toCopy);
+ copied += toCopy;
+ currentOffset += toCopy;
+ tweak.advancePosition(toCopy);
+ }
+ }
+
+ private void processBlock(long[] output)
+ {
+ threefish.init(true, chain, tweak.getWords());
+ for (int i = 0; i < message.length; i++)
+ {
+ message[i] = ThreefishEngine.bytesToWord(currentBlock, i * 8);
+ }
+
+ threefish.processBlock(message, output);
+
+ for (int i = 0; i < output.length; i++)
+ {
+ output[i] ^= message[i];
+ }
+ }
+
+ public void doFinal(long[] output)
+ {
+ // Pad remainder of current block with zeroes
+ for (int i = currentOffset; i < currentBlock.length; i++)
+ {
+ currentBlock[i] = 0;
+ }
+
+ tweak.setFinal(true);
+ processBlock(output);
+ }
+
+ }
+
+ /**
+ * Underlying Threefish tweakable block cipher
+ */
+ private ThreefishEngine threefish;
+
+ /**
+ * Size of the digest output, in bytes
+ */
+ private int outputSizeBytes;
+
+ /**
+ * The current chaining/state value
+ */
+ long[] chain;
+
+ /**
+ * The initial state value
+ */
+ private long[] initialState;
+
+ /**
+ * The (optional) key parameter
+ */
+ private byte[] key;
+
+ /**
+ * Parameters to apply prior to the message
+ */
+ private Parameter[] preMessageParameters;
+
+ /**
+ * Parameters to apply after the message, but prior to output
+ */
+ private Parameter[] postMessageParameters;
+
+ /**
+ * The current UBI operation
+ */
+ private UBI ubi;
+
+ /**
+ * Buffer for single byte update method
+ */
+ private final byte[] singleByte = new byte[1];
+
+ /**
+ * Constructs a Skein engine.
+ *
+ * @param blockSizeBits the internal state size in bits - one of {@link #SKEIN_256}, {@link #SKEIN_512} or
+ * {@link #SKEIN_1024}.
+ * @param outputSizeBits the output/digest size to produce in bits, which must be an integral number of
+ * bytes.
+ */
+ public SkeinEngine(int blockSizeBits, int outputSizeBits)
+ {
+ if (outputSizeBits % 8 != 0)
+ {
+ throw new IllegalArgumentException("Output size must be a multiple of 8 bits. :" + outputSizeBits);
+ }
+ // TODO: Prevent digest sizes > block size?
+ this.outputSizeBytes = outputSizeBits / 8;
+
+ this.threefish = new ThreefishEngine(blockSizeBits);
+ this.ubi = new UBI(threefish.getBlockSize());
+ }
+
+ /**
+ * Creates a SkeinEngine as an exact copy of an existing instance.
+ */
+ public SkeinEngine(SkeinEngine engine)
+ {
+ this(engine.getBlockSize() * 8, engine.getOutputSize() * 8);
+ copyIn(engine);
+ }
+
+ private void copyIn(SkeinEngine engine)
+ {
+ this.ubi.reset(engine.ubi);
+ this.chain = Arrays.clone(engine.chain, this.chain);
+ this.initialState = Arrays.clone(engine.initialState, this.initialState);
+ this.key = Arrays.clone(engine.key, this.key);
+ this.preMessageParameters = clone(engine.preMessageParameters, this.preMessageParameters);
+ this.postMessageParameters = clone(engine.postMessageParameters, this.postMessageParameters);
+ }
+
+ private static Parameter[] clone(Parameter[] data, Parameter[] existing)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ if ((existing == null) || (existing.length != data.length))
+ {
+ existing = new Parameter[data.length];
+ }
+ System.arraycopy(data, 0, existing, 0, existing.length);
+ return existing;
+ }
+
+ public Memoable copy()
+ {
+ return new SkeinEngine(this);
+ }
+
+ public void reset(Memoable other)
+ {
+ SkeinEngine s = (SkeinEngine)other;
+ if ((getBlockSize() != s.getBlockSize()) || (outputSizeBytes != s.outputSizeBytes))
+ {
+ throw new IllegalArgumentException("Incompatible parameters in provided SkeinEngine.");
+ }
+ copyIn(s);
+ }
+
+ public int getOutputSize()
+ {
+ return outputSizeBytes;
+ }
+
+ public int getBlockSize()
+ {
+ return threefish.getBlockSize();
+ }
+
+ /**
+ * Initialises the Skein engine with the provided parameters. See {@link SkeinParameters} for
+ * details on the parameterisation of the Skein hash function.
+ *
+ * @param params the parameters to apply to this engine, or <code>null</code> to use no parameters.
+ */
+ public void init(SkeinParameters params)
+ {
+ this.chain = null;
+ this.key = null;
+ this.preMessageParameters = null;
+ this.postMessageParameters = null;
+
+ if (params != null)
+ {
+ byte[] key = params.getKey();
+ if (key.length < 16)
+ {
+ throw new IllegalArgumentException("Skein key must be at least 128 bits.");
+ }
+ initParams(params.getParameters());
+ }
+ createInitialState();
+
+ // Initialise message block
+ ubiInit(PARAM_TYPE_MESSAGE);
+ }
+
+ private void initParams(Hashtable parameters)
+ {
+ Enumeration keys = parameters.keys();
+ final Vector pre = new Vector();
+ final Vector post = new Vector();
+
+ while (keys.hasMoreElements())
+ {
+ Integer type = (Integer)keys.nextElement();
+ byte[] value = (byte[])parameters.get(type);
+
+ if (type.intValue() == PARAM_TYPE_KEY)
+ {
+ this.key = value;
+ }
+ else if (type.intValue() < PARAM_TYPE_MESSAGE)
+ {
+ pre.addElement(new Parameter(type.intValue(), value));
+ }
+ else
+ {
+ post.addElement(new Parameter(type.intValue(), value));
+ }
+ }
+ preMessageParameters = new Parameter[pre.size()];
+ pre.copyInto(preMessageParameters);
+ sort(preMessageParameters);
+
+ postMessageParameters = new Parameter[post.size()];
+ post.copyInto(postMessageParameters);
+ sort(postMessageParameters);
+ }
+
+ private static void sort(Parameter[] params)
+ {
+ if (params == null)
+ {
+ return;
+ }
+ // Insertion sort, for Java 1.1 compatibility
+ for (int i = 1; i < params.length; i++)
+ {
+ Parameter param = params[i];
+ int hole = i;
+ while (hole > 0 && param.getType() < params[hole - 1].getType())
+ {
+ params[hole] = params[hole - 1];
+ hole = hole - 1;
+ }
+ params[hole] = param;
+ }
+ }
+
+ /**
+ * Calculate the initial (pre message block) chaining state.
+ */
+ private void createInitialState()
+ {
+ long[] precalc = (long[])INITIAL_STATES.get(variantIdentifier(getBlockSize(), getOutputSize()));
+ if ((key == null) && (precalc != null))
+ {
+ // Precalculated UBI(CFG)
+ chain = Arrays.clone(precalc);
+ }
+ else
+ {
+ // Blank initial state
+ chain = new long[getBlockSize() / 8];
+
+ // Process key block
+ if (key != null)
+ {
+ ubiComplete(SkeinParameters.PARAM_TYPE_KEY, key);
+ }
+
+ // Process configuration block
+ ubiComplete(PARAM_TYPE_CONFIG, new Configuration(outputSizeBytes * 8).getBytes());
+ }
+
+ // Process additional pre-message parameters
+ if (preMessageParameters != null)
+ {
+ for (int i = 0; i < preMessageParameters.length; i++)
+ {
+ Parameter param = preMessageParameters[i];
+ ubiComplete(param.getType(), param.getValue());
+ }
+ }
+ initialState = Arrays.clone(chain);
+ }
+
+ /**
+ * Reset the engine to the initial state (with the key and any pre-message parameters , ready to
+ * accept message input.
+ */
+ public void reset()
+ {
+ System.arraycopy(initialState, 0, chain, 0, chain.length);
+
+ ubiInit(PARAM_TYPE_MESSAGE);
+ }
+
+ private void ubiComplete(int type, byte[] value)
+ {
+ ubiInit(type);
+ this.ubi.update(value, 0, value.length, chain);
+ ubiFinal();
+ }
+
+ private void ubiInit(int type)
+ {
+ this.ubi.reset(type);
+ }
+
+ private void ubiFinal()
+ {
+ ubi.doFinal(chain);
+ }
+
+ private void checkInitialised()
+ {
+ if (this.ubi == null)
+ {
+ throw new IllegalArgumentException("Skein engine is not initialised.");
+ }
+ }
+
+ public void update(byte in)
+ {
+ singleByte[0] = in;
+ update(singleByte, 0, 1);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ {
+ checkInitialised();
+ ubi.update(in, inOff, len, chain);
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ checkInitialised();
+ if (out.length < (outOff + outputSizeBytes))
+ {
+ throw new DataLengthException("Output buffer is too short to hold output of " + outputSizeBytes + " bytes");
+ }
+
+ // Finalise message block
+ ubiFinal();
+
+ // Process additional post-message parameters
+ if (postMessageParameters != null)
+ {
+ for (int i = 0; i < postMessageParameters.length; i++)
+ {
+ Parameter param = postMessageParameters[i];
+ ubiComplete(param.getType(), param.getValue());
+ }
+ }
+
+ // Perform the output transform
+ final int blockSize = getBlockSize();
+ final int blocksRequired = ((outputSizeBytes + blockSize - 1) / blockSize);
+ for (int i = 0; i < blocksRequired; i++)
+ {
+ final int toWrite = Math.min(blockSize, outputSizeBytes - (i * blockSize));
+ output(i, out, outOff + (i * blockSize), toWrite);
+ }
+
+ reset();
+
+ return outputSizeBytes;
+ }
+
+ private void output(long outputSequence, byte[] out, int outOff, int outputBytes)
+ {
+ byte[] currentBytes = new byte[8];
+ ThreefishEngine.wordToBytes(outputSequence, currentBytes, 0);
+
+ // Output is a sequence of UBI invocations all of which use and preserve the pre-output
+ // state
+ long[] outputWords = new long[chain.length];
+ ubiInit(PARAM_TYPE_OUTPUT);
+ this.ubi.update(currentBytes, 0, currentBytes.length, outputWords);
+ ubi.doFinal(outputWords);
+
+ final int wordsRequired = ((outputBytes + 8 - 1) / 8);
+ for (int i = 0; i < wordsRequired; i++)
+ {
+ int toWrite = Math.min(8, outputBytes - (i * 8));
+ if (toWrite == 8)
+ {
+ ThreefishEngine.wordToBytes(outputWords[i], out, outOff + (i * 8));
+ }
+ else
+ {
+ ThreefishEngine.wordToBytes(outputWords[i], currentBytes, 0);
+ System.arraycopy(currentBytes, 0, out, outOff + (i * 8), toWrite);
+ }
+ }
+ }
+
+}
diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/engines/NullEngine.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/engines/NullEngine.java
new file mode 100644
index 00000000..b5c74512
--- /dev/null
+++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/engines/NullEngine.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.OutputLengthException;
+
+/**
+ * The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting.
+ * Provided for the sake of completeness.
+ */
+public class NullEngine implements BlockCipher
+{
+ private boolean initialised;
+ protected static final int DEFAULT_BLOCK_SIZE = 1;
+ private int blockSize;
+
+ /**
+ * Constructs a null engine with a block size of 1 byte.
+ */
+ public NullEngine()
+ {
+ this(DEFAULT_BLOCK_SIZE);
+ }
+
+ /**
+ * Constructs a null engine with a specific block size.
+ *
+ * @param blockSize the block size in bytes.
+ */
+ public NullEngine(int blockSize)
+ {
+ this.blockSize = blockSize;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.crypto.BlockCipher#init(boolean, org.bouncycastle.crypto.CipherParameters)
+ */
+ public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException
+ {
+ // we don't mind any parameters that may come in
+ this.initialised = true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.crypto.BlockCipher#getAlgorithmName()
+ */
+ public String getAlgorithmName()
+ {
+ return "Null";
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.crypto.BlockCipher#getBlockSize()
+ */
+ public int getBlockSize()
+ {
+ return blockSize;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.crypto.BlockCipher#processBlock(byte[], int, byte[], int)
+ */
+ public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if (!initialised)
+ {
+ throw new IllegalStateException("Null engine not initialised");
+ }
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > out.length)
+ {
+ throw new OutputLengthException("output buffer too short");
+ }
+
+ for (int i = 0; i < blockSize; ++i)
+ {
+ out[outOff + i] = in[inOff + i];
+ }
+
+ return blockSize;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.crypto.BlockCipher#reset()
+ */
+ public void reset()
+ {
+ // nothing needs to be done
+ }
+}
diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/signers/RSADigestSigner.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/signers/RSADigestSigner.java
new file mode 100644
index 00000000..f15e4047
--- /dev/null
+++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/signers/RSADigestSigner.java
@@ -0,0 +1,238 @@
+package org.bouncycastle.crypto.signers;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DigestInfo;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.Signer;
+import org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import org.bouncycastle.crypto.engines.RSABlindedEngine;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.util.Arrays;
+
+public class RSADigestSigner
+ implements Signer
+{
+ private final AsymmetricBlockCipher rsaEngine = new PKCS1Encoding(new RSABlindedEngine());
+ private AlgorithmIdentifier algId;
+ private Digest digest;
+ private boolean forSigning;
+
+ private static final Hashtable oidMap = new Hashtable();
+
+ /*
+ * Load OID table.
+ */
+ static
+ {
+ oidMap.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128);
+ oidMap.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160);
+ oidMap.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256);
+
+ oidMap.put("SHA-1", X509ObjectIdentifiers.id_SHA1);
+ oidMap.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+ oidMap.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+ oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384);
+ oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+
+ oidMap.put("MD2", PKCSObjectIdentifiers.md2);
+ oidMap.put("MD4", PKCSObjectIdentifiers.md4);
+ oidMap.put("MD5", PKCSObjectIdentifiers.md5);
+ }
+
+ public RSADigestSigner(
+ Digest digest)
+ {
+ this(digest, (ASN1ObjectIdentifier)oidMap.get(digest.getAlgorithmName()));
+ }
+
+ public RSADigestSigner(
+ Digest digest,
+ ASN1ObjectIdentifier digestOid)
+ {
+ this.digest = digest;
+ this.algId = new AlgorithmIdentifier(digestOid, DERNull.INSTANCE);
+ }
+
+ /**
+ * @deprecated
+ */
+ public String getAlgorithmName()
+ {
+ return digest.getAlgorithmName() + "withRSA";
+ }
+
+ /**
+ * initialise the signer for signing or verification.
+ *
+ * @param forSigning
+ * true if for signing, false otherwise
+ * @param parameters
+ * necessary parameters.
+ */
+ public void init(
+ boolean forSigning,
+ CipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+ AsymmetricKeyParameter k;
+
+ if (parameters instanceof ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).getParameters();
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.isPrivate())
+ {
+ throw new IllegalArgumentException("signing requires private key");
+ }
+
+ if (!forSigning && k.isPrivate())
+ {
+ throw new IllegalArgumentException("verification requires public key");
+ }
+
+ reset();
+
+ rsaEngine.init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void update(
+ byte input)
+ {
+ digest.update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void update(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.update(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using the key
+ * we were initialised with.
+ */
+ public byte[] generateSignature()
+ throws CryptoException, DataLengthException
+ {
+ if (!forSigning)
+ {
+ throw new IllegalStateException("RSADigestSigner not initialised for signature generation.");
+ }
+
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] data = derEncode(hash);
+ return rsaEngine.processBlock(data, 0, data.length);
+ }
+ catch (IOException e)
+ {
+ throw new CryptoException("unable to encode signature: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * return true if the internal state represents the signature described in
+ * the passed in array.
+ */
+ public boolean verifySignature(
+ byte[] signature)
+ {
+ if (forSigning)
+ {
+ throw new IllegalStateException("RSADigestSigner not initialised for verification");
+ }
+
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ byte[] sig;
+ byte[] expected;
+
+ try
+ {
+ sig = rsaEngine.processBlock(signature, 0, signature.length);
+ expected = derEncode(hash);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ if (sig.length == expected.length)
+ {
+ return Arrays.constantTimeAreEqual(sig, expected);
+ }
+ 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 nonEqual = 0;
+
+ for (int i = 0; i < hash.length; i++)
+ {
+ nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]);
+ }
+
+ for (int i = 0; i < sigOffset; i++)
+ {
+ nonEqual |= (sig[i] ^ expected[i]); // check header less NULL
+ }
+
+ return nonEqual == 0;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public void reset()
+ {
+ digest.reset();
+ }
+
+ private byte[] derEncode(
+ byte[] hash)
+ throws IOException
+ {
+ DigestInfo dInfo = new DigestInfo(algId, hash);
+
+ return dInfo.getEncoded(ASN1Encoding.DER);
+ }
+}