hello there,

the attached patch --already committed-- adds ASN.1 encoding and 
decoding capabilities to the RSA key-pair implementation.

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

        * gnu/java/security/key/rsa/RSAKeyPairX509Codec.java: New file.
        * gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java: Likewise.
        * gnu/java/security/key/rsa/RSAKeyPairGenerator.java
        (PREFERRED_ENCODING_FORMAT): New constant.
        (DEFAULT_ENCODING_FORMAT): Likewise.
        (preferredFormat): New field.
        (setup): Add support for preferred encoding format.
        (generate): Call key constructors with explicit format identifier.
        * gnu/java/security/key/rsa/GnuRSAPublicKey.java (GnuRSAPublicKey(2)): 
        Call constructor with 3 arguments..
        (GnuRSAPublicKey(3)): New constructor.
        (valueOf): Added support for ASN.1 format.
        (getEncoded): Likewise.
        * gnu/java/security/key/rsa/GnuRSAPrivateKey.java 
(GnuRSAPrivateKey(4)):
        Call constructor with 5 arguments.
        (GnuRSAPrivateKey(5)): New constructor.
        (GnuRSAPrivateKey(9)): New constructor.
        (valueOf): Added support for ASN.1 format.
        (getEncoded): Likewise.
        * gnu/java/security/key/rsa/GnuRSAKey.java (defaultFormat): New field.
        (GnuRSAKey): Modified constructor.
        (getFormat): Return preferred format identifier.
        * gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java
        (decodePrivateKey): Fixed documentation.
        Check Version field.
        * gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java
        (initialize(int,SecureRandom)): Set ASN.1 as the preferred encoding
        format.
        (initialize(AlgorithmParameterSpec,SecureRandom)): Likewise.
        * gnu/java/security/jce/sig/EncodedKeyFactory.java
        (engineGeneratePublic): Added support for RSA.
        (engineGeneratePrivate): Likewise.


cheers;
rsn
Index: EncodedKeyFactory.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java,v
retrieving revision 1.1
diff -u -r1.1 EncodedKeyFactory.java
--- EncodedKeyFactory.java	7 Feb 2006 12:06:48 -0000	1.1
+++ EncodedKeyFactory.java	9 Feb 2006 11:45:50 -0000
@@ -41,6 +41,8 @@
 import gnu.java.security.Registry;
 import gnu.java.security.key.dss.DSSPrivateKey;
 import gnu.java.security.key.dss.DSSPublicKey;
+import gnu.java.security.key.rsa.GnuRSAPrivateKey;
+import gnu.java.security.key.rsa.GnuRSAPublicKey;

 import java.security.InvalidKeyException;
 import java.security.InvalidParameterException;
@@ -79,7 +81,14 @@
       {
       }

-    // FIXME: try RSA
+    // try RSA
+    try
+    {
+      return GnuRSAPublicKey.valueOf(input);
+    }
+  catch (InvalidParameterException ignored)
+    {
+    }

     // FIXME: try DH

@@ -103,7 +112,14 @@
       {
       }

-    // FIXME: try RSA
+    // try RSA
+    try
+    {
+      return GnuRSAPrivateKey.valueOf(input);
+    }
+  catch (InvalidParameterException ignored)
+    {
+    }

     // FIXME: try DH

Index: RSAKeyPairGeneratorSpi.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java,v
retrieving revision 1.1
diff -u -r1.1 RSAKeyPairGeneratorSpi.java
--- RSAKeyPairGeneratorSpi.java	26 Jan 2006 02:25:10 -0000	1.1
+++ RSAKeyPairGeneratorSpi.java	9 Feb 2006 11:46:24 -0000
@@ -1,4 +1,4 @@
-/* RSAKeyPairGeneratorSpi.java --
+/* RSAKeyPairGeneratorSpi.java -- JCE RSA KeyPairGenerator Adapter
    Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.

 This file is a part of GNU Classpath.
@@ -84,6 +84,8 @@
         attributes.put(RSAKeyPairGenerator.SOURCE_OF_RANDOMNESS, random);
       }

+    attributes.put(RSAKeyPairGenerator.PREFERRED_ENCODING_FORMAT,
+                   new Integer(Registry.ASN1_ENCODING_ID));
     adaptee.setup(attributes);
   }

@@ -106,6 +108,8 @@
         attributes.put(RSAKeyPairGenerator.SOURCE_OF_RANDOMNESS, random);
       }

+    attributes.put(RSAKeyPairGenerator.PREFERRED_ENCODING_FORMAT,
+                   new Integer(Registry.ASN1_ENCODING_ID));
     adaptee.setup(attributes);
   }
 }
Index: DSSKeyPairPKCS8Codec.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java,v
retrieving revision 1.1
diff -u -r1.1 DSSKeyPairPKCS8Codec.java
--- DSSKeyPairPKCS8Codec.java	7 Feb 2006 12:06:48 -0000	1.1
+++ DSSKeyPairPKCS8Codec.java	9 Feb 2006 11:46:50 -0000
@@ -177,7 +177,7 @@

   /**
    * @param input the byte array to unmarshall into a valid DSS
-   *          [EMAIL PROTECTED] PublicKey} instance. MUST NOT be null.
+   *          [EMAIL PROTECTED] PrivateKey} instance. MUST NOT be null.
    * @return a new instance of a [EMAIL PROTECTED] DSSPrivateKey} decoded from the
    *         <i>PrivateKeyInfo</i> material fed as <code>input</code>.
    * @throw InvalidParameterException if an exception occurs during the
@@ -188,7 +188,7 @@
     if (input == null)
       throw new InvalidParameterException("Input bytes MUST NOT be null");

-    BigInteger p, q, g, x;
+    BigInteger version, p, q, g, x;
     DERReader der = new DERReader(input);
     try
       {
@@ -199,6 +199,10 @@
         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");

Index: GnuRSAKey.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/key/rsa/GnuRSAKey.java,v
retrieving revision 1.1
diff -u -r1.1 GnuRSAKey.java
--- GnuRSAKey.java	26 Jan 2006 02:25:11 -0000	1.1
+++ GnuRSAKey.java	9 Feb 2006 11:47:12 -0000
@@ -40,6 +40,7 @@

 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;
@@ -62,20 +63,29 @@
   /** The public exponent of an RSA key pair. */
   private final BigInteger e;

+  /**
+   * 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 n the public modulus <code>n</code>.
    * @param e the public exponent <code>e</code>.
    */
-  //   protected GnuRSAKey(BigInteger n) {
-  protected GnuRSAKey(final BigInteger n, final BigInteger e)
+  protected GnuRSAKey(int defaultFormat, BigInteger n, BigInteger e)
   {
     super();

+    this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID
+                                            : defaultFormat;
     this.n = n;
     this.e = e;
   }
@@ -108,7 +118,7 @@

   public String getFormat()
   {
-    return null;
+    return KeyPairCodecFactory.getEncodingShortName(defaultFormat);
   }

   // Other instance methods --------------------------------------------------
Index: GnuRSAPrivateKey.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java,v
retrieving revision 1.1
diff -u -r1.1 GnuRSAPrivateKey.java
--- GnuRSAPrivateKey.java	26 Jan 2006 02:25:11 -0000	1.1
+++ GnuRSAPrivateKey.java	9 Feb 2006 11:47:37 -0000
@@ -90,80 +90,119 @@
   // -------------------------------------------------------------------------

   /**
-   * <p>Trivial constructor.</p>
+   * Convenience constructor. Calls the constructor with 5 arguments passing
+   * [EMAIL PROTECTED] Registry#RAW_ENCODING_ID} as the identifier of the preferred
+   * encoding format.
    *
    * @param p the modulus first prime divisor.
    * @param q the modulus second prime divisor.
    * @param e the public exponent.
    * @param d the private exponent.
    */
-  public GnuRSAPrivateKey(final BigInteger p, final BigInteger q,
-                          final BigInteger e, final BigInteger d)
+  public GnuRSAPrivateKey(BigInteger p, BigInteger q, BigInteger e,
+                          BigInteger d)
   {
-    //      super(p.multiply(q));
-    super(p.multiply(q), e);
+    this(Registry.RAW_ENCODING_ID, p, q, e, d);
+  }

+  /**
+   * Constructs a new instance of a <code>GnuRSAPrivateKey</code> given the
+   * designated arguments.
+   *
+   * @param preferredFormat the indetifier of the preferred encoding format to
+   *          use when externalizing this key.
+   * @param p the modulus first prime divisor.
+   * @param q the modulus second prime divisor.
+   * @param e the public exponent.
+   * @param d the private exponent.
+   */
+  public GnuRSAPrivateKey(int preferredFormat, BigInteger p, BigInteger q,
+                          BigInteger e, BigInteger d)
+  {
+    this(preferredFormat, p.multiply(q), e, d, p, q,
+         e.modInverse(p.subtract(BigInteger.ONE)),
+         e.modInverse(q.subtract(BigInteger.ONE)),
+         q.modInverse(p));
+  }
+
+  /**
+   * Constructs a new instance of a <code>GnuRSAPrivateKey</code> given the
+   * designated arguments.
+   *
+   * @param preferredFormat the indetifier of the preferred encoding format to
+   *          use when externalizing this key.
+   * @param n the public modulus, which is also the product of <code>p</code>
+   * and <code>q</code>.
+   * @param e the public exponent.
+   * @param d the private exponent.
+   * @param p the modulus first prime divisor.
+   * @param q the modulus second prime divisor.
+   * @param dP the first prime's exponen. A positive integer less than
+   * <code>p</code> and <code>q</code>, satisfying <code>e * dP = 1 (mod p-1)
+   * </code>.
+   * @param dQ the second prime's exponent. A positive integer less than
+   * <code>p</code> and <code>q</code>, satisfying <code>e * dQ = 1 (mod p-1)
+   * </code>.
+   * @param qInv the Chinese Remainder Theorem coefiicient. A positive integer
+   * less than <code>p</code>, satisfying <code>q * qInv = 1 (mod p)</code>.
+   */
+  GnuRSAPrivateKey(int preferredFormat, BigInteger n, BigInteger e,
+                   BigInteger d, BigInteger p, BigInteger q, BigInteger dP,
+                   BigInteger dQ, BigInteger qInv)
+  {
+    super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID
+                                                       : preferredFormat,
+          n, e);
+
+    this.d = d;
     this.p = p;
     this.q = q;
-    //      this.e = e;
-    this.d = d;
-
     // the exponents dP and dQ are positive integers less than p and q
     // respectively satisfying
     //    e * dP = 1 (mod p-1);
     //    e * dQ = 1 (mod q-1),
-    dP = e.modInverse(p.subtract(BigInteger.ONE));
-    dQ = e.modInverse(q.subtract(BigInteger.ONE));
-    // and the CRT coefficient qInv is a positive integer less than p
-    // satisfying
+    this.dP = dP;
+    this.dQ = dQ;
+    // the CRT coefficient qInv is a positive integer less than p satisfying
     //    q * qInv = 1 (mod p).
-    qInv = q.modInverse(p);
+    this.qInv = qInv;
   }

   // Class methods
   // -------------------------------------------------------------------------

   /**
-   * <p>A class method that takes the output of the <code>encodePrivateKey()</code>
+   * A class method that takes the output of the <code>encodePrivateKey()</code>
    * method of an RSA keypair codec object (an instance implementing
-   * [EMAIL PROTECTED] gnu.crypto.key.IKeyPairCodec} for RSA keys, and re-constructs an
-   * instance of this object.</p>
-   *
+   * [EMAIL PROTECTED] IKeyPairCodec} for RSA keys, and re-constructs an instance of this
+   * object.
+   *
    * @param k the contents of a previously encoded instance of this object.
    * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in
-   * <code>k</code>, to represent a valid encoding of an instance of this object.
+   *           <code>k</code>, to represent a valid encoding of an instance
+   *           of this object.
    * @throws IllegalArgumentException if the byte sequence does not represent a
-   * valid encoding of an instance of this object.
+   *           valid encoding of an instance of this object.
    */
   public static GnuRSAPrivateKey valueOf(final 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_RSA_PRIVATE_KEY[0])
-      {
-        // it's likely to be in raw format. get a raw codec and hand it over
-        final IKeyPairCodec codec = new RSAKeyPairRawCodec();
-        return (GnuRSAPrivateKey) codec.decodePrivateKey(k);
-      }
-    else
-      {
-        throw new IllegalArgumentException("magic");
-      }
+      try
+        {
+          return (GnuRSAPrivateKey) new RSAKeyPairRawCodec().decodePrivateKey(k);
+        }
+      catch (IllegalArgumentException ignored)
+        {
+        }
+
+    // try PKCS#8 codec
+    return (GnuRSAPrivateKey) new RSAKeyPairPKCS8Codec().decodePrivateKey(k);
   }

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

-  // java.security.interfaces.RSAPrivateCrtKey interface implementation ------
-
-  //   public BigInteger getPublicExponent() {
-  //      return e;
-  //   }
-
   public BigInteger getPrimeP()
   {
     return p;
@@ -199,16 +238,17 @@
   // Other instance methods --------------------------------------------------

   /**
-   * <p>Returns the encoded form of this private key according to the
-   * designated format.</p>
+   * 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.
    * @throws IllegalArgumentException if the format is not supported.
-   * @see gnu.crypto.key.rsa.RSAKeyPairRawCodec
+   * @see RSAKeyPairRawCodec
+   * @see RSAKeyPairPKCS8Codec
    */
-  public byte[] getEncoded(final int format)
+  public byte[] getEncoded(int format)
   {
     final byte[] result;
     switch (format)
@@ -216,8 +256,12 @@
       case IKeyPairCodec.RAW_FORMAT:
         result = new RSAKeyPairRawCodec().encodePrivateKey(this);
         break;
+      case IKeyPairCodec.PKCS8_FORMAT:
+        result = new RSAKeyPairPKCS8Codec().encodePrivateKey(this);
+        break;
       default:
-        throw new IllegalArgumentException("format");
+        throw new IllegalArgumentException("Unsupported encoding format: "
+                                           + format);
       }
     return result;
   }
Index: GnuRSAPublicKey.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java,v
retrieving revision 1.1
diff -u -r1.1 GnuRSAPublicKey.java
--- GnuRSAPublicKey.java	26 Jan 2006 02:25:11 -0000	1.1
+++ GnuRSAPublicKey.java	9 Feb 2006 11:48:15 -0000
@@ -65,70 +65,73 @@
   // Constants and variables
   // -------------------------------------------------------------------------

-  /** The public exponent of an RSA public key. */
-  //   private final BigInteger e;
   // Constructor(s)
   // -------------------------------------------------------------------------
+
   /**
-   * <p>Trivial constructor.</p>
+   * Conveience constructor. Calls the constructor with 3 arguments passing
+   * [EMAIL PROTECTED] Registry#RAW_ENCODING_ID} as the identifier of the preferred
+   * encoding format.
    *
    * @param n the modulus.
    * @param e the public exponent.
    */
   public GnuRSAPublicKey(final BigInteger n, final BigInteger e)
   {
-    //      super(n);
-    super(n, e);
-    //
-    //      this.e = e;
+    this(Registry.RAW_ENCODING_ID, n, e);
+  }
+
+  /**
+   * Constructs a new instance of <code>GnuRSAPublicKey</code> given the
+   * designated arguments.
+   *
+   * @param preferredFormat the identifier of the preferred encoding format to
+   *          use when externalizing this key.
+   * @param n the modulus.
+   * @param e the public exponent.
+   */
+  public GnuRSAPublicKey(int preferredFormat, BigInteger n, BigInteger e)
+  {
+    super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID
+                                                       : preferredFormat,
+          n, e);
   }

   // Class methods
   // -------------------------------------------------------------------------

   /**
-   * <p>A class method that takes the output of the <code>encodePublicKey()</code>
+   * A class method that takes the output of the <code>encodePublicKey()</code>
    * method of an RSA keypair codec object (an instance implementing
-   * [EMAIL PROTECTED] gnu.crypto.key.IKeyPairCodec} for RSA keys, and re-constructs an
-   * instance of this object.</p>
-   *
+   * [EMAIL PROTECTED] IKeyPairCodec} for RSA keys, and re-constructs an instance of this
+   * object.
+   *
    * @param k the contents of a previously encoded instance of this object.
    * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in
-   * <code>k</code>, to represent a valid encoding of an instance of this object.
+   *           <code>k</code>, to represent a valid encoding of an instance
+   *           of this object.
    * @throws IllegalArgumentException if the byte sequence does not represent a
-   * valid encoding of an instance of this object.
+   *           valid encoding of an instance of this object.
    */
   public static GnuRSAPublicKey valueOf(final 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_RSA_PUBLIC_KEY[0])
-      {
-        // it's likely to be in raw format. get a raw codec and hand it over
-        final IKeyPairCodec codec = new RSAKeyPairRawCodec();
-        return (GnuRSAPublicKey) codec.decodePublicKey(k);
-      }
-    else
-      {
-        throw new IllegalArgumentException("magic");
-      }
+      try
+        {
+          return (GnuRSAPublicKey) new RSAKeyPairRawCodec().decodePublicKey(k);
+        }
+      catch (IllegalArgumentException ignored)
+        {
+        }
+
+    // try X.509 codec
+    return (GnuRSAPublicKey) new RSAKeyPairX509Codec().decodePublicKey(k);
   }

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

-  // java.security.interfaces.RSAPublicKey interface implementation ----------
-
-  //   public BigInteger getPublicExponent() {
-  //      return e;
-  //   }
-
-  // Other instance methods --------------------------------------------------
-
   /**
    * <p>Returns the encoded form of this public key according to the designated
    * format.</p>
@@ -147,8 +150,12 @@
       case IKeyPairCodec.RAW_FORMAT:
         result = new RSAKeyPairRawCodec().encodePublicKey(this);
         break;
+      case IKeyPairCodec.X509_FORMAT:
+        result = new RSAKeyPairX509Codec().encodePublicKey(this);
+        break;
       default:
-        throw new IllegalArgumentException("format");
+        throw new IllegalArgumentException("Unsupported encoding format: "
+                                           + format);
       }
     return result;
   }
@@ -172,7 +179,6 @@
         return false;
       }
     final RSAPublicKey that = (RSAPublicKey) obj;
-    //      return super.equals(that) && e.equals(that.getPublicExponent());
     return super.equals(that)
            && getPublicExponent().equals(that.getPublicExponent());
   }
Index: RSAKeyPairGenerator.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java,v
retrieving revision 1.2
diff -u -r1.2 RSAKeyPairGenerator.java
--- RSAKeyPairGenerator.java	3 Feb 2006 19:29:01 -0000	1.2
+++ RSAKeyPairGenerator.java	9 Feb 2006 11:48:49 -0000
@@ -95,9 +95,19 @@
    */
   public static final String RSA_PARAMETERS = "gnu.crypto.rsa.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 [EMAIL PROTECTED] Integer} that encapsulates an encoding format identifier.
+   */
+  public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.rsa.encoding";
+
   /** Default value for the modulus length. */
   private 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;
+
   /** The desired bit length of the modulus. */
   private int L;

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

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

@@ -159,6 +172,11 @@
       {
         throw new IllegalArgumentException(MODULUS_LENGTH);
       }
+
+    // what is the preferred encoding format
+    Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
+    preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT
+                                       : formatID.intValue();
   }

   /**
@@ -213,8 +231,8 @@
     d = e.modInverse(phi);

     // 5. Output the public key and the private key.
-    PublicKey pubK = new GnuRSAPublicKey(n, e);
-    PrivateKey secK = new GnuRSAPrivateKey(p, q, e, d);
+    PublicKey pubK = new GnuRSAPublicKey(preferredFormat, n, e);
+    PrivateKey secK = new GnuRSAPrivateKey(preferredFormat, p, q, e, d);

     return new KeyPair(pubK, secK);
   }
Index: RSAKeyPairPKCS8Codec.java
===================================================================
RCS file: RSAKeyPairPKCS8Codec.java
diff -N RSAKeyPairPKCS8Codec.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ RSAKeyPairPKCS8Codec.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,289 @@
+/* RSAKeyPairPKCS8Codec.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.rsa;
+
+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;
+
+/**
+ * An implementation of an [EMAIL PROTECTED] IKeyPairCodec} that knows how to encode /
+ * decode PKCS#8 ASN.1 external representation of RSA private keys.
+ */
+public class RSAKeyPairPKCS8Codec
+    implements IKeyPairCodec
+{
+  private static final OID RSA_ALG_OID = new OID(Registry.RSA_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;
+  }
+
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    throw new IllegalArgumentException("Wrong format for public keys");
+  }
+
+  /**
+   * Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of an RSA
+   * 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
+   *   }
+   * </pre>
+   *
+   * <p>The <i>privateKey</i> field, which is an OCTET STRING, contains the
+   * DER-encoded form of the RSA private key defined as:</p>
+   *
+   * <pre>
+   *   RSAPrivateKey ::= SEQUENCE {
+   *     version                 INTEGER, -- MUST be 0
+   *     modulus                 INTEGER, -- n
+   *     publicExponent          INTEGER, -- e
+   *     privateExponent         INTEGER, -- d
+   *     prime1                  INTEGER, -- p
+   *     prime2                  INTEGER, -- q
+   *     exponent1               INTEGER, -- d mod (p-1)
+   *     exponent2               INTEGER, -- d mod (q-1)
+   *     coefficient             INTEGER, -- (inverse of q) mod p
+   *   }
+   * </pre>
+   *
+   * @return the DER encoded form of the ASN.1 representation of the
+   *         <i>PrivateKeyInfo</i> field for an RSA [EMAIL PROTECTED] PrivateKey}..
+   * @throw InvalidParameterException if an error occurs during the marshalling
+   *        process.
+   */
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    if (! (key instanceof GnuRSAPrivateKey))
+      throw new IllegalArgumentException("Wrong key type");
+
+    GnuRSAPrivateKey pk = (GnuRSAPrivateKey) key;
+    BigInteger n = pk.getN();
+    BigInteger e = pk.getE();
+    BigInteger d = pk.getPrivateExponent();
+    BigInteger p = pk.getPrimeP();
+    BigInteger q = pk.getPrimeQ();
+    BigInteger dP = pk.getPrimeExponentP();
+    BigInteger dQ = pk.getPrimeExponentQ();
+    BigInteger qInv = pk.getCrtCoefficient();
+
+    DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+
+    DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, RSA_ALG_OID);
+
+    ArrayList algorithmID = new ArrayList(1);
+    algorithmID.add(derOID);
+    DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                           algorithmID);
+
+    DERValue derRSAVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+    DERValue derN = new DERValue(DER.INTEGER, n);
+    DERValue derE = new DERValue(DER.INTEGER, e);
+    DERValue derD = new DERValue(DER.INTEGER, d);
+    DERValue derP = new DERValue(DER.INTEGER, p);
+    DERValue derQ = new DERValue(DER.INTEGER, q);
+    DERValue derDP = new DERValue(DER.INTEGER, dP);
+    DERValue derDQ = new DERValue(DER.INTEGER, dQ);
+    DERValue derQInv = new DERValue(DER.INTEGER, qInv);
+
+    ArrayList rsaPrivateKey = new ArrayList();
+    rsaPrivateKey.add(derRSAVersion);
+    rsaPrivateKey.add(derN);
+    rsaPrivateKey.add(derE);
+    rsaPrivateKey.add(derD);
+    rsaPrivateKey.add(derP);
+    rsaPrivateKey.add(derQ);
+    rsaPrivateKey.add(derDP);
+    rsaPrivateKey.add(derDQ);
+    rsaPrivateKey.add(derQInv);
+    DERValue derRSAPrivateKey = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                             rsaPrivateKey);
+    byte[] pkBytes = derRSAPrivateKey.getEncoded();
+    DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, pkBytes);
+
+    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 x)
+      {
+        InvalidParameterException y = new InvalidParameterException();
+        y.initCause(x);
+        throw y;
+      }
+
+    return result;
+  }
+
+  public PublicKey decodePublicKey(byte[] input)
+  {
+    throw new IllegalArgumentException("Wrong format for public keys");
+  }
+
+  /**
+   * @param input the byte array to unmarshall into a valid RSA
+   *          [EMAIL PROTECTED] PrivateKey} instance. MUST NOT be null.
+   * @return a new instance of a [EMAIL PROTECTED] GnuRSAPrivateKey} 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, n, e, d, p, q, dP, dQ, qInv;
+    DERReader der = new DERReader(input);
+    try
+      {
+        DERValue derPKI = der.read();
+        checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field");
+
+        DERValue derVersion = der.read();
+        checkIsBigInteger(derVersion, "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(RSA_ALG_OID))
+          throw new InvalidParameterException("Unexpected OID: " + algOID);
+
+        DERValue val = der.read();
+        byte[] pkBytes = (byte[]) val.getValue();
+
+        der = new DERReader(pkBytes);
+        DERValue derRSAPrivateKey = der.read();
+        checkIsConstructed(derRSAPrivateKey, "Wrong RSAPrivateKey field");
+
+        val = der.read();
+        checkIsBigInteger(val, "Wrong RSAPrivateKey Version field");
+        version = (BigInteger) val.getValue();
+        if (version.compareTo(BigInteger.ZERO) != 0)
+          throw new InvalidParameterException("Unexpected RSAPrivateKey Version: "
+                                              + version);
+
+        val = der.read();
+        checkIsBigInteger(val, "Wrong modulus field");
+        n = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong publicExponent field");
+        e = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong privateExponent field");
+        d = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong prime1 field");
+        p = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong prime2 field");
+        q = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong exponent1 field");
+        dP = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong exponent2 field");
+        dQ = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong coefficient field");
+        qInv = (BigInteger) val.getValue();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException y = new InvalidParameterException();
+        y.initCause(x);
+        throw y;
+      }
+
+    return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, n, e, d, p, q,
+                                dP, dQ, qInv);
+  }
+}
Index: RSAKeyPairX509Codec.java
===================================================================
RCS file: RSAKeyPairX509Codec.java
diff -N RSAKeyPairX509Codec.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ RSAKeyPairX509Codec.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,237 @@
+/* RSAKeyPairX509Codec.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.rsa;
+
+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 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 [EMAIL PROTECTED] IKeyPairCodec} that knows how to encode /
+ * decode X.509 ASN.1 external representation of RSA public keys.
+ */
+public class RSAKeyPairX509Codec
+    implements IKeyPairCodec
+{
+  private static final OID RSA_ALG_OID = new OID(Registry.RSA_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 X.509 ASN.1 <i>SubjectPublicKeyInfo</i> representation of an
+   * RSA 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
+   *   }
+   * </pre>
+   *
+   * <p>The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+   * DER-encoded form of the RSA public key defined as:</p>
+   *
+   * <pre>
+   *   RSAPublicKey ::= SEQUENCE {
+   *     modulus         INTEGER, -- n
+   *     publicExponent  INTEGER  -- e
+   *   }
+   * </pre>
+   *
+   * @param key the [EMAIL PROTECTED] PublicKey} instance to encode. MUST be an instance of
+   *          [EMAIL PROTECTED] GnuRSAPublicKey}.
+   * @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 [EMAIL PROTECTED] GnuRSAPublicKey} or if an exception occurs during the
+   *        marshalling process.
+   */
+  public byte[] encodePublicKey(PublicKey key)
+  {
+    if (! (key instanceof GnuRSAPublicKey))
+      throw new InvalidParameterException("key");
+
+    DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, RSA_ALG_OID);
+
+    GnuRSAPublicKey rsaKey = (GnuRSAPublicKey) key;
+    BigInteger n = rsaKey.getN();
+    BigInteger e = rsaKey.getE();
+
+    DERValue derN = new DERValue(DER.INTEGER, n);
+    DERValue derE = new DERValue(DER.INTEGER, e);
+
+    ArrayList algorithmID = new ArrayList(1);
+    algorithmID.add(derOID);
+    DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                           algorithmID);
+
+    ArrayList publicKey = new ArrayList(2);
+    publicKey.add(derN);
+    publicKey.add(derE);
+    DERValue derPublicKey = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+                                         publicKey);
+    byte[] spkBytes = derPublicKey.getEncoded();
+    DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(spkBytes));
+
+    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 y = new InvalidParameterException();
+        y.initCause(x);
+        throw y;
+      }
+
+    return result;
+  }
+
+  public byte[] encodePrivateKey(PrivateKey key)
+  {
+    throw new IllegalArgumentException("Wrong format for private keys");
+  }
+
+  /**
+   * @param input the byte array to unmarshall into a valid RSA
+   *          [EMAIL PROTECTED] PublicKey} instance. MUST NOT be null.
+   * @return a new instance of a [EMAIL PROTECTED] GnuRSAPublicKey} 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 n, e;
+    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(RSA_ALG_OID))
+          throw new IllegalArgumentException("Unexpected OID: " + algOID);
+
+        DERValue val = der.read();
+        if (! (val.getValue() instanceof BitString))
+          throw new InvalidParameterException("Wrong SubjectPublicKey field");
+
+        byte[] spkBytes = ((BitString) val.getValue()).toByteArray();
+
+        der = new DERReader(spkBytes);
+        val = der.read();
+        checkIsConstructed(derAlgorithmID, "Wrong subjectPublicKey field");
+
+        val = der.read();
+        checkIsBigInteger(val, "Wrong modulus field");
+        n = (BigInteger) val.getValue();
+        val = der.read();
+        checkIsBigInteger(val, "Wrong publicExponent field");
+        e = (BigInteger) val.getValue();
+      }
+    catch (IOException x)
+      {
+        InvalidParameterException y = new InvalidParameterException();
+        y.initCause(x);
+        throw y;
+      }
+
+    return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e);
+  }
+
+  public PrivateKey decodePrivateKey(byte[] input)
+  {
+    throw new IllegalArgumentException("Wrong format for private keys");
+  }
+}

Attachment: pgpMjxkJL146z.pgp
Description: PGP signature

Reply via email to