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"); + } +}
pgpMjxkJL146z.pgp
Description: PGP signature