hello there,

the attached patch --already committed-- adds support for ASN.1 DER 
encoding and decoding to DH keys.


2006-02-12  Raif S. Naffah  <[EMAIL PROTECTED]>

        * gnu/javax/crypto/key/dh/GnuDHPublicKey.java
        (GnuDHPublicKey(4)): Call constructor with 5 arguments.
        (GnuDHPublicKey): New constructor.
        (getEncoded): Removed.
        (valueOf): Added support for ASN.1 encoding.
        (getEncoded(int)): Likewise.
        (equals): New method.
        * gnu/javax/crypto/key/dh/GnuDHPrivateKey.java
        (GnuDHPrivateKey(4)): Call constructor with 5 arguments.
        (GnuDHPrivateKey(5)): New constructor.
        (getEncoded): Removed.
        (valueOf): Added support for ASN.1 encoding.
        (getEncoded(int)): Likewise.
        (equals): New method.
        * gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java
        (PREFERRED_ENCODING_FORMAT): New constant.
        (DEFAULT_ENCODING_FORMAT): Likewise.
        (preferredFormat): New field.
        (setup): Handle preferred encoding format identifier.
        (generate): Call constructors with format identifier.
        * gnu/javax/crypto/key/dh/GnuDHKey.java (defaultFormat): New field.
        (GnuDHKey): Added an int argument.
        (getEncoded): New method.
        (getFormat): New implementation.
        (getEncoded(int)): New abstract method.
        * gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java: New file.
        * gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java: Likewise.
        * gnu/javax/crypto/jce/GnuCrypto.java (run): Added mappings for DH
        key-pair generator and key-factory.
        * gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java: New file.
        * gnu/javax/crypto/jce/sig/DHKeyFactory.java: Likewise.
        * gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java: Made it 
public.
        * gnu/java/security/jce/sig/EncodedKeyFactory.java
        (invokeConstructor): New method.
        (getConcreteClass): Likewise.
        (getConcreteCtor): Likewise.
        (invokeValueOf): Likewise.
        (getValueOfMethod): Likewise.
        (engineGeneratePublic): Add support for DH keys.
        (engineGeneratePrivate): Likewise.
        (decodeDHPublicKey(DHPublicKeySpec)): New method.
        (decodeDHPublicKey(byte[])): Likewise.
        (decodeDHPrivateKey(DHPrivateKeySpec)): Likewise.
        (decodeDHPrivateKey(byte[])): Likewise.


the Mauve tests TestOfFormat and TestOfKeyFactory, both in 
gnu/testlet/gnu/java/security/jce, have been amended to test the above.


cheers;
rsn
Index: EncodedKeyFactory.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java,v
retrieving revision 1.3
diff -u -r1.3 EncodedKeyFactory.java
--- EncodedKeyFactory.java	11 Feb 2006 08:48:51 -0000	1.3
+++ EncodedKeyFactory.java	12 Feb 2006 08:21:13 -0000
@@ -44,6 +44,9 @@
 import gnu.java.security.key.rsa.GnuRSAPrivateKey;
 import gnu.java.security.key.rsa.GnuRSAPublicKey;

+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.math.BigInteger;
 import java.security.InvalidKeyException;
 import java.security.InvalidParameterException;
@@ -60,6 +63,11 @@
 import java.security.spec.RSAPublicKeySpec;
 import java.security.spec.X509EncodedKeySpec;

+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
 /**
  * A factory for keys encoded in either the X.509 format (for public keys) or
  * the PKCS#8 format (for private keys).
@@ -69,6 +77,118 @@
 {
   // implicit 0-arguments constructor

+  // Class methods
+  // --------------------------------------------------------------------------
+
+  private static Object invokeConstructor(String className, Object[] params)
+      throws InvalidKeySpecException
+  {
+    Class clazz = getConcreteClass(className);
+    try
+      {
+        Constructor ctor = getConcreteCtor(clazz);
+        Object result = ctor.newInstance(params);
+        return result;
+      }
+    catch (InstantiationException x)
+      {
+        InvalidKeySpecException y = new InvalidKeySpecException();
+        y.initCause(x);
+        throw y;
+      }
+    catch (IllegalAccessException x)
+      {
+        InvalidKeySpecException y = new InvalidKeySpecException();
+        y.initCause(y);
+        throw y;
+      }
+    catch (InvocationTargetException x)
+      {
+        InvalidKeySpecException y = new InvalidKeySpecException();
+        y.initCause(x);
+        throw y;
+      }
+  }
+
+  private static Class getConcreteClass(String className)
+      throws InvalidKeySpecException
+  {
+    try
+      {
+        Class result = Class.forName(className);
+        return result;
+      }
+    catch (ClassNotFoundException x)
+      {
+        InvalidKeySpecException y = new InvalidKeySpecException();
+        y.initCause(x);
+        throw y;
+      }
+  }
+
+  private static Constructor getConcreteCtor(Class clazz)
+      throws InvalidKeySpecException
+  {
+    try
+      {
+        Constructor result = clazz.getConstructor(new Class[] {int.class,
+                                                               BigInteger.class,
+                                                               BigInteger.class,
+                                                               BigInteger.class,
+                                                               BigInteger.class});
+        return result;
+      }
+    catch (NoSuchMethodException x)
+      {
+        InvalidKeySpecException y = new InvalidKeySpecException();
+        y.initCause(x);
+        throw y;
+      }
+  }
+
+  private static Object invokeValueOf(String className, byte[] encoded)
+      throws InvalidKeySpecException
+  {
+    Class clazz = getConcreteClass(className);
+    try
+      {
+        Method valueOf = getValueOfMethod(clazz);
+        Object result = valueOf.invoke(null, new Object[] { encoded });
+        return result;
+      }
+    catch (IllegalAccessException x)
+      {
+        InvalidKeySpecException y = new InvalidKeySpecException();
+        y.initCause(x);
+        throw y;
+      }
+    catch (InvocationTargetException x)
+      {
+        InvalidKeySpecException y = new InvalidKeySpecException();
+        y.initCause(x);
+        throw y;
+      }
+  }
+
+  private static Method getValueOfMethod(Class clazz)
+      throws InvalidKeySpecException
+  {
+    try
+      {
+        Method result = clazz.getMethod("valueOf", new Class[] {byte[].class});
+        return result;
+      }
+    catch (NoSuchMethodException x)
+      {
+        InvalidKeySpecException y = new InvalidKeySpecException();
+        y.initCause(x);
+        throw y;
+      }
+  }
+
+  // Instance methods
+  // --------------------------------------------------------------------------
+
   protected PublicKey engineGeneratePublic(KeySpec keySpec)
       throws InvalidKeySpecException
   {
@@ -78,6 +198,9 @@
     if (keySpec instanceof RSAPublicKeySpec)
       return decodeRSAPublicKey((RSAPublicKeySpec) keySpec);

+    if (keySpec instanceof DHPublicKeySpec)
+      return decodeDHPublicKey((DHPublicKeySpec) keySpec);
+
     if (! (keySpec instanceof X509EncodedKeySpec))
       throw new InvalidKeySpecException("Unsupported key specification");

@@ -101,9 +224,8 @@
       {
       }

-    // FIXME: try DH
-
-    throw new InvalidKeySpecException();
+    // try DH
+    return decodeDHPublicKey(input);
   }

   protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
@@ -115,6 +237,9 @@
     if (keySpec instanceof RSAPrivateCrtKeySpec)
       return decodeRSAPrivateKey((RSAPrivateCrtKeySpec) keySpec);

+    if (keySpec instanceof DHPrivateKeySpec)
+      return decodeDHPrivateKey((DHPrivateKeySpec) keySpec);
+
     if (! (keySpec instanceof PKCS8EncodedKeySpec))
       throw new InvalidKeySpecException("Unsupported key specification");

@@ -138,9 +263,8 @@
       {
       }

-    // FIXME: try DH
-
-    throw new InvalidKeySpecException();
+    // try DH
+    return decodeDHPrivateKey(input);
   }

   protected KeySpec engineGetKeySpec(Key key, Class keySpec)
@@ -191,6 +315,43 @@
   }

   /**
+   * @param spec an instance of [EMAIL PROTECTED] DHPublicKeySpec} to decode.
+   * @return an instance of a [EMAIL PROTECTED] DHPublicKey} constructed from the
+   *         information in the designated key-specification.
+   * @throws InvalidKeySpecException if no concrete implementation of the
+   *           [EMAIL PROTECTED] DHPublicKey} interface exists at run-time, or if an
+   *           exception occurs during its instantiation.
+   */
+  private DHPublicKey decodeDHPublicKey(DHPublicKeySpec spec)
+      throws InvalidKeySpecException
+  {
+    BigInteger p = spec.getP();
+    BigInteger g = spec.getG();
+    BigInteger y = spec.getY();
+    Object[] params = new Object[] {new Integer(Registry.X509_ENCODING_ID),
+                                    null, p, g, y};
+    Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPublicKey",
+                                   params);
+    return (DHPublicKey) obj;
+  }
+
+  /**
+   * @param encoded the bytes to decode.
+   * @return an instance of a [EMAIL PROTECTED] DHPublicKey} constructed from the
+   *         information in the designated key-specification.
+   * @throws InvalidKeySpecException if no concrete implementation of the
+   *           [EMAIL PROTECTED] DHPublicKey} interface exists at run-time, or if an
+   *           exception occurs during its instantiation.
+   */
+  private DHPublicKey decodeDHPublicKey(byte[] encoded)
+      throws InvalidKeySpecException
+  {
+    Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPublicKey",
+                               encoded);
+    return (DHPublicKey) obj;
+  }
+
+  /**
    * @param spec an instance of [EMAIL PROTECTED] DSAPrivateKeySpec} to decode.
    * @return an instance of [EMAIL PROTECTED] DSSPrivateKey} constructed from the
    * information in the designated key-specification.
@@ -222,4 +383,41 @@
     return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID,
                                 n, e, d, p, q, dP, dQ, qInv);
   }
+
+  /**
+   * @param spec an instance of [EMAIL PROTECTED] DHPrivateKeySpec} to decode.
+   * @return an instance of a [EMAIL PROTECTED] DHPrivateKey} constructed from the
+   *         information in the designated key-specification.
+   * @throws InvalidKeySpecException if no concrete implementation of the
+   *           [EMAIL PROTECTED] DHPrivateKey} interface exists at run-time, or if an
+   *           exception occurs during its instantiation.
+   */
+  private DHPrivateKey decodeDHPrivateKey(DHPrivateKeySpec spec)
+      throws InvalidKeySpecException
+  {
+    BigInteger p = spec.getP();
+    BigInteger g = spec.getG();
+    BigInteger x = spec.getX();
+    Object[] params = new Object[] {new Integer(Registry.PKCS8_ENCODING_ID),
+                                    null, p, g, x};
+    Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPrivateKey",
+                                   params);
+    return (DHPrivateKey) obj;
+  }
+
+  /**
+   * @param encoded the bytes to decode.
+   * @return an instance of a [EMAIL PROTECTED] DHPrivateKey} constructed from the
+   *         information in the designated key-specification.
+   * @throws InvalidKeySpecException if no concrete implementation of the
+   *           [EMAIL PROTECTED] DHPrivateKey} interface exists at run-time, or if an
+   *           exception occurs during its instantiation.
+   */
+  private DHPrivateKey decodeDHPrivateKey(byte[] encoded)
+      throws InvalidKeySpecException
+  {
+    Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPrivateKey",
+                               encoded);
+    return (DHPrivateKey) obj;
+  }
 }
Index: KeyPairGeneratorAdapter.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java,v
retrieving revision 1.2
diff -u -r1.2 KeyPairGeneratorAdapter.java
--- KeyPairGeneratorAdapter.java	4 Feb 2006 01:13:16 -0000	1.2
+++ KeyPairGeneratorAdapter.java	12 Feb 2006 08:28:51 -0000
@@ -66,7 +66,7 @@
  *
  * @version $Revision: 1.2 $
  */
-abstract class KeyPairGeneratorAdapter extends KeyPairGenerator
+public abstract class KeyPairGeneratorAdapter extends KeyPairGenerator
 {

   // Constants and variables
Index: DHKeyFactory.java
===================================================================
RCS file: DHKeyFactory.java
diff -N DHKeyFactory.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ DHKeyFactory.java	12 Feb 2006 08:31:31 -0000
@@ -0,0 +1,230 @@
+/* DHKeyFactory.java -- DH key-factory JCE Adapter
+   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.javax.crypto.jce.sig;
+
+import gnu.java.security.Registry;
+import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec;
+import gnu.javax.crypto.key.dh.DHKeyPairX509Codec;
+import gnu.javax.crypto.key.dh.GnuDHPrivateKey;
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+/**
+ * Implementation of a JCE Adapter for DH a key-factory.
+ */
+public class DHKeyFactory
+    extends KeyFactorySpi
+{
+  // implicit 0-arguments constructor
+
+  protected PublicKey engineGeneratePublic(KeySpec keySpec)
+      throws InvalidKeySpecException
+  {
+    if (keySpec instanceof DHPublicKeySpec)
+      {
+        DHPublicKeySpec spec = (DHPublicKeySpec) keySpec;
+        BigInteger p = spec.getP();
+        BigInteger g = spec.getG();
+        BigInteger y = spec.getY();
+        return new GnuDHPublicKey(Registry.X509_ENCODING_ID, null, p, g, y);
+      }
+
+    if (keySpec instanceof X509EncodedKeySpec)
+      {
+        X509EncodedKeySpec spec = (X509EncodedKeySpec) keySpec;
+        byte[] encoded = spec.getEncoded();
+        PublicKey result;
+        try
+          {
+            result = new DHKeyPairX509Codec().decodePublicKey(encoded);
+          }
+        catch (RuntimeException x)
+          {
+            InvalidKeySpecException y = new InvalidKeySpecException();
+            y.initCause(x);
+            throw y;
+          }
+      }
+
+    throw new InvalidKeySpecException("Unsupported (public) key specification");
+  }
+
+  protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+      throws InvalidKeySpecException
+  {
+    if (keySpec instanceof DHPrivateKeySpec)
+      {
+        DHPrivateKeySpec spec = (DHPrivateKeySpec) keySpec;
+        BigInteger p = spec.getP();
+        BigInteger g = spec.getG();
+        BigInteger x = spec.getX();
+        return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, null, p, g, x);
+      }
+
+    if (keySpec instanceof PKCS8EncodedKeySpec)
+      {
+        PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec;
+        byte[] encoded = spec.getEncoded();
+        PrivateKey result;
+        try
+          {
+            result = new DHKeyPairPKCS8Codec().decodePrivateKey(encoded);
+          }
+        catch (RuntimeException x)
+          {
+            InvalidKeySpecException y = new InvalidKeySpecException();
+            y.initCause(x);
+            throw y;
+          }
+      }
+
+    throw new InvalidKeySpecException("Unsupported (private) key specification");
+  }
+
+  protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+      throws InvalidKeySpecException
+  {
+    if (key instanceof DHPublicKey)
+      {
+        if (keySpec.isAssignableFrom(DHPublicKeySpec.class))
+          {
+            DHPublicKey dssKey = (DHPublicKey) key;
+            BigInteger p = dssKey.getParams().getP();
+            BigInteger g = dssKey.getParams().getG();
+            BigInteger y = dssKey.getY();
+            return new DHPublicKeySpec(y, p, g);
+          }
+
+        if (keySpec.isAssignableFrom(X509EncodedKeySpec.class))
+          {
+            if (key instanceof GnuDHPublicKey)
+              {
+                GnuDHPublicKey dhKey = (GnuDHPublicKey) key;
+                byte[] encoded = dhKey.getEncoded(Registry.X509_ENCODING_ID);
+                return new X509EncodedKeySpec(encoded);
+              }
+
+            if (Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat()))
+              {
+                byte[] encoded = key.getEncoded();
+                return new X509EncodedKeySpec(encoded);
+              }
+
+            throw new InvalidKeySpecException("Wrong key type or unsupported (public) key specification");
+          }
+
+        throw new InvalidKeySpecException("Unsupported (public) key specification");
+      }
+
+    if (key instanceof DHPrivateKey)
+      {
+        if (keySpec.isAssignableFrom(DHPrivateKeySpec.class))
+          {
+            DHPrivateKey dhKey = (DHPrivateKey) key;
+            BigInteger p = dhKey.getParams().getP();
+            BigInteger g = dhKey.getParams().getG();
+            BigInteger x = dhKey.getX();
+            return new DHPrivateKeySpec(x, p, g);
+          }
+
+        if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class))
+          {
+            if (key instanceof GnuDHPrivateKey)
+              {
+                GnuDHPrivateKey dhKey = (GnuDHPrivateKey) key;
+                byte[] encoded = dhKey.getEncoded(Registry.PKCS8_ENCODING_ID);
+                return new PKCS8EncodedKeySpec(encoded);
+              }
+
+            if (Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat()))
+              {
+                byte[] encoded = key.getEncoded();
+                return new PKCS8EncodedKeySpec(encoded);
+              }
+
+            throw new InvalidKeySpecException("Wrong key type or unsupported (private) key specification");
+          }
+
+        throw new InvalidKeySpecException("Unsupported (private) key specification");
+      }
+
+    throw new InvalidKeySpecException("Wrong key type or unsupported key specification");
+  }
+
+  protected Key engineTranslateKey(Key key) throws InvalidKeyException
+  {
+    if ((key instanceof GnuDHPublicKey) || (key instanceof GnuDHPrivateKey))
+      return key;
+
+    if (key instanceof DHPublicKey)
+      {
+        DHPublicKey dsaKey = (DHPublicKey) key;
+        BigInteger p = dsaKey.getParams().getP();
+        BigInteger g = dsaKey.getParams().getG();
+        BigInteger y = dsaKey.getY();
+        return new GnuDHPublicKey(Registry.X509_ENCODING_ID, null, p, g, y);
+      }
+
+    if (key instanceof DHPrivateKey)
+      {
+        DHPrivateKey dsaKey = (DHPrivateKey) key;
+        BigInteger p = dsaKey.getParams().getP();
+        BigInteger g = dsaKey.getParams().getG();
+        BigInteger x = dsaKey.getX();
+        return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, null, p, g, x);
+      }
+
+    throw new InvalidKeyException("Wrong key type");
+  }
+}
Index: DHKeyPairGeneratorSpi.java
===================================================================
RCS file: DHKeyPairGeneratorSpi.java
diff -N DHKeyPairGeneratorSpi.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ DHKeyPairGeneratorSpi.java	12 Feb 2006 08:32:18 -0000
@@ -0,0 +1,91 @@
+/* DHKeyPairGeneratorSpi.java -- DH key-pair generator JCE Adapter
+   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.javax.crypto.jce.sig;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+
+import javax.crypto.spec.DHGenParameterSpec;
+
+import gnu.java.security.Registry;
+import gnu.java.security.jce.sig.KeyPairGeneratorAdapter;
+import gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator;
+
+public class DHKeyPairGeneratorSpi
+    extends KeyPairGeneratorAdapter
+{
+  public DHKeyPairGeneratorSpi()
+  {
+    super(Registry.DH_KPG);
+  }
+
+  public void initialize(int keysize, SecureRandom random)
+  {
+    HashMap attributes = new HashMap();
+    attributes.put(GnuDHKeyPairGenerator.PRIME_SIZE, new Integer(keysize));
+    if (random != null)
+      attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random);
+
+    attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT,
+                   new Integer(Registry.ASN1_ENCODING_ID));
+    adaptee.setup(attributes);
+  }
+
+  public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+      throws InvalidAlgorithmParameterException
+  {
+    HashMap attributes = new HashMap();
+    if (params != null)
+      {
+        if (! (params instanceof DHGenParameterSpec))
+          throw new InvalidAlgorithmParameterException("params");
+
+        attributes.put(GnuDHKeyPairGenerator.DH_PARAMETERS, params);
+      }
+
+    if (random != null)
+      attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random);
+
+    attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT,
+                   new Integer(Registry.ASN1_ENCODING_ID));
+    adaptee.setup(attributes);
+  }
+}
Index: GnuCrypto.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/crypto/jce/GnuCrypto.java,v
retrieving revision 1.2
diff -u -r1.2 GnuCrypto.java
--- GnuCrypto.java	26 Jan 2006 19:23:57 -0000	1.2
+++ GnuCrypto.java	12 Feb 2006 08:36:52 -0000
@@ -556,6 +556,20 @@
         put("KeyStore.GKR", gnu.javax.crypto.jce.keyring.GnuKeyring.class.getName());
         put("Alg.Alias.KeyStore.GnuKeyring", "GKR");

+        // KeyPairGenerator ---------------------------------------------------
+        put("KeyPairGenerator.DH",
+            gnu.javax.crypto.jce.sig.DHKeyPairGeneratorSpi.class.getName());
+        put("KeyPairGenerator.DH KeySize", "512");
+        put("KeyPairGenerator.DH ImplementedIn", "Software");
+
+        put("Alg.Alias.KeyPairGenerator.DiffieHellman", "DH");
+
+        // KeyFactory ---------------------------------------------------------
+        put("KeyFactory.DH",
+            gnu.javax.crypto.jce.sig.DHKeyFactory.class.getName());
+
+        put("Alg.Alias,KeyFactory.DiffieHellman", "DH");
+
         return null;
       }
     });
Index: DHKeyPairPKCS8Codec.java
===================================================================
RCS file: DHKeyPairPKCS8Codec.java
diff -N DHKeyPairPKCS8Codec.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ DHKeyPairPKCS8Codec.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,240 @@
+/* DHKeyPairPKCS8Codec.java -- PKCS#8 encoder/decoder for DH keys
+   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.javax.crypto.key.dh;
+
+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 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.Util;
+
+public class DHKeyPairPKCS8Codec
+    implements IKeyPairCodec
+{
+  private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING);
+
+  // implicit 0-arguments constructor
+
+  private static void checkIsConstructed(DERValue v, String msg)
+  {
+    if (! v.isConstructed())
+      throw new InvalidParameterException(msg);
+  }
+
+  private static void checkIsBigInteger(DERValue v, String msg)
+  {
+    if (! (v.getValue() instanceof BigInteger))
+      throw new InvalidParameterException(msg);
+  }
+
+  public int getFormatID()
+  {
+    return PKCS8_FORMAT;
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    throw new InvalidParameterException("Wrong format for public keys");
+  }
+
+  /**
+   * Returns the DER-encoded form of the PKCS#8 ASN.1 <i>PrivateKeyInfo</i>
+   * representation of a DH 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
+   *   }
+   *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * </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 GnuDHPrivateKey))
+      throw new InvalidParameterException("Wrong key type");
+
+    DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+
+    DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID);
+
+    GnuDHPrivateKey pk = (GnuDHPrivateKey) key;
+    BigInteger p = pk.getParams().getP();
+    BigInteger g = pk.getParams().getG();
+    BigInteger q = pk.getQ();
+    BigInteger x = pk.getX();
+
+    ArrayList params = new ArrayList(3);
+    params.add(new DERValue(DER.INTEGER, p));
+    params.add(new DERValue(DER.INTEGER, g));
+    params.add(new DERValue(DER.INTEGER, q));
+    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);
+
+    DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, Util.trim(x));
+
+    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();
+        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 DH
+   *          [EMAIL PROTECTED] PrivateKey} instance. MUST NOT be null.
+   * @return a new instance of a [EMAIL PROTECTED] GnuDHPrivateKey} 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 (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();
+        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();
+        checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field");
+
+        DERValue derOID = der.read();
+        OID algOID = (OID) derOID.getValue();
+        if (! algOID.equals(DH_ALG_OID))
+          throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+        DERValue derParams = der.read();
+        checkIsConstructed(derParams, "Wrong DSS Parameters field");
+
+        DERValue val = der.read();
+        checkIsBigInteger(val, "Wrong P field");
+        p = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong G field");
+        g = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong Q field");
+        q = (BigInteger) val.getValue();
+
+        val = der.read();
+        byte[] xBytes = (byte[]) val.getValue();
+        x = new BigInteger(1, xBytes);
+      }
+    catch (IOException e)
+      {
+        InvalidParameterException y = new InvalidParameterException();
+        y.initCause(e);
+        throw y;
+      }
+
+    return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, q, p, g, x);
+  }
+}
Index: DHKeyPairX509Codec.java
===================================================================
RCS file: DHKeyPairX509Codec.java
diff -N DHKeyPairX509Codec.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ DHKeyPairX509Codec.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,255 @@
+/* DHKeyPairX509Codec.java -- X.509 DER encoder/decoder for DH keys
+   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.javax.crypto.key.dh;
+
+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 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;
+
+public class DHKeyPairX509Codec
+    implements IKeyPairCodec
+{
+  private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING);
+
+  // implicit 0-arguments constructor
+
+  private static void checkIsConstructed(DERValue v, String msg)
+  {
+    if (! v.isConstructed())
+      throw new InvalidParameterException(msg);
+  }
+
+  private static void checkIsBigInteger(DERValue v, String msg)
+  {
+    if (! (v.getValue() instanceof BigInteger))
+      throw new InvalidParameterException(msg);
+  }
+
+  public int getFormatID()
+  {
+    return X509_FORMAT;
+  }
+
+  /**
+   * Returns the DER-encoded form of the X.509 ASN.1 <i>SubjectPublicKeyInfo</i>
+   * representation of a DH 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
+   *   }
+   *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * </pre>
+   *
+   * <p>The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+   * DER-encoded form of the DH public key as an INTEGER.</p>
+   *
+   * <pre>
+   *       DHPublicKey ::= INTEGER -- public key, y = g^x mod p
+   * </pre>
+   *
+   * @param key the [EMAIL PROTECTED] PublicKey} instance to encode. MUST be an instance of
+   *          [EMAIL PROTECTED] GnuDHPublicKey}.
+   * @return the DER-encoded form of 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 [EMAIL PROTECTED] GnuDHPublicKey} or if an exception occurs during the
+   *        marshalling process.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    if (! (key instanceof GnuDHPublicKey))
+      throw new InvalidParameterException("Wrong key type");
+
+    DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID);
+
+    GnuDHPublicKey dhKey = (GnuDHPublicKey) key;
+    BigInteger p = dhKey.getParams().getP();
+    BigInteger g = dhKey.getParams().getG();
+    BigInteger q = dhKey.getQ();
+    BigInteger y = dhKey.getY();
+
+    DERValue derP = new DERValue(DER.INTEGER, p);
+    DERValue derG = new DERValue(DER.INTEGER, g);
+    DERValue derQ = new DERValue(DER.INTEGER, q);
+
+    ArrayList params = new ArrayList(3);
+    params.add(derP);
+    params.add(derG);
+    params.add(derQ);
+    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);
+
+    DERValue derDHPublicKey = new DERValue(DER.INTEGER, y);
+    byte[] yBytes = derDHPublicKey.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();
+        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 DH
+   *          [EMAIL PROTECTED] PublicKey} instance. MUST NOT be null.
+   * @return a new instance of a [EMAIL PROTECTED] GnuDHPublicKey} 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, g, q, y;
+    DERReader der = new DERReader(input);
+    try
+      {
+        DERValue derSPKI = der.read();
+        checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field");
+
+        DERValue derAlgorithmID = der.read();
+        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(DH_ALG_OID))
+          throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+        DERValue derParams = der.read();
+        checkIsConstructed(derParams, "Wrong DH Parameters field");
+
+        DERValue val = der.read();
+        checkIsBigInteger(val, "Wrong P field");
+        p = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong G field");
+        g = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong Q field");
+        q = (BigInteger) val.getValue();
+
+        val = der.read();
+        if (! (val.getValue() instanceof BitString))
+          throw new InvalidParameterException("Wrong SubjectPublicKey field");
+
+        byte[] yBytes = ((BitString) val.getValue()).toByteArray();
+
+        DERReader dhPub = new DERReader(yBytes);
+        val = dhPub.read();
+        checkIsBigInteger(val, "Wrong Y field");
+        y = (BigInteger) val.getValue();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException e = new InvalidParameterException();
+        e.initCause(x);
+        throw e;
+      }
+
+    return new GnuDHPublicKey(Registry.X509_ENCODING_ID, q, p, g, y);
+  }
+
+  /**
+   * @throws InvalidParameterException ALWAYS.
+   */
+  public PrivateKey decodePrivateKey(byte[] input)
+  {
+    throw new InvalidParameterException("Wrong format for private keys");
+  }
+}
Index: GnuDHKey.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java,v
retrieving revision 1.1
diff -u -r1.1 GnuDHKey.java
--- GnuDHKey.java	26 Jan 2006 02:25:09 -0000	1.1
+++ GnuDHKey.java	12 Feb 2006 08:41:54 -0000
@@ -39,6 +39,8 @@
 package gnu.javax.crypto.key.dh;

 import gnu.java.security.Registry;
+import gnu.java.security.key.IKeyPairCodec;
+import gnu.java.security.key.KeyPairCodecFactory;

 import java.math.BigInteger;
 import java.security.Key;
@@ -79,20 +81,30 @@
   /** The generator g. */
   protected BigInteger g;

+  /**
+   * Identifier of the default encoding format to use when externalizing the
+   * key material.
+   */
+  protected final int defaultFormat;
+
   // Constructor(s)
   // -------------------------------------------------------------------------

   /**
-   * <p>Trivial protected constructor.</p>
-   *
+   * Trivial protected constructor.
+   *
+   * @param defaultFormat the identifier of the encoding format to use by
+   *          default when externalizing the key.
    * @param q a prime divisor of p-1.
    * @param p the public prime.
    * @param g the generator of the group.
    */
-  protected GnuDHKey(BigInteger q, BigInteger p, BigInteger g)
+  protected GnuDHKey(int defaultFormat, BigInteger q, BigInteger p, BigInteger g)
   {
     super();

+    this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID
+                                            : defaultFormat;
     this.q = q;
     this.p = p;
     this.g = g;
@@ -125,9 +137,15 @@
     return Registry.DH_KPG;
   }

+  /** @deprecated see getEncoded(int). */
+  public byte[] getEncoded()
+  {
+    return getEncoded(IKeyPairCodec.RAW_FORMAT);
+  }
+
   public String getFormat()
   {
-    return null;
+    return KeyPairCodecFactory.getEncodingShortName(defaultFormat);
   }

   // Other instance methods --------------------------------------------------
@@ -160,4 +178,8 @@
     return p.equals(that.getParams().getP())
            && g.equals(that.getParams().getG());
   }
+
+  // abstract methods to be implemented by subclasses ------------------------
+
+  public abstract byte[] getEncoded(int format);
 }
Index: GnuDHKeyPairGenerator.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java,v
retrieving revision 1.2
diff -u -r1.2 GnuDHKeyPairGenerator.java
--- GnuDHKeyPairGenerator.java	3 Feb 2006 19:29:01 -0000	1.2
+++ GnuDHKeyPairGenerator.java	12 Feb 2006 08:42:46 -0000
@@ -103,6 +103,13 @@
   /** Property name of the size in bits (Integer) of the private exponent (x). */
   public static final String EXPONENT_SIZE = "gnu.crypto.dh.m";

+  /**
+   * 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 [EMAIL PROTECTED] Integer} that encapsulates an encoding format identifier.
+   */
+  public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dh.encoding";
+
   /** Default value for the size in bits of the public prime (p). */
   //   private static final int DEFAULT_PRIME_SIZE = 1024;
   private static final int DEFAULT_PRIME_SIZE = 512;
@@ -110,6 +117,9 @@
   /** Default value for the size in bits of the private exponent (x). */
   private static final int DEFAULT_EXPONENT_SIZE = 160;

+  /** Default encoding format to use when none was specified. */
+  private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID;
+
   /** The SHA instance to use. */
   private Sha160 sha = new Sha160();

@@ -137,6 +147,9 @@
   /** Our default source of randomness. */
   private PRNG prng = null;

+  /** Preferred encoding format of generated keys. */
+  private int preferredFormat;
+
   // Constructor(s)
   // -------------------------------------------------------------------------

@@ -191,6 +204,11 @@
       {
         throw new IllegalArgumentException("exponent size > modulus size");
       }
+
+    // what is the preferred encoding format
+    Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
+    preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT
+                                       : formatID.intValue();
   }

   public KeyPair generate()
@@ -231,8 +249,8 @@
       }
     BigInteger y = g.modPow(x, p);

-    PrivateKey secK = new GnuDHPrivateKey(q, p, g, x);
-    PublicKey pubK = new GnuDHPublicKey(q, p, g, y);
+    PrivateKey secK = new GnuDHPrivateKey(preferredFormat, q, p, g, x);
+    PublicKey pubK = new GnuDHPublicKey(preferredFormat, q, p, g, y);

     return new KeyPair(pubK, secK);
   }
Index: GnuDHPrivateKey.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java,v
retrieving revision 1.1
diff -u -r1.1 GnuDHPrivateKey.java
--- GnuDHPrivateKey.java	26 Jan 2006 02:25:09 -0000	1.1
+++ GnuDHPrivateKey.java	12 Feb 2006 08:46:40 -0000
@@ -42,6 +42,7 @@
 import gnu.java.security.key.IKeyPairCodec;

 import java.math.BigInteger;
+
 import javax.crypto.interfaces.DHPrivateKey;

 /**
@@ -66,9 +67,37 @@
   // Constructor(s)
   // -------------------------------------------------------------------------

+  /**
+   * Convenience constructor. Calls the constructor with five arguments passing
+   * [EMAIL PROTECTED] Registry#RAW_ENCODING_ID} as the value of its first argument.
+   *
+   * @param q a prime divisor of p-1.
+   * @param p the public prime.
+   * @param g the generator of the group.
+   * @param x the private value x.
+   */
   public GnuDHPrivateKey(BigInteger q, BigInteger p, BigInteger g, BigInteger x)
   {
-    super(q, p, g);
+    this(Registry.RAW_ENCODING_ID, q, p, g, x);
+  }
+
+  /**
+   * Constructs a new instance of <code>GnuDHPrivateKey</code> given the
+   * designated parameters.
+   *
+   * @param preferredFormat the identifier of the encoding format to use by
+   *          default when externalizing the key.
+   * @param q a prime divisor of p-1.
+   * @param p the public prime.
+   * @param g the generator of the group.
+   * @param x the private value x.
+   */
+  public GnuDHPrivateKey(int preferredFormat,
+                         BigInteger q, BigInteger p, BigInteger g, BigInteger x)
+  {
+    super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID
+                                                       : preferredFormat,
+          q, p, g);

     this.x = x;
   }
@@ -91,35 +120,23 @@
    */
   public static GnuDHPrivateKey valueOf(byte[] k)
   {
-    // check magic...
-    // we should parse here enough bytes to know which codec to use, and
-    // direct the byte array to the appropriate codec.  since we only have one
-    // codec, we could have immediately tried it; nevertheless since testing
-    // one byte is cheaper than instatiating a codec that will fail we test
-    // the first byte before we carry on.
+    // try RAW codec
     if (k[0] == Registry.MAGIC_RAW_DH_PRIVATE_KEY[0])
-      {
-        // it's likely to be in raw format. get a raw codec and hand it over
-        IKeyPairCodec codec = new DHKeyPairRawCodec();
-        return (GnuDHPrivateKey) codec.decodePrivateKey(k);
-      }
-    else
-      {
-        throw new IllegalArgumentException("magic");
-      }
+      try
+        {
+          return (GnuDHPrivateKey) new DHKeyPairRawCodec().decodePrivateKey(k);
+        }
+      catch (IllegalArgumentException ignored)
+        {
+        }
+
+    // try PKCS#8 codec
+    return (GnuDHPrivateKey) new DHKeyPairPKCS8Codec().decodePrivateKey(k);
   }

   // Instance methods
   // -------------------------------------------------------------------------

-  // java.security.Key interface implementation ------------------------------
-
-  /** @deprecated see getEncoded(int). */
-  public byte[] getEncoded()
-  {
-    return getEncoded(IKeyPairCodec.RAW_FORMAT);
-  }
-
   // javax.crypto.interfaces.DHPrivateKey interface implementation -----------

   public BigInteger getX()
@@ -147,9 +164,33 @@
       case IKeyPairCodec.RAW_FORMAT:
         result = new DHKeyPairRawCodec().encodePrivateKey(this);
         break;
+      case IKeyPairCodec.PKCS8_FORMAT:
+        result = new DHKeyPairPKCS8Codec().encodePrivateKey(this);
+        break;
       default:
-        throw new IllegalArgumentException("format");
+        throw new IllegalArgumentException("Unsupported encoding format: "
+                                           + format);
       }
     return result;
   }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * [EMAIL PROTECTED] DHPrivateKey} and has the same parameter values as this one.
+   *
+   * @param obj the other non-null DH 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 DHPrivateKey))
+      return false;
+
+    DHPrivateKey that = (DHPrivateKey) obj;
+    return super.equals(that) && x.equals(that.getX());
+  }
 }
Index: GnuDHPublicKey.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java,v
retrieving revision 1.1
diff -u -r1.1 GnuDHPublicKey.java
--- GnuDHPublicKey.java	26 Jan 2006 02:25:09 -0000	1.1
+++ GnuDHPublicKey.java	12 Feb 2006 08:51:30 -0000
@@ -66,9 +66,37 @@
   // Constructor(s)
   // -------------------------------------------------------------------------

+  /**
+   * Convenience constructor. Calls the constructor with five arguments passing
+   * [EMAIL PROTECTED] Registry#RAW_ENCODING_ID} as the value of its first argument.
+   *
+   * @param q a prime divisor of p-1.
+   * @param p the public prime.
+   * @param g the generator of the group.
+   * @param y the public value y.
+   */
   public GnuDHPublicKey(BigInteger q, BigInteger p, BigInteger g, BigInteger y)
   {
-    super(q, p, g);
+    this(Registry.RAW_ENCODING_ID, q, p, g, y);
+  }
+
+  /**
+   * Constructs a new instance of <code>GnuDHPublicKey</code> given the
+   * designated parameters.
+   *
+   * @param preferredFormat the identifier of the encoding format to use by
+   *          default when externalizing the key.
+   * @param q a prime divisor of p-1.
+   * @param p the public prime.
+   * @param g the generator of the group.
+   * @param y the public value y.
+   */
+  public GnuDHPublicKey(int preferredFormat,
+                        BigInteger q, BigInteger p, BigInteger g, BigInteger y)
+  {
+    super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID
+                                                       : preferredFormat,
+          q, p, g);

     this.y = y;
   }
@@ -91,35 +119,23 @@
    */
   public static GnuDHPublicKey valueOf(byte[] k)
   {
-    // check magic...
-    // we should parse here enough bytes to know which codec to use, and
-    // direct the byte array to the appropriate codec.  since we only have one
-    // codec, we could have immediately tried it; nevertheless since testing
-    // one byte is cheaper than instatiating a codec that will fail we test
-    // the first byte before we carry on.
+    // try RAW codec
     if (k[0] == Registry.MAGIC_RAW_DH_PUBLIC_KEY[0])
-      {
-        // it's likely to be in raw format. get a raw codec and hand it over
-        IKeyPairCodec codec = new DHKeyPairRawCodec();
-        return (GnuDHPublicKey) codec.decodePublicKey(k);
-      }
-    else
-      {
-        throw new IllegalArgumentException("magic");
-      }
+      try
+        {
+          return (GnuDHPublicKey) new DHKeyPairRawCodec().decodePublicKey(k);
+        }
+      catch (IllegalArgumentException ignored)
+        {
+        }
+
+    // try X.509 codec
+    return (GnuDHPublicKey) new DHKeyPairX509Codec().decodePublicKey(k);
   }

   // Instance methods
   // -------------------------------------------------------------------------

-  // java.security.Key interface implementation ------------------------------
-
-  /** @deprecated see getEncoded(int). */
-  public byte[] getEncoded()
-  {
-    return getEncoded(IKeyPairCodec.RAW_FORMAT);
-  }
-
   // javax.crypto.interfaces.DHPublicKey interface implementation ------------

   public BigInteger getY()
@@ -137,7 +153,6 @@
    * @return the byte sequence encoding this key according to the designated
    * format.
    * @exception IllegalArgumentException if the format is not supported.
-   * @see gnu.crypto.key.dh.DHKeyPairRawCodec
    */
   public byte[] getEncoded(int format)
   {
@@ -147,9 +162,33 @@
       case IKeyPairCodec.RAW_FORMAT:
         result = new DHKeyPairRawCodec().encodePublicKey(this);
         break;
+      case IKeyPairCodec.X509_FORMAT:
+        result = new DHKeyPairX509Codec().encodePublicKey(this);
+        break;
       default:
-        throw new IllegalArgumentException("format");
+        throw new IllegalArgumentException("Unsupported encoding format: "
+                                           + format);
       }
     return result;
   }
+
+  /**
+   * Returns <code>true</code> if the designated object is an instance of
+   * [EMAIL PROTECTED] DHPublicKey} and has the same parameter values as this one.
+   *
+   * @param obj the other non-null DH 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 DHPublicKey))
+      return false;
+
+    DHPublicKey that = (DHPublicKey) obj;
+    return super.equals(that) && y.equals(that.getY());
+  }
 }

Attachment: pgpoMNMf4M5jS.pgp
Description: PGP signature

Reply via email to