summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu/java/security/key/dss
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/gnu/java/security/key/dss')
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSKey.java213
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java382
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java249
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java347
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java276
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java205
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java203
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/FIPS186.java262
8 files changed, 2137 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSKey.java
new file mode 100644
index 000000000..49f229f7b
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/key/dss/DSSKey.java
@@ -0,0 +1,213 @@
+/* DSSKey.java --
+ Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.lang.CPStringBuilder;
+
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.util.FormatUtil;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.Key;
+import java.security.interfaces.DSAKey;
+import java.security.interfaces.DSAParams;
+import java.security.spec.DSAParameterSpec;
+
+/**
+ * A base asbtract class for both public and private DSS (Digital Signature
+ * Standard) keys. It encapsulates the three DSS numbers: <code>p</code>,
+ * <code>q</code> and <code>g</code>.
+ * <p>
+ * According to the JDK, cryptographic <i>Keys</i> all have a <i>format</i>.
+ * The format used in this implementation is called <i>Raw</i>, and basically
+ * consists of the raw byte sequences of algorithm parameters. The exact order
+ * of the byte sequences and the implementation details are given in each of the
+ * relevant <code>getEncoded()</code> methods of each of the private and
+ * public keys.
+ * <p>
+ * <b>IMPORTANT</b>: Under certain circumstances (e.g. in an X.509 certificate
+ * with inherited AlgorithmIdentifier's parameters of a SubjectPublicKeyInfo
+ * element) these three MPIs may be <code>null</code>.
+ *
+ * @see DSSPrivateKey#getEncoded
+ * @see DSSPublicKey#getEncoded
+ */
+public abstract class DSSKey
+ implements Key, DSAKey
+{
+ /**
+ * A prime modulus, where
+ * <code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup></code> for
+ * <code>512 &lt;= L &lt;= 1024</code> and <code>L</code> a multiple of
+ * <code>64</code>.
+ */
+ protected final BigInteger p;
+
+ /**
+ * A prime divisor of <code>p - 1</code>, where
+ * <code>2<sup>159</sup> &lt; q
+ * &lt; 2<sup>160</sup></code>.
+ */
+ protected final BigInteger q;
+
+ /**
+ * <code>g = h<sup>(p-1)</sup>/q mod p</code>, where <code>h</code> is
+ * any integer with <code>1 &lt; h &lt; p - 1</code> such that <code>h<sup>
+ * (p-1)</sup>/q mod p > 1</code> (<code>g</code>
+ * has order <code>q mod p
+ * </code>).
+ */
+ protected final BigInteger g;
+
+ /**
+ * Identifier of the default encoding format to use when externalizing the key
+ * material.
+ */
+ protected final int defaultFormat;
+
+ /** String representation of this key. Cached for speed. */
+ private transient String str;
+
+ /**
+ * Trivial protected constructor.
+ *
+ * @param defaultFormat the identifier of the encoding format to use by
+ * default when externalizing the key.
+ * @param p the DSS parameter <code>p</code>.
+ * @param q the DSS parameter <code>q</code>.
+ * @param g the DSS parameter <code>g</code>.
+ */
+ protected DSSKey(int defaultFormat, BigInteger p, BigInteger q, BigInteger g)
+ {
+ super();
+
+ this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID
+ : defaultFormat;
+ this.p = p;
+ this.q = q;
+ this.g = g;
+ }
+
+ public DSAParams getParams()
+ {
+ return new DSAParameterSpec(p, q, g);
+ }
+
+ public String getAlgorithm()
+ {
+ return Registry.DSS_KPG;
+ }
+
+ /** @deprecated see getEncoded(int). */
+ public byte[] getEncoded()
+ {
+ return getEncoded(defaultFormat);
+ }
+
+ public String getFormat()
+ {
+ return FormatUtil.getEncodingShortName(defaultFormat);
+ }
+
+ /**
+ * Returns <code>true</code> if the designated object is an instance of
+ * {@link DSAKey} and has the same DSS (Digital Signature Standard) parameter
+ * values as this one.
+ * <p>
+ * Always returns <code>false</code> if the MPIs of this key are
+ * <i>inherited</i>. This may be the case when the key is re-constructed from
+ * an X.509 certificate with absent or NULL AlgorithmIdentifier's parameters
+ * field.
+ *
+ * @param obj the other non-null DSS key to compare to.
+ * @return <code>true</code> if the designated object is of the same type
+ * and value as this one.
+ */
+ public boolean equals(Object obj)
+ {
+ if (hasInheritedParameters())
+ return false;
+
+ if (obj == null)
+ return false;
+
+ if (! (obj instanceof DSAKey))
+ return false;
+
+ DSAKey that = (DSAKey) obj;
+ return p.equals(that.getParams().getP())
+ && q.equals(that.getParams().getQ())
+ && g.equals(that.getParams().getG());
+ }
+
+ public String toString()
+ {
+ if (str == null)
+ {
+ String ls = (String) AccessController.doPrivileged(new GetPropertyAction("line.separator"));
+ CPStringBuilder sb = new CPStringBuilder(ls)
+ .append("defaultFormat=").append(defaultFormat).append(",")
+ .append(ls);
+ if (hasInheritedParameters())
+ sb.append("p=inherited,").append(ls)
+ .append("q=inherited,").append(ls)
+ .append("g=inherited");
+ else
+ sb.append("p=0x").append(p.toString(16)).append(",").append(ls)
+ .append("q=0x").append(q.toString(16)).append(",").append(ls)
+ .append("g=0x").append(g.toString(16));
+ str = sb.toString();
+ }
+ return str;
+ }
+
+ public abstract byte[] getEncoded(int format);
+
+ /**
+ * @return <code>true</code> if <code>p</code>, <code>q</code> and
+ * <code>g</code> are all <code>null</code>. Returns
+ * <code>false</code> otherwise.
+ */
+ public boolean hasInheritedParameters()
+ {
+ return p == null && q == null && g == null;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java
new file mode 100644
index 000000000..6bda4e88e
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java
@@ -0,0 +1,382 @@
+/* DSSKeyPairGenerator.java --
+ Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.key.IKeyPairGenerator;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.DSAParameterSpec;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * A key-pair generator for asymetric keys to use in conjunction with the DSS
+ * (Digital Signature Standard).
+ * <p>
+ * References:
+ * <p>
+ * <a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
+ * Standard (DSS)</a>, Federal Information Processing Standards Publication
+ * 186. National Institute of Standards and Technology.
+ */
+public class DSSKeyPairGenerator
+ implements IKeyPairGenerator
+{
+ private static final Logger log = Logger.getLogger(DSSKeyPairGenerator.class.getName());
+
+ /** The BigInteger constant 2. */
+ private static final BigInteger TWO = BigInteger.valueOf(2L);
+
+ /** Property name of the length (Integer) of the modulus (p) of a DSS key. */
+ public static final String MODULUS_LENGTH = "gnu.crypto.dss.L";
+
+ /**
+ * Property name of the Boolean indicating wether or not to use default pre-
+ * computed values of <code>p</code>, <code>q</code> and <code>g</code>
+ * for a given modulus length. The ultimate behaviour of this generator with
+ * regard to using pre-computed parameter sets will depend on the value of
+ * this property and of the following one {@link #STRICT_DEFAULTS}:
+ * <ol>
+ * <li>If this property is {@link Boolean#FALSE} then this generator will
+ * accept being setup for generating parameters for any modulus length
+ * provided the modulus length is between <code>512</code> and
+ * <code>1024</code>, and is of the form <code>512 + 64 * n</code>. In
+ * addition, a new paramter set will always be generated; i.e. no pre-
+ * computed values are used.</li>
+ * <li>If this property is {@link Boolean#TRUE} and the value of
+ * {@link #STRICT_DEFAULTS} is also {@link Boolean#TRUE} then this generator
+ * will only accept being setup for generating parameters for modulus lengths
+ * of <code>512</code>, <code>768</code> and <code>1024</code>. Any
+ * other value, of the modulus length, even if between <code>512</code> and
+ * <code>1024</code>, and of the form <code>512 + 64 * n</code>, will
+ * cause an {@link IllegalArgumentException} to be thrown. When those modulus
+ * length (<code>512</code>, <code>768</code>, and <code>1024</code>)
+ * are specified, the paramter set is always the same.</li>
+ * <li>Finally, if this property is {@link Boolean#TRUE} and the value of
+ * {@link #STRICT_DEFAULTS} is {@link Boolean#FALSE} then this generator will
+ * behave as in point 1 above, except that it will use pre-computed values
+ * when possible; i.e. the modulus length is one of <code>512</code>,
+ * <code>768</code>, or <code>1024</code>.</li>
+ * </ol>
+ * The default value of this property is {@link Boolean#TRUE}.
+ */
+ public static final String USE_DEFAULTS = "gnu.crypto.dss.use.defaults";
+
+ /**
+ * Property name of the Boolean indicating wether or not to generate new
+ * parameters, even if the modulus length <i>L</i> is not one of the pre-
+ * computed defaults (value {@link Boolean#FALSE}), or throw an exception
+ * (value {@link Boolean#TRUE}) -- the exception in this case is an
+ * {@link IllegalArgumentException}. The default value for this property is
+ * {@link Boolean#FALSE}. The ultimate behaviour of this generator will
+ * depend on the values of this and {@link #USE_DEFAULTS} properties -- see
+ * {@link #USE_DEFAULTS} for more information.
+ */
+ public static final String STRICT_DEFAULTS = "gnu.crypto.dss.strict.defaults";
+
+ /**
+ * Property name of an optional {@link SecureRandom} instance to use. The
+ * default is to use a classloader singleton from {@link PRNG}.
+ */
+ public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dss.prng";
+
+ /**
+ * Property name of an optional {@link DSAParameterSpec} instance to use for
+ * this generator's <code>p</code>, <code>q</code>, and <code>g</code>
+ * values. The default is to generate these values or use pre-computed ones,
+ * depending on the value of the <code>USE_DEFAULTS</code> attribute.
+ */
+ public static final String DSS_PARAMETERS = "gnu.crypto.dss.params";
+
+ /**
+ * Property name of the preferred encoding format to use when externalizing
+ * generated instance of key-pairs from this generator. The property is taken
+ * to be an {@link Integer} that encapsulates an encoding format identifier.
+ */
+ public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dss.encoding";
+
+ /** Default value for the modulus length. */
+ public static final int DEFAULT_MODULUS_LENGTH = 1024;
+
+ /** Default encoding format to use when none was specified. */
+ private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID;
+
+ /** Initial SHS context. */
+ private static final int[] T_SHS = new int[] {
+ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
+ };
+
+ // from jdk1.3.1/docs/guide/security/CryptoSpec.html#AppB
+ public static final DSAParameterSpec KEY_PARAMS_512 = new DSAParameterSpec(
+ new BigInteger(
+ "fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae"
+ + "01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16),
+ new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16),
+ new BigInteger(
+ "678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e"
+ + "35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16));
+ public static final DSAParameterSpec KEY_PARAMS_768 = new DSAParameterSpec(
+ new BigInteger(
+ "e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d8901419"
+ + "22d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d77"
+ + "7d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16),
+ new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", 16),
+ new BigInteger(
+ "30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4"
+ + "dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d8"
+ + "3c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16));
+ public static final DSAParameterSpec KEY_PARAMS_1024 = new DSAParameterSpec(
+ new BigInteger(
+ "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669"
+ + "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7"
+ + "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb"
+ + "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16),
+ new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16),
+ new BigInteger(
+ "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267"
+ + "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1"
+ + "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b"
+ + "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", 16));
+
+ private static final BigInteger TWO_POW_160 = TWO.pow(160);
+
+ /** The length of the modulus of DSS keys generated by this instance. */
+ private int L;
+
+ /** The optional {@link SecureRandom} instance to use. */
+ private SecureRandom rnd = null;
+
+ private BigInteger seed;
+
+ private BigInteger counter;
+
+ private BigInteger p;
+
+ private BigInteger q;
+
+ private BigInteger e;
+
+ private BigInteger g;
+
+ private BigInteger XKEY;
+
+ /** Our default source of randomness. */
+ private PRNG prng = null;
+
+ /** Preferred encoding format of generated keys. */
+ private int preferredFormat;
+
+ public String name()
+ {
+ return Registry.DSS_KPG;
+ }
+
+ /**
+ * Configures this instance.
+ *
+ * @param attributes the map of name/value pairs to use.
+ * @exception IllegalArgumentException if the designated MODULUS_LENGTH value
+ * is not greater than 512, less than 1024 and not of the form
+ * <code>512 + 64j</code>.
+ */
+ public void setup(Map attributes)
+ {
+ // find out the modulus length
+ Integer l = (Integer) attributes.get(MODULUS_LENGTH);
+ L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue());
+ if ((L % 64) != 0 || L < 512 || L > 1024)
+ throw new IllegalArgumentException(MODULUS_LENGTH);
+
+ // should we use the default pre-computed params?
+ Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS);
+ if (useDefaults == null)
+ useDefaults = Boolean.TRUE;
+
+ Boolean strictDefaults = (Boolean) attributes.get(STRICT_DEFAULTS);
+ if (strictDefaults == null)
+ strictDefaults = Boolean.FALSE;
+
+ // are we given a set of DSA params or we shall use/generate our own?
+ DSAParameterSpec params = (DSAParameterSpec) attributes.get(DSS_PARAMETERS);
+ if (params != null)
+ {
+ p = params.getP();
+ q = params.getQ();
+ g = params.getG();
+ }
+ else if (useDefaults.equals(Boolean.TRUE))
+ {
+ switch (L)
+ {
+ case 512:
+ p = KEY_PARAMS_512.getP();
+ q = KEY_PARAMS_512.getQ();
+ g = KEY_PARAMS_512.getG();
+ break;
+ case 768:
+ p = KEY_PARAMS_768.getP();
+ q = KEY_PARAMS_768.getQ();
+ g = KEY_PARAMS_768.getG();
+ break;
+ case 1024:
+ p = KEY_PARAMS_1024.getP();
+ q = KEY_PARAMS_1024.getQ();
+ g = KEY_PARAMS_1024.getG();
+ break;
+ default:
+ if (strictDefaults.equals(Boolean.TRUE))
+ throw new IllegalArgumentException(
+ "Does not provide default parameters for " + L
+ + "-bit modulus length");
+ else
+ {
+ p = null;
+ q = null;
+ g = null;
+ }
+ }
+ }
+ else
+ {
+ p = null;
+ q = null;
+ g = null;
+ }
+ // do we have a SecureRandom, or should we use our own?
+ rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
+ // what is the preferred encoding format
+ Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
+ preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT
+ : formatID.intValue();
+ // set the seed-key
+ byte[] kb = new byte[20]; // we need 160 bits of randomness
+ nextRandomBytes(kb);
+ XKEY = new BigInteger(1, kb).setBit(159).setBit(0);
+ }
+
+ public KeyPair generate()
+ {
+ if (p == null)
+ {
+ BigInteger[] params = new FIPS186(L, rnd).generateParameters();
+ seed = params[FIPS186.DSA_PARAMS_SEED];
+ counter = params[FIPS186.DSA_PARAMS_COUNTER];
+ q = params[FIPS186.DSA_PARAMS_Q];
+ p = params[FIPS186.DSA_PARAMS_P];
+ e = params[FIPS186.DSA_PARAMS_E];
+ g = params[FIPS186.DSA_PARAMS_G];
+ if (Configuration.DEBUG)
+ {
+ log.fine("seed: " + seed.toString(16));
+ log.fine("counter: " + counter.intValue());
+ log.fine("q: " + q.toString(16));
+ log.fine("p: " + p.toString(16));
+ log.fine("e: " + e.toString(16));
+ log.fine("g: " + g.toString(16));
+ }
+ }
+ BigInteger x = nextX();
+ BigInteger y = g.modPow(x, p);
+ PublicKey pubK = new DSSPublicKey(preferredFormat, p, q, g, y);
+ PrivateKey secK = new DSSPrivateKey(preferredFormat, p, q, g, x);
+ return new KeyPair(pubK, secK);
+ }
+
+ /**
+ * This method applies the following algorithm described in 3.1 of FIPS-186:
+ * <ol>
+ * <li>XSEED = optional user input.</li>
+ * <li>XVAL = (XKEY + XSEED) mod 2<sup>b</sup>.</li>
+ * <li>x = G(t, XVAL) mod q.</li>
+ * <li>XKEY = (1 + XKEY + x) mod 2<sup>b</sup>.</li>
+ * </ol>
+ * <p>
+ * Where <code>b</code> is the length of a secret b-bit seed-key (XKEY).
+ * <p>
+ * Note that in this implementation, XSEED, the optional user input, is always
+ * zero.
+ */
+ private synchronized BigInteger nextX()
+ {
+ byte[] xk = XKEY.toByteArray();
+ byte[] in = new byte[64]; // 512-bit block for SHS
+ System.arraycopy(xk, 0, in, 0, xk.length);
+ int[] H = Sha160.G(T_SHS[0], T_SHS[1], T_SHS[2], T_SHS[3], T_SHS[4], in, 0);
+ byte[] h = new byte[20];
+ for (int i = 0, j = 0; i < 5; i++)
+ {
+ h[j++] = (byte)(H[i] >>> 24);
+ h[j++] = (byte)(H[i] >>> 16);
+ h[j++] = (byte)(H[i] >>> 8);
+ h[j++] = (byte) H[i];
+ }
+ BigInteger result = new BigInteger(1, h).mod(q);
+ XKEY = XKEY.add(result).add(BigInteger.ONE).mod(TWO_POW_160);
+ return result;
+ }
+
+ /**
+ * Fills the designated byte array with random data.
+ *
+ * @param buffer the byte array to fill with random data.
+ */
+ private void nextRandomBytes(byte[] buffer)
+ {
+ if (rnd != null)
+ rnd.nextBytes(buffer);
+ else
+ getDefaultPRNG().nextBytes(buffer);
+ }
+
+ private PRNG getDefaultPRNG()
+ {
+ if (prng == null)
+ prng = PRNG.getInstance();
+
+ return prng;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java
new file mode 100644
index 000000000..a59ca3cee
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java
@@ -0,0 +1,249 @@
+/* DSSKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.util.DerUtil;
+import gnu.java.security.util.Util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+/**
+ * An implementation of an {@link IKeyPairCodec} that knows how to encode /
+ * decode PKCS#8 ASN.1 external representation of DSS private keys.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class DSSKeyPairPKCS8Codec
+ implements IKeyPairCodec
+{
+ private static final Logger log = Logger.getLogger(DSSKeyPairPKCS8Codec.class.getName());
+ private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
+
+ // implicit 0-arguments constructor
+
+ public int getFormatID()
+ {
+ return PKCS8_FORMAT;
+ }
+
+ /**
+ * @throws InvalidParameterException ALWAYS.
+ */
+ public byte[] encodePublicKey(PublicKey key)
+ {
+ throw new InvalidParameterException("Wrong format for public keys");
+ }
+
+ /**
+ * Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of a DSA
+ * private key. The ASN.1 specification is as follows:
+ *
+ * <pre>
+ * PrivateKeyInfo ::= SEQUENCE {
+ * version INTEGER, -- MUST be 0
+ * privateKeyAlgorithm AlgorithmIdentifier,
+ * privateKey OCTET STRING
+ * }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
+ * DssParams ::= SEQUENCE {
+ * p INTEGER,
+ * q INTEGER,
+ * g INTEGER
+ * }
+ * </pre>
+ *
+ * @return the DER encoded form of the ASN.1 representation of the
+ * <i>PrivateKeyInfo</i> field in an X.509 certificate.
+ * @throw InvalidParameterException if an error occurs during the marshalling
+ * process.
+ */
+ public byte[] encodePrivateKey(PrivateKey key)
+ {
+ if (! (key instanceof DSSPrivateKey))
+ throw new InvalidParameterException("Wrong key type");
+
+ DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+
+ DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
+
+ DSSPrivateKey pk = (DSSPrivateKey) key;
+ BigInteger p = pk.getParams().getP();
+ BigInteger q = pk.getParams().getQ();
+ BigInteger g = pk.getParams().getG();
+ BigInteger x = pk.getX();
+
+ ArrayList params = new ArrayList(3);
+ params.add(new DERValue(DER.INTEGER, p));
+ params.add(new DERValue(DER.INTEGER, q));
+ params.add(new DERValue(DER.INTEGER, g));
+ DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+
+ ArrayList algorithmID = new ArrayList(2);
+ algorithmID.add(derOID);
+ algorithmID.add(derParams);
+ DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ algorithmID);
+
+ // The OCTET STRING is the DER encoding of an INTEGER.
+ DERValue derX = new DERValue(DER.INTEGER, x);
+ DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, derX.getEncoded());
+
+ ArrayList pki = new ArrayList(3);
+ pki.add(derVersion);
+ pki.add(derAlgorithmID);
+ pki.add(derPrivateKey);
+ DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
+
+ byte[] result;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try
+ {
+ DERWriter.write(baos, derPKI);
+ result = baos.toByteArray();
+ }
+ catch (IOException e)
+ {
+ InvalidParameterException y = new InvalidParameterException(e.getMessage());
+ y.initCause(e);
+ throw y;
+ }
+ return result;
+ }
+
+ /**
+ * @throws InvalidParameterException ALWAYS.
+ */
+ public PublicKey decodePublicKey(byte[] input)
+ {
+ throw new InvalidParameterException("Wrong format for public keys");
+ }
+
+ /**
+ * @param input the byte array to unmarshall into a valid DSS
+ * {@link PrivateKey} instance. MUST NOT be null.
+ * @return a new instance of a {@link DSSPrivateKey} decoded from the
+ * <i>PrivateKeyInfo</i> material fed as <code>input</code>.
+ * @throw InvalidParameterException if an exception occurs during the
+ * unmarshalling process.
+ */
+ public PrivateKey decodePrivateKey(byte[] input)
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "decodePrivateKey");
+ if (input == null)
+ throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+ BigInteger version, p, q, g, x;
+ DERReader der = new DERReader(input);
+ try
+ {
+ DERValue derPKI = der.read();
+ DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
+
+ DERValue derVersion = der.read();
+ if (! (derVersion.getValue() instanceof BigInteger))
+ throw new InvalidParameterException("Wrong Version field");
+
+ version = (BigInteger) derVersion.getValue();
+ if (version.compareTo(BigInteger.ZERO) != 0)
+ throw new InvalidParameterException("Unexpected Version: " + version);
+
+ DERValue derAlgoritmID = der.read();
+ DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
+
+ DERValue derOID = der.read();
+ OID algOID = (OID) derOID.getValue();
+ if (! algOID.equals(DSA_ALG_OID))
+ throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+ DERValue derParams = der.read();
+ DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field");
+
+ DERValue val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong P field");
+ p = (BigInteger) val.getValue();
+ val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong Q field");
+ q = (BigInteger) val.getValue();
+ val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong G field");
+ g = (BigInteger) val.getValue();
+
+ val = der.read();
+ if (Configuration.DEBUG)
+ log.fine("val = " + val);
+ byte[] xBytes = (byte[]) val.getValue();
+ if (Configuration.DEBUG)
+ log.fine(Util.dumpString(xBytes, "xBytes: "));
+ DERReader der2 = new DERReader(xBytes);
+ val = der2.read();
+ DerUtil.checkIsBigInteger(val, "Wrong X field");
+ x = (BigInteger) val.getValue();
+ }
+ catch (IOException e)
+ {
+ InvalidParameterException y = new InvalidParameterException(e.getMessage());
+ y.initCause(e);
+ throw y;
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "decodePrivateKey");
+ return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java
new file mode 100644
index 000000000..5b93c6b1e
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java
@@ -0,0 +1,347 @@
+/* DSSKeyPairRawCodec.java --
+ Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * An object that implements the {@link IKeyPairCodec} operations for the
+ * <i>Raw</i> format to use with DSS keypairs.
+ */
+public class DSSKeyPairRawCodec
+ implements IKeyPairCodec
+{
+ // implicit 0-arguments constructor
+
+ public int getFormatID()
+ {
+ return RAW_FORMAT;
+ }
+
+ /**
+ * Returns the encoded form of the designated DSS (Digital Signature Standard)
+ * public key according to the <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for a DSA public key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_DSS_PUBLIC_KEY},
+ * <li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>p</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>p</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>q</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>q</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>y</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>y</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> format encoding of the designated key.
+ * @throws IllegalArgumentException if the designated key is not a DSS
+ * (Digital Signature Standard) one.
+ * @see Registry#MAGIC_RAW_DSS_PUBLIC_KEY
+ */
+ public byte[] encodePublicKey(PublicKey key)
+ {
+ if (! (key instanceof DSSPublicKey))
+ throw new IllegalArgumentException("key");
+
+ DSSPublicKey dssKey = (DSSPublicKey) key;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ // magic
+ baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]);
+ baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[1]);
+ baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[2]);
+ baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[3]);
+ // version
+ baos.write(0x01);
+ // p
+ byte[] buffer = dssKey.getParams().getP().toByteArray();
+ int length = buffer.length;
+ baos.write(length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write(length & 0xFF);
+ baos.write(buffer, 0, length);
+ // q
+ buffer = dssKey.getParams().getQ().toByteArray();
+ length = buffer.length;
+ baos.write(length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write(length & 0xFF);
+ baos.write(buffer, 0, length);
+ // g
+ buffer = dssKey.getParams().getG().toByteArray();
+ length = buffer.length;
+ baos.write(length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write(length & 0xFF);
+ baos.write(buffer, 0, length);
+ // y
+ buffer = dssKey.getY().toByteArray();
+ length = buffer.length;
+ baos.write(length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write(length & 0xFF);
+ baos.write(buffer, 0, length);
+ return baos.toByteArray();
+ }
+
+ public PublicKey decodePublicKey(byte[] k)
+ {
+ // magic
+ if (k[0] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]
+ || k[1] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[1]
+ || k[2] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[2]
+ || k[3] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[3])
+ throw new IllegalArgumentException("magic");
+
+ // version
+ if (k[4] != 0x01)
+ throw new IllegalArgumentException("version");
+
+ int i = 5;
+ int l;
+ byte[] buffer;
+ // p
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger p = new BigInteger(1, buffer);
+ // q
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger q = new BigInteger(1, buffer);
+ // g
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger g = new BigInteger(1, buffer);
+ // y
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger y = new BigInteger(1, buffer);
+ return new DSSPublicKey(p, q, g, y);
+ }
+
+ /**
+ * Returns the encoded form of the designated DSS (Digital Signature Standard)
+ * private key according to the <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for a DSA private key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_DSS_PRIVATE_KEY},
+ * <li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>p</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>p</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>q</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>q</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>x</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>x</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> format encoding of the designated key.
+ * @throws IllegalArgumentException if the designated key is not a DSS
+ * (Digital Signature Standard) one.
+ */
+ public byte[] encodePrivateKey(PrivateKey key)
+ {
+ if (! (key instanceof DSSPrivateKey))
+ throw new IllegalArgumentException("key");
+
+ DSSPrivateKey dssKey = (DSSPrivateKey) key;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ // magic
+ baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]);
+ baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[1]);
+ baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[2]);
+ baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[3]);
+ // version
+ baos.write(0x01);
+ // p
+ byte[] buffer = dssKey.getParams().getP().toByteArray();
+ int length = buffer.length;
+ baos.write(length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write(length & 0xFF);
+ baos.write(buffer, 0, length);
+ // q
+ buffer = dssKey.getParams().getQ().toByteArray();
+ length = buffer.length;
+ baos.write(length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write(length & 0xFF);
+ baos.write(buffer, 0, length);
+ // g
+ buffer = dssKey.getParams().getG().toByteArray();
+ length = buffer.length;
+ baos.write(length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write(length & 0xFF);
+ baos.write(buffer, 0, length);
+ // x
+ buffer = dssKey.getX().toByteArray();
+ length = buffer.length;
+ baos.write(length >>> 24);
+ baos.write((length >>> 16) & 0xFF);
+ baos.write((length >>> 8) & 0xFF);
+ baos.write(length & 0xFF);
+ baos.write(buffer, 0, length);
+ return baos.toByteArray();
+ }
+
+ public PrivateKey decodePrivateKey(byte[] k)
+ {
+ // magic
+ if (k[0] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]
+ || k[1] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[1]
+ || k[2] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[2]
+ || k[3] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[3])
+ throw new IllegalArgumentException("magic");
+
+ // version
+ if (k[4] != 0x01)
+ throw new IllegalArgumentException("version");
+
+ int i = 5;
+ int l;
+ byte[] buffer;
+ // p
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger p = new BigInteger(1, buffer);
+ // q
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger q = new BigInteger(1, buffer);
+ // g
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger g = new BigInteger(1, buffer);
+ // x
+ l = k[i++] << 24
+ | (k[i++] & 0xFF) << 16
+ | (k[i++] & 0xFF) << 8
+ | (k[i++] & 0xFF);
+ buffer = new byte[l];
+ System.arraycopy(k, i, buffer, 0, l);
+ i += l;
+ BigInteger x = new BigInteger(1, buffer);
+ return new DSSPrivateKey(p, q, g, x);
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java
new file mode 100644
index 000000000..8c26910f1
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java
@@ -0,0 +1,276 @@
+/* DSSKeyPairX509Codec.java -- X.509 Encoding/Decoding handler
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.util.DerUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+
+/**
+ * An implementation of an {@link IKeyPairCodec} that knows how to encode /
+ * decode X.509 ASN.1 external representation of DSS public keys.
+ */
+public class DSSKeyPairX509Codec
+ implements IKeyPairCodec
+{
+ private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
+
+ // implicit 0-arguments constructor
+
+ public int getFormatID()
+ {
+ return X509_FORMAT;
+ }
+
+ /**
+ * Returns the X.509 ASN.1 <i>SubjectPublicKeyInfo</i> representation of a
+ * DSA public key. The ASN.1 specification, as defined in RFC-3280, and
+ * RFC-2459, is as follows:
+ *
+ * <pre>
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
+ * DssParams ::= SEQUENCE {
+ * p INTEGER,
+ * q INTEGER,
+ * g INTEGER
+ * }
+ * </pre>
+ * <p>
+ * Note that RFC-3280 (page 79) implies that some certificates MAY have an
+ * absent, or NULL, parameters field in their AlgorithmIdentifier element,
+ * implying that those parameters MUST be <i>inherited</i> from another
+ * certificate. This implementation, encodes a <i>NULL</i> element as the DER
+ * value of the parameters field when such is the case.
+ * <p>
+ * The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+ * DER-encoded form of the DSA public key as an INTEGER.
+ *
+ * <pre>
+ * DSAPublicKey ::= INTEGER -- public key, Y
+ * </pre>
+ *
+ * @param key the {@link PublicKey} instance to encode. MUST be an instance of
+ * {@link DSSPublicKey}.
+ * @return the ASN.1 representation of the <i>SubjectPublicKeyInfo</i> in an
+ * X.509 certificate.
+ * @throw InvalidParameterException if <code>key</code> is not an instance
+ * of {@link DSSPublicKey} or if an exception occurs during the
+ * marshalling process.
+ */
+ public byte[] encodePublicKey(PublicKey key)
+ {
+ if (! (key instanceof DSSPublicKey))
+ throw new InvalidParameterException("key");
+
+ DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
+
+ DSSPublicKey dssKey = (DSSPublicKey) key;
+ DERValue derParams;
+ if (dssKey.hasInheritedParameters())
+ derParams = new DERValue(DER.NULL, null);
+ else
+ {
+ BigInteger p = dssKey.getParams().getP();
+ BigInteger q = dssKey.getParams().getQ();
+ BigInteger g = dssKey.getParams().getG();
+
+ DERValue derP = new DERValue(DER.INTEGER, p);
+ DERValue derQ = new DERValue(DER.INTEGER, q);
+ DERValue derG = new DERValue(DER.INTEGER, g);
+
+ ArrayList params = new ArrayList(3);
+ params.add(derP);
+ params.add(derQ);
+ params.add(derG);
+ derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
+ }
+
+ ArrayList algorithmID = new ArrayList(2);
+ algorithmID.add(derOID);
+ algorithmID.add(derParams);
+ DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ algorithmID);
+
+ BigInteger y = dssKey.getY();
+ DERValue derDSAPublicKey = new DERValue(DER.INTEGER, y);
+ byte[] yBytes = derDSAPublicKey.getEncoded();
+ DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes));
+
+ ArrayList spki = new ArrayList(2);
+ spki.add(derAlgorithmID);
+ spki.add(derSPK);
+ DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki);
+
+ byte[] result;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try
+ {
+ DERWriter.write(baos, derSPKI);
+ result = baos.toByteArray();
+ }
+ catch (IOException x)
+ {
+ InvalidParameterException e = new InvalidParameterException(x.getMessage());
+ e.initCause(x);
+ throw e;
+ }
+ return result;
+ }
+
+ /**
+ * @throws InvalidParameterException ALWAYS.
+ */
+ public byte[] encodePrivateKey(PrivateKey key)
+ {
+ throw new InvalidParameterException("Wrong format for private keys");
+ }
+
+ /**
+ * @param input the byte array to unmarshall into a valid DSS
+ * {@link PublicKey} instance. MUST NOT be null.
+ * @return a new instance of a {@link DSSPublicKey} decoded from the
+ * <i>SubjectPublicKeyInfo</i> material in an X.509 certificate.
+ * @throw InvalidParameterException if an exception occurs during the
+ * unmarshalling process.
+ */
+ public PublicKey decodePublicKey(byte[] input)
+ {
+ if (input == null)
+ throw new InvalidParameterException("Input bytes MUST NOT be null");
+
+ BigInteger p = null;
+ BigInteger g = null;
+ BigInteger q = null;
+ BigInteger y;
+ DERReader der = new DERReader(input);
+ try
+ {
+ DERValue derSPKI = der.read();
+ DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field");
+
+ DERValue derAlgorithmID = der.read();
+ DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field");
+
+ DERValue derOID = der.read();
+ if (! (derOID.getValue() instanceof OID))
+ throw new InvalidParameterException("Wrong Algorithm field");
+
+ OID algOID = (OID) derOID.getValue();
+ if (! algOID.equals(DSA_ALG_OID))
+ throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+ DERValue val = der.read();
+ // RFC-3280, page 79 states: "If the subjectPublicKeyInfo field of the
+ // certificate contains an algorithm field with null parameters or
+ // parameters are omitted, compare the certificate subjectPublicKey
+ // algorithm to the working_public_key_algorithm. If the certificate
+ // subjectPublicKey algorithm and the working_public_key_algorithm are
+ // different, set the working_public_key_parameters to null."
+ // in other words, the parameters field of an AlgorithmIdentifier
+ // element MAY NOT be present at all, or if present MAY be NULL!
+ // the Mauve test ValidDSAParameterInheritenceTest5, in
+ // gnu.testlet.java.security.cert.pkix.pkits, is/was failing because
+ // of this.
+ if (val.getTag() == DER.NULL)
+ val = der.read();
+ else if (val.isConstructed())
+ {
+ val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong P field");
+ p = (BigInteger) val.getValue();
+ val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong Q field");
+ q = (BigInteger) val.getValue();
+ val = der.read();
+ DerUtil.checkIsBigInteger(val, "Wrong G field");
+ g = (BigInteger) val.getValue();
+
+ val = der.read();
+ }
+
+ if (! (val.getValue() instanceof BitString))
+ throw new InvalidParameterException("Wrong SubjectPublicKey field");
+
+ byte[] yBytes = ((BitString) val.getValue()).toByteArray();
+
+ DERReader dsaPub = new DERReader(yBytes);
+ val = dsaPub.read();
+ DerUtil.checkIsBigInteger(val, "Wrong Y field");
+ y = (BigInteger) val.getValue();
+ }
+ catch (IOException x)
+ {
+ InvalidParameterException e = new InvalidParameterException(x.getMessage());
+ e.initCause(x);
+ throw e;
+ }
+ return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y);
+ }
+
+ /**
+ * @throws InvalidParameterException ALWAYS.
+ */
+ public PrivateKey decodePrivateKey(byte[] input)
+ {
+ throw new InvalidParameterException("Wrong format for private keys");
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java
new file mode 100644
index 000000000..de3668c01
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java
@@ -0,0 +1,205 @@
+/* DSSPrivateKey.java --
+ Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.lang.CPStringBuilder;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.PrivateKey;
+import java.security.interfaces.DSAPrivateKey;
+
+/**
+ * An object that embodies a DSS (Digital Signature Standard) private key.
+ *
+ * @see #getEncoded
+ */
+public class DSSPrivateKey
+ extends DSSKey
+ implements PrivateKey, DSAPrivateKey
+{
+ /**
+ * A randomly or pseudorandomly generated integer with <code>0 &lt; x &lt;
+ * q</code>.
+ */
+ private final BigInteger x;
+
+ /** String representation of this key. Cached for speed. */
+ private transient String str;
+
+ /**
+ * Convenience constructor. Calls the constructor with 5 arguments passing
+ * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred
+ * encoding format.
+ *
+ * @param p the public modulus.
+ * @param q the public prime divisor of <code>p-1</code>.
+ * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+ * <sub>p</sub></code>.
+ * @param x the private key part.
+ */
+ public DSSPrivateKey(BigInteger p, BigInteger q, BigInteger g, BigInteger x)
+ {
+ this(Registry.RAW_ENCODING_ID, p, q, g, x);
+ }
+
+ /**
+ * Constructs a new instance of a <code>DSSPrivateKey</code> given the
+ * designated arguments.
+ *
+ * @param preferredFormat the indetifier of the preferred encoding format to
+ * use when externalizing this key.
+ * @param p the public modulus.
+ * @param q the public prime divisor of <code>p-1</code>.
+ * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+ * <sub>p</sub></code>.
+ * @param x the private key part.
+ */
+ public DSSPrivateKey(int preferredFormat, BigInteger p, BigInteger q,
+ BigInteger g, BigInteger x)
+ {
+ super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID
+ : preferredFormat,
+ p, q, g);
+ this.x = x;
+ }
+
+ /**
+ * A class method that takes the output of the <code>encodePrivateKey()</code>
+ * method of a DSS keypair codec object (an instance implementing
+ * {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs
+ * an instance of this object.
+ *
+ * @param k the contents of a previously encoded instance of this object.
+ * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in
+ * <code>k</code>, to represent a valid encoding of an
+ * instance of this object.
+ * @exception IllegalArgumentException if the byte sequence does not represent
+ * a valid encoding of an instance of this object.
+ */
+ public static DSSPrivateKey valueOf(byte[] k)
+ {
+ // try RAW codec
+ if (k[0] == Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0])
+ try
+ {
+ return (DSSPrivateKey) new DSSKeyPairRawCodec().decodePrivateKey(k);
+ }
+ catch (IllegalArgumentException ignored)
+ {
+ }
+ // try PKCS#8 codec
+ return (DSSPrivateKey) new DSSKeyPairPKCS8Codec().decodePrivateKey(k);
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ /**
+ * Returns the encoded form of this private key according to the designated
+ * format.
+ *
+ * @param format the desired format identifier of the resulting encoding.
+ * @return the byte sequence encoding this key according to the designated
+ * format.
+ * @exception IllegalArgumentException if the format is not supported.
+ * @see DSSKeyPairRawCodec
+ */
+ public byte[] getEncoded(int format)
+ {
+ byte[] result;
+ switch (format)
+ {
+ case IKeyPairCodec.RAW_FORMAT:
+ result = new DSSKeyPairRawCodec().encodePrivateKey(this);
+ break;
+ case IKeyPairCodec.PKCS8_FORMAT:
+ result = new DSSKeyPairPKCS8Codec().encodePrivateKey(this);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported encoding format: "
+ + format);
+ }
+ return result;
+ }
+
+ /**
+ * Returns <code>true</code> if the designated object is an instance of
+ * {@link DSAPrivateKey} and has the same DSS (Digital Signature Standard)
+ * parameter values as this one.
+ *
+ * @param obj the other non-null DSS key to compare to.
+ * @return <code>true</code> if the designated object is of the same type
+ * and value as this one.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+
+ if (! (obj instanceof DSAPrivateKey))
+ return false;
+
+ DSAPrivateKey that = (DSAPrivateKey) obj;
+ return super.equals(that) && x.equals(that.getX());
+ }
+
+ public String toString()
+ {
+ if (str == null)
+ {
+ String ls = (String) AccessController.doPrivileged
+ (new GetPropertyAction("line.separator"));
+ str = new CPStringBuilder(this.getClass().getName()).append("(")
+ .append(super.toString()).append(",").append(ls)
+ .append("x=0x").append(Configuration.DEBUG ? x.toString(16)
+ : "**...*").append(ls)
+ .append(")")
+ .toString();
+ }
+ return str;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java
new file mode 100644
index 000000000..d7c1afe15
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java
@@ -0,0 +1,203 @@
+/* DSSPublicKey.java --
+ Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.lang.CPStringBuilder;
+
+import gnu.java.security.Registry;
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.key.IKeyPairCodec;
+
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPublicKey;
+
+/**
+ * An object that embodies a DSS (Digital Signature Standard) public key.
+ *
+ * @see #getEncoded
+ */
+public class DSSPublicKey
+ extends DSSKey
+ implements PublicKey, DSAPublicKey
+{
+ /**
+ * <code>y = g<sup>x</sup> mod p</code> where <code>x</code> is the
+ * private part of the DSA key.
+ */
+ private final BigInteger y;
+
+ /** String representation of this key. Cached for speed. */
+ private transient String str;
+
+ /**
+ * Conveience constructor. Calls the constructor with 5 arguments passing
+ * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred
+ * encoding format.
+ *
+ * @param p the public modulus.
+ * @param q the public prime divisor of <code>p-1</code>.
+ * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+ * <sub>p</sub></code>.
+ * @param y the public key part.
+ */
+ public DSSPublicKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y)
+ {
+ this(Registry.RAW_ENCODING_ID, p, q, g, y);
+ }
+
+ /**
+ * Constructs a new instance of <code>DSSPublicKey</code> given the
+ * designated arguments.
+ *
+ * @param preferredFormat the identifier of the preferred encoding format to
+ * use when externalizing this key.
+ * @param p the public modulus.
+ * @param q the public prime divisor of <code>p-1</code>.
+ * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+ * <sub>p</sub></code>.
+ * @param y the public key part.
+ */
+ public DSSPublicKey(int preferredFormat, BigInteger p, BigInteger q,
+ BigInteger g, BigInteger y)
+ {
+ super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID
+ : preferredFormat,
+ p, q, g);
+ this.y = y;
+ }
+
+ /**
+ * A class method that takes the output of the <code>encodePublicKey()</code>
+ * method of a DSS keypair codec object (an instance implementing
+ * {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs
+ * an instance of this object.
+ *
+ * @param k the contents of a previously encoded instance of this object.
+ * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in
+ * <code>k</code>, to represent a valid encoding of an
+ * instance of this object.
+ * @exception IllegalArgumentException if the byte sequence does not represent
+ * a valid encoding of an instance of this object.
+ */
+ public static DSSPublicKey valueOf(byte[] k)
+ {
+ // try RAW codec
+ if (k[0] == Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0])
+ try
+ {
+ return (DSSPublicKey) new DSSKeyPairRawCodec().decodePublicKey(k);
+ }
+ catch (IllegalArgumentException ignored)
+ {
+ }
+ // try X.509 codec
+ return (DSSPublicKey) new DSSKeyPairX509Codec().decodePublicKey(k);
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ /**
+ * Returns the encoded form of this public key according to the designated
+ * format.
+ *
+ * @param format the desired format identifier of the resulting encoding.
+ * @return the byte sequence encoding this key according to the designated
+ * format.
+ * @exception IllegalArgumentException if the format is not supported.
+ * @see DSSKeyPairRawCodec
+ */
+ public byte[] getEncoded(int format)
+ {
+ byte[] result;
+ switch (format)
+ {
+ case IKeyPairCodec.RAW_FORMAT:
+ result = new DSSKeyPairRawCodec().encodePublicKey(this);
+ break;
+ case IKeyPairCodec.X509_FORMAT:
+ result = new DSSKeyPairX509Codec().encodePublicKey(this);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported encoding format: "
+ + format);
+ }
+ return result;
+ }
+
+ /**
+ * Returns <code>true</code> if the designated object is an instance of
+ * {@link DSAPublicKey} and has the same DSS (Digital Signature Standard)
+ * parameter values as this one.
+ *
+ * @param obj the other non-null DSS key to compare to.
+ * @return <code>true</code> if the designated object is of the same type
+ * and value as this one.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+
+ if (! (obj instanceof DSAPublicKey))
+ return false;
+
+ DSAPublicKey that = (DSAPublicKey) obj;
+ return super.equals(that) && y.equals(that.getY());
+ }
+
+ public String toString()
+ {
+ if (str == null)
+ {
+ String ls = (String) AccessController.doPrivileged
+ (new GetPropertyAction("line.separator"));
+ str = new CPStringBuilder(this.getClass().getName()).append("(")
+ .append(super.toString()).append(",").append(ls)
+ .append("y=0x").append(y.toString(16)).append(ls)
+ .append(")")
+ .toString();
+ }
+ return str;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/key/dss/FIPS186.java b/libjava/classpath/gnu/java/security/key/dss/FIPS186.java
new file mode 100644
index 000000000..5d371e10c
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/key/dss/FIPS186.java
@@ -0,0 +1,262 @@
+/* FIPS186.java --
+ Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.security.key.dss;
+
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.util.PRNG;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * An implementation of the DSA parameters generation as described in FIPS-186.
+ * <p>
+ * References:
+ * <p>
+ * <a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
+ * Standard (DSS)</a>, Federal Information Processing Standards Publication
+ * 186. National Institute of Standards and Technology.
+ */
+public class FIPS186
+{
+ public static final int DSA_PARAMS_SEED = 0;
+
+ public static final int DSA_PARAMS_COUNTER = 1;
+
+ public static final int DSA_PARAMS_Q = 2;
+
+ public static final int DSA_PARAMS_P = 3;
+
+ public static final int DSA_PARAMS_E = 4;
+
+ public static final int DSA_PARAMS_G = 5;
+
+ /** The BigInteger constant 2. */
+ private static final BigInteger TWO = BigInteger.valueOf(2L);
+
+ private static final BigInteger TWO_POW_160 = TWO.pow(160);
+
+ /** The SHA instance to use. */
+ private Sha160 sha = new Sha160();
+
+ /** The length of the modulus of DSS keys generated by this instance. */
+ private int L;
+
+ /** The optional {@link SecureRandom} instance to use. */
+ private SecureRandom rnd = null;
+
+ /** Our default source of randomness. */
+ private PRNG prng = null;
+
+ public FIPS186(int L, SecureRandom rnd)
+ {
+ super();
+
+ this.L = L;
+ this.rnd = rnd;
+ }
+
+ /**
+ * This method generates the DSS <code>p</code>, <code>q</code>, and
+ * <code>g</code> parameters only when <code>L</code> (the modulus length)
+ * is not one of the following: <code>512</code>, <code>768</code> and
+ * <code>1024</code>. For those values of <code>L</code>, this
+ * implementation uses pre-computed values of <code>p</code>,
+ * <code>q</code>, and <code>g</code> given in the document <i>CryptoSpec</i>
+ * included in the security guide documentation of the standard JDK
+ * distribution.
+ * <p>
+ * The DSS requires two primes , <code>p</code> and <code>q</code>,
+ * satisfying the following three conditions:
+ * <ul>
+ * <li><code>2<sup>159</sup> &lt; q &lt; 2<sup>160</sup></code></li>
+ * <li><code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup></code> for a
+ * specified <code>L</code>, where <code>L = 512 + 64j</code> for some
+ * <code>0 &lt;= j &lt;= 8</code></li>
+ * <li>q divides p - 1.</li>
+ * </ul>
+ * The algorithm used to find these primes is as described in FIPS-186,
+ * section 2.2: GENERATION OF PRIMES. This prime generation scheme starts by
+ * using the {@link Sha160} and a user supplied <i>SEED</i> to construct a
+ * prime, <code>q</code>, in the range 2<sup>159</sup> &lt; q &lt; 2<sup>160</sup>.
+ * Once this is accomplished, the same <i>SEED</i> value is used to construct
+ * an <code>X</code> in the range <code>2<sup>L-1
+ * </sup> &lt; X &lt; 2<sup>L</sup>. The prime, <code>p</code>, is then
+ * formed by rounding <code>X</code> to a number congruent to <code>1 mod
+ * 2q</code>. In this implementation we use the same <i>SEED</i> value given
+ * in FIPS-186, Appendix 5.
+ */
+ public BigInteger[] generateParameters()
+ {
+ int counter, offset;
+ BigInteger SEED, alpha, U, q, OFFSET, SEED_PLUS_OFFSET, W, X, p, c, g;
+ byte[] a, u;
+ byte[] kb = new byte[20]; // to hold 160 bits of randomness
+
+ // Let L-1 = n*160 + b, where b and n are integers and 0 <= b < 160.
+ int b = (L - 1) % 160;
+ int n = (L - 1 - b) / 160;
+ BigInteger[] V = new BigInteger[n + 1];
+ algorithm: while (true)
+ {
+ step1: while (true)
+ {
+ // 1. Choose an arbitrary sequence of at least 160 bits and
+ // call it SEED.
+ nextRandomBytes(kb);
+ SEED = new BigInteger(1, kb).setBit(159).setBit(0);
+ // Let g be the length of SEED in bits. here always 160
+ // 2. Compute: U = SHA[SEED] XOR SHA[(SEED+1) mod 2**g]
+ alpha = SEED.add(BigInteger.ONE).mod(TWO_POW_160);
+ synchronized (sha)
+ {
+ a = SEED.toByteArray();
+ sha.update(a, 0, a.length);
+ a = sha.digest();
+ u = alpha.toByteArray();
+ sha.update(u, 0, u.length);
+ u = sha.digest();
+ }
+ for (int i = 0; i < a.length; i++)
+ a[i] ^= u[i];
+
+ U = new BigInteger(1, a);
+ // 3. Form q from U by setting the most significant bit (the
+ // 2**159 bit) and the least significant bit to 1. In terms of
+ // boolean operations, q = U OR 2**159 OR 1. Note that
+ // 2**159 < q < 2**160.
+ q = U.setBit(159).setBit(0);
+ // 4. Use a robust primality testing algorithm to test whether
+ // q is prime(1). A robust primality test is one where the
+ // probability of a non-prime number passing the test is at
+ // most 1/2**80.
+ // 5. If q is not prime, go to step 1.
+ if (q.isProbablePrime(80))
+ break step1;
+ } // step1
+ // 6. Let counter = 0 and offset = 2.
+ counter = 0;
+ offset = 2;
+ while (true)
+ {
+ OFFSET = BigInteger.valueOf(offset & 0xFFFFFFFFL);
+ SEED_PLUS_OFFSET = SEED.add(OFFSET);
+ // 7. For k = 0,...,n let V[k] = SHA[(SEED + offset + k) mod 2**g].
+ synchronized (sha)
+ {
+ for (int k = 0; k <= n; k++)
+ {
+ a = SEED_PLUS_OFFSET
+ .add(BigInteger.valueOf(k & 0xFFFFFFFFL))
+ .mod(TWO_POW_160).toByteArray();
+ sha.update(a, 0, a.length);
+ V[k] = new BigInteger(1, sha.digest());
+ }
+ }
+ // 8. Let W be the integer:
+ // V[0]+V[1]*2**160+...+V[n-1]*2**((n-1)*160)+(V[n]mod2**b)*2**(n*160)
+ // and let : X = W + 2**(L-1).
+ // Note that 0 <= W < 2**(L-1) and hence 2**(L-1) <= X < 2**L.
+ W = V[0];
+ for (int k = 1; k < n; k++)
+ W = W.add(V[k].multiply(TWO.pow(k * 160)));
+
+ W = W.add(V[n].mod(TWO.pow(b)).multiply(TWO.pow(n * 160)));
+ X = W.add(TWO.pow(L - 1));
+ // 9. Let c = X mod 2q and set p = X - (c - 1).
+ // Note that p is congruent to 1 mod 2q.
+ c = X.mod(TWO.multiply(q));
+ p = X.subtract(c.subtract(BigInteger.ONE));
+ // 10. If p < 2**(L-1), then go to step 13.
+ if (p.compareTo(TWO.pow(L - 1)) >= 0)
+ {
+ // 11. Perform a robust primality test on p.
+ // 12. If p passes the test performed in step 11, go to step 15.
+ if (p.isProbablePrime(80))
+ break algorithm;
+ }
+ // 13. Let counter = counter + 1 and offset = offset + n + 1.
+ counter++;
+ offset += n + 1;
+ // 14. If counter >= 4096 go to step 1, otherwise go to step 7.
+ if (counter >= 4096)
+ continue algorithm;
+ } // step7
+ } // algorithm
+ // compute g. from FIPS-186, Appendix 4:
+ // 1. Generate p and q as specified in Appendix 2.
+ // 2. Let e = (p - 1) / q
+ BigInteger e = p.subtract(BigInteger.ONE).divide(q);
+ BigInteger h = TWO;
+ BigInteger p_minus_1 = p.subtract(BigInteger.ONE);
+ g = TWO;
+ // 3. Set h = any integer, where 1 < h < p - 1 and
+ // h differs from any value previously tried
+ for (; h.compareTo(p_minus_1) < 0; h = h.add(BigInteger.ONE))
+ {
+ // 4. Set g = h**e mod p
+ g = h.modPow(e, p);
+ // 5. If g = 1, go to step 3
+ if (! g.equals(BigInteger.ONE))
+ break;
+ }
+ return new BigInteger[] { SEED, BigInteger.valueOf(counter), q, p, e, g };
+ }
+
+ /**
+ * Fills the designated byte array with random data.
+ *
+ * @param buffer the byte array to fill with random data.
+ */
+ private void nextRandomBytes(byte[] buffer)
+ {
+ if (rnd != null)
+ rnd.nextBytes(buffer);
+ else
+ getDefaultPRNG().nextBytes(buffer);
+ }
+
+ private PRNG getDefaultPRNG()
+ {
+ if (prng == null)
+ prng = PRNG.getInstance();
+
+ return prng;
+ }
+}