From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- .../gnu/java/security/key/IKeyPairCodec.java | 124 +++++++ .../gnu/java/security/key/IKeyPairGenerator.java | 73 ++++ .../gnu/java/security/key/KeyPairCodecFactory.java | 360 +++++++++++++++++++ .../java/security/key/KeyPairGeneratorFactory.java | 120 +++++++ .../gnu/java/security/key/dss/DSSKey.java | 213 ++++++++++++ .../java/security/key/dss/DSSKeyPairGenerator.java | 382 +++++++++++++++++++++ .../security/key/dss/DSSKeyPairPKCS8Codec.java | 249 ++++++++++++++ .../java/security/key/dss/DSSKeyPairRawCodec.java | 347 +++++++++++++++++++ .../java/security/key/dss/DSSKeyPairX509Codec.java | 276 +++++++++++++++ .../gnu/java/security/key/dss/DSSPrivateKey.java | 205 +++++++++++ .../gnu/java/security/key/dss/DSSPublicKey.java | 203 +++++++++++ .../gnu/java/security/key/dss/FIPS186.java | 262 ++++++++++++++ .../gnu/java/security/key/rsa/GnuRSAKey.java | 178 ++++++++++ .../java/security/key/rsa/GnuRSAPrivateKey.java | 313 +++++++++++++++++ .../gnu/java/security/key/rsa/GnuRSAPublicKey.java | 190 ++++++++++ .../java/security/key/rsa/RSAKeyPairGenerator.java | 246 +++++++++++++ .../security/key/rsa/RSAKeyPairPKCS8Codec.java | 299 ++++++++++++++++ .../java/security/key/rsa/RSAKeyPairRawCodec.java | 300 ++++++++++++++++ .../java/security/key/rsa/RSAKeyPairX509Codec.java | 250 ++++++++++++++ 19 files changed, 4590 insertions(+) create mode 100644 libjava/classpath/gnu/java/security/key/IKeyPairCodec.java create mode 100644 libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java create mode 100644 libjava/classpath/gnu/java/security/key/KeyPairGeneratorFactory.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKey.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/FIPS186.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/GnuRSAKey.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java (limited to 'libjava/classpath/gnu/java/security/key') diff --git a/libjava/classpath/gnu/java/security/key/IKeyPairCodec.java b/libjava/classpath/gnu/java/security/key/IKeyPairCodec.java new file mode 100644 index 000000000..5c88c86ca --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/IKeyPairCodec.java @@ -0,0 +1,124 @@ +/* IKeyPairCodec.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import gnu.java.security.Registry; + +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * The visible methods of an object that knows how to encode and decode + * cryptographic asymmetric keypairs. Codecs are useful for (a) externalising + * public and private keys for storage and on-the-wire transmission, as well as + * (b) re-creating their internal Java representation from external sources. + */ +public interface IKeyPairCodec +{ + /** Constant identifying the Raw encoding format. */ + int RAW_FORMAT = Registry.RAW_ENCODING_ID; + + /** Constant identifying the X.509 encoding format. */ + int X509_FORMAT = Registry.X509_ENCODING_ID; + + /** Constant identifying the PKCS#8 encoding format. */ + int PKCS8_FORMAT = Registry.PKCS8_ENCODING_ID; + + /** + * Constant identifying the ASN.1 encoding format: a combined encoding + * of X.509 for public keys, and PKCS#8 for private ones. + */ + int ASN1_FORMAT = Registry.ASN1_ENCODING_ID; + + /** + * Returns the unique identifier (within this library) of the format used to + * externalise public and private keys. + * + * @return the identifier of the format, the object supports. + */ + int getFormatID(); + + /** + * Encodes an instance of a public key for storage or transmission purposes. + * + * @param key the non-null key to encode. + * @return a byte sequence representing the encoding of the designated key + * according to the format supported by this codec. + * @exception IllegalArgumentException if the designated key is not supported + * by this codec. + */ + byte[] encodePublicKey(PublicKey key); + + /** + * Encodes an instance of a private key for storage or transmission purposes. + * + * @param key the non-null key to encode. + * @return a byte sequence representing the encoding of the designated key + * according to the format supported by this codec. + * @exception IllegalArgumentException if the designated key is not supported + * by this codec. + */ + byte[] encodePrivateKey(PrivateKey key); + + /** + * Decodes an instance of an external public key into its native Java + * representation. + * + * @param input the source of the externalised key to decode. + * @return a concrete instance of a public key, reconstructed from the + * designated input. + * @exception IllegalArgumentException if the designated input does not + * contain a known representation of a public key for the format + * supported by the concrete codec. + */ + PublicKey decodePublicKey(byte[] input); + + /** + * Decodes an instance of an external private key into its native Java + * representation. + * + * @param input the source of the externalised key to decode. + * @return a concrete instance of a private key, reconstructed from the + * designated input. + * @exception IllegalArgumentException if the designated input does not + * contain a known representation of a private key for the format + * supported by the concrete codec. + */ + PrivateKey decodePrivateKey(byte[] input); +} diff --git a/libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java b/libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java new file mode 100644 index 000000000..72aac2463 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java @@ -0,0 +1,73 @@ +/* IKeyPairGenerator.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import java.security.KeyPair; +import java.util.Map; + +/** + * The visible methods of every asymmetric keypair generator. + */ +public interface IKeyPairGenerator +{ + /** + * Returns the canonical name of this keypair generator. + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * [Re]-initialises this instance for use with a given set of attributes. + * + * @param attributes a map of name/value pairs to use for setting up the + * instance. + * @exception IllegalArgumentException if at least one of the mandatory + * attributes is missing or an invalid value was specified. + */ + void setup(Map attributes); + + /** + * Generates a new keypair based on the attributes used to configure the + * instance. + * + * @return a new keypair. + */ + KeyPair generate(); +} diff --git a/libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java b/libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java new file mode 100644 index 000000000..d42866423 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java @@ -0,0 +1,360 @@ +/* KeyPairCodecFactory.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec; +import gnu.java.security.key.dss.DSSKeyPairRawCodec; +import gnu.java.security.key.dss.DSSKeyPairX509Codec; +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 gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec; +import gnu.java.security.key.rsa.RSAKeyPairRawCodec; +import gnu.java.security.key.rsa.RSAKeyPairX509Codec; +import gnu.java.security.util.FormatUtil; + +import java.lang.reflect.Constructor; +import java.security.Key; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory class to instantiate key encoder/decoder instances. + */ +public class KeyPairCodecFactory +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private KeyPairCodecFactory() + { + super(); + } + + /** + * Returns the appropriate codec given a composed key-pair generator algorithm + * and an encoding format. A composed name is formed by the concatenation of + * the canonical key-pair algorithm name, the forward slash character + * / and the canonical name of the encoding format. + *

+ * IMPORTANT: For backward compatibility, when the encoding format + * name is missing, the Raw encoding format is assumed. When this is the case + * the trailing forward slash is discarded from the name. + * + * @param name the case-insensitive key codec name. + * @return an instance of the keypair codec, or null if none + * found. + */ + public static IKeyPairCodec getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + if (name.length() == 0) + return null; + + if (name.startsWith("/")) + return null; + + if (name.endsWith("/")) + return getInstance(name.substring(0, name.length() - 1), + Registry.RAW_ENCODING_ID); + + int i = name.indexOf("/"); + if (i == -1) + return getInstance(name, Registry.RAW_ENCODING_ID); + + String kpgName = name.substring(0, i); + String formatName = name.substring(i + 1); + return getInstance(kpgName, formatName); + } + + /** + * Returns an instance of a keypair codec given the canonical name of the + * key-pair algorithm, and the name of the encoding format to use when + * externalizing the keys. + * + * @param name the case-insensitive key-pair algorithm name. + * @param format the name of the encoding format to use when externalizing the + * keys generated by the key-pair algorithm. + * @return an instance of the key-pair codec, or null if none + * found. + */ + public static IKeyPairCodec getInstance(String name, String format) + { + int formatID = FormatUtil.getFormatID(format); + if (formatID == 0) + return null; + + return getInstance(name, formatID); + } + + /** + * Returns an instance of a keypair codec given the canonical name of the + * key-pair algorithm, and the identifier of the format to use when + * externalizing the keys. + * + * @param name the case-insensitive key-pair algorithm name. + * @param formatID the identifier of the format to use when externalizing the + * keys generated by the key-pair algorithm. + * @return an instance of the key-pair codec, or null if none + * found. + */ + public static IKeyPairCodec getInstance(String name, int formatID) + { + if (name == null) + return null; + + name = name.trim(); + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + return getRawCodec(name); + case Registry.X509_ENCODING_ID: + return getX509Codec(name); + case Registry.PKCS8_ENCODING_ID: + return getPKCS8Codec(name); + } + + return null; + } + + /** + * Returns an instance of a keypair codec given a key. + * + * @param key the key to encode. + * @return an instance of the keypair codec, or null if none + * found. + */ + public static IKeyPairCodec getInstance(Key key) + { + if (key == null) + return null; + + String format = key.getFormat(); + int formatID = FormatUtil.getFormatID(format); + if (formatID == 0) + return null; + + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + return getRawCodec(key); + case Registry.X509_ENCODING_ID: + return getX509Codec(key); + case Registry.PKCS8_ENCODING_ID: + return getPKCS8Codec(key); + } + + return null; + } + + /** + * Returns a {@link Set} of supported key-pair codec names. + * + * @return a {@link Set} of the names of supported key-pair codec (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(Registry.DSS_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME); + hs.add(Registry.DSS_KPG + "/" + Registry.X509_ENCODING_SORT_NAME); + hs.add(Registry.DSS_KPG + "/" + Registry.PKCS8_ENCODING_SHORT_NAME); + hs.add(Registry.RSA_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME); + hs.add(Registry.RSA_KPG + "/" + Registry.X509_ENCODING_SORT_NAME); + hs.add(Registry.RSA_KPG + "/" + Registry.PKCS8_ENCODING_SHORT_NAME); + hs.add(Registry.DH_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME); + hs.add(Registry.SRP_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME); + names = Collections.unmodifiableSet(hs); + } + return names; + } + + private static IKeyPairCodec makeInstance (String clazz) + { + try + { + Class c = Class.forName (clazz); + Constructor ctor = c.getConstructor (new Class[0]); + return (IKeyPairCodec) ctor.newInstance (new Object[0]); + } + catch (Exception x) + { + IllegalArgumentException iae = + new IllegalArgumentException ("strong crypto key codec not available: " + + clazz); + iae.initCause (x); + throw iae; + } + } + + private static boolean matches (Object o, String clazz) + { + try + { + Class c = Class.forName (clazz); + return c.isAssignableFrom (o.getClass ()); + } + catch (Exception x) + { + // Can't match. + return false; + } + } + + /** + * @param name the trimmed name of a key-pair algorithm. + * @return a Raw format codec for the designated key-pair algorithm, or + * null if none exists. + */ + private static IKeyPairCodec getRawCodec(String name) + { + IKeyPairCodec result = null; + if (name.equalsIgnoreCase(Registry.DSA_KPG) + || name.equals(Registry.DSS_KPG)) + result = new DSSKeyPairRawCodec(); + else if (name.equalsIgnoreCase(Registry.RSA_KPG)) + result = new RSAKeyPairRawCodec(); + else if (name.equalsIgnoreCase(Registry.DH_KPG)) + result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairRawCodec"); + else if (name.equalsIgnoreCase(Registry.SRP_KPG)) + result = makeInstance("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec"); + + return result; + } + + /** + * @param name the trimmed name of a key-pair algorithm. + * @return a X.509 format codec for the designated key-pair algorithm, or + * null if none exists. + */ + private static IKeyPairCodec getX509Codec(String name) + { + IKeyPairCodec result = null; + if (name.equalsIgnoreCase(Registry.DSA_KPG) + || name.equals(Registry.DSS_KPG)) + result = new DSSKeyPairX509Codec(); + else if (name.equalsIgnoreCase(Registry.RSA_KPG)) + result = new RSAKeyPairX509Codec(); + else if (name.equalsIgnoreCase(Registry.DH_KPG)) + result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairX509Codec"); + + return result; + } + + /** + * @param name the trimmed name of a key-pair algorithm. + * @return a PKCS#8 format codec for the designated key-pair algorithm, or + * null if none exists. + */ + private static IKeyPairCodec getPKCS8Codec(String name) + { + IKeyPairCodec result = null; + if (name.equalsIgnoreCase(Registry.DSA_KPG) + || name.equals(Registry.DSS_KPG)) + result = new DSSKeyPairPKCS8Codec(); + else if (name.equalsIgnoreCase(Registry.RSA_KPG)) + result = new RSAKeyPairPKCS8Codec(); + else if (name.equalsIgnoreCase(Registry.DH_KPG)) + result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec"); + + return result; + } + + /** + * @param key a {@link Key} for which we want to return a Raw codec. + * @return the Raw codec corresponding to the key, or null if + * none exists for this key. + */ + private static IKeyPairCodec getRawCodec(Key key) + { + IKeyPairCodec result = null; + if ((key instanceof DSSPublicKey) || (key instanceof DSSPrivateKey)) + result = new DSSKeyPairRawCodec(); + else if ((key instanceof GnuRSAPublicKey) + || (key instanceof GnuRSAPrivateKey)) + result = new RSAKeyPairRawCodec(); + else if (matches(key, "gnu.javax.crypto.key.dh.GnuDHPublicKey") + || matches(key, "gnu.javax.crypto.key.dh.GnuDHPrivateKey")) + result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairRawCodec"); + else if (matches(key, "gnu.javax.crypto.key.srp6.SRPPublicKey") + || matches(key, "gnu.javax.crypto.key.srp6.SRPPrivateKey")) + result = makeInstance("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec"); + + return result; + } + + /** + * @param key a {@link Key} for which we want to return an X.509 codec. + * @return the X.509 codec corresponding to the key, or null if + * none exists for this key. + */ + private static IKeyPairCodec getX509Codec(Key key) + { + IKeyPairCodec result = null; + if (key instanceof DSSPublicKey) + result = new DSSKeyPairX509Codec(); + else if (key instanceof GnuRSAPublicKey) + result = new RSAKeyPairX509Codec(); + + return result; + } + + /** + * @param key a {@link Key} for which we want to return a PKCS#8 codec. + * @return the PKCS#8 codec corresponding to the key, or null if + * none exists for this key. + */ + private static IKeyPairCodec getPKCS8Codec(Key key) + { + IKeyPairCodec result = null; + if (key instanceof DSSPrivateKey) + result = new DSSKeyPairPKCS8Codec(); + else if (key instanceof GnuRSAPrivateKey) + result = new RSAKeyPairPKCS8Codec(); + + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/key/KeyPairGeneratorFactory.java b/libjava/classpath/gnu/java/security/key/KeyPairGeneratorFactory.java new file mode 100644 index 000000000..151cace39 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/KeyPairGeneratorFactory.java @@ -0,0 +1,120 @@ +/* KeyPairGeneratorFactory.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairGenerator; +import gnu.java.security.key.rsa.RSAKeyPairGenerator; + +import java.lang.reflect.Constructor; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory to instantiate asymmetric keypair generators. + */ +public class KeyPairGeneratorFactory +{ + /** Trivial constructor to enforce Singleton pattern. */ + private KeyPairGeneratorFactory() + { + super(); + } + + /** + * Returns an instance of a keypair generator given its name. + * + * @param name the case-insensitive key generator name. + * @return an instance of the keypair generator, or null if + * none found. + */ + public static IKeyPairGenerator getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + IKeyPairGenerator result = null; + if (name.equalsIgnoreCase(Registry.DSA_KPG) + || name.equalsIgnoreCase(Registry.DSS_KPG)) + result = new DSSKeyPairGenerator(); + else if (name.equalsIgnoreCase(Registry.RSA_KPG)) + result = new RSAKeyPairGenerator(); + else if (name.equalsIgnoreCase(Registry.DH_KPG)) + result = makeInstance("gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator"); + else if (name.equalsIgnoreCase(Registry.SRP_KPG)) + result = makeInstance("gnu.javax.crypto.key.srp6.SRPKeyPairGenerator"); + + return result; + } + + /** + * Returns a {@link Set} of keypair generator names supported by this + * Factory. Those keypair generators may be used in conjunction with + * the digital signature schemes with appendix supported by this library. + * + * @return a {@link Set} of keypair generator names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(Registry.DSS_KPG); + hs.add(Registry.DSA_KPG); + hs.add(Registry.RSA_KPG); + hs.add(Registry.DH_KPG); + hs.add(Registry.SRP_KPG); + return Collections.unmodifiableSet(hs); + } + + private static IKeyPairGenerator makeInstance(String clazz) + { + try + { + Class c = Class.forName(clazz); + Constructor ctor = c.getConstructor(new Class[0]); + return (IKeyPairGenerator) ctor.newInstance(new Object[0]); + } + catch (Exception x) + { + throw new IllegalArgumentException( + "strong crypto key pair generator not available: " + clazz, x); + } + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSKey.java new file mode 100644 index 000000000..49f229f7b --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKey.java @@ -0,0 +1,213 @@ +/* DSSKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.util.FormatUtil; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.Key; +import java.security.interfaces.DSAKey; +import java.security.interfaces.DSAParams; +import java.security.spec.DSAParameterSpec; + +/** + * A base asbtract class for both public and private DSS (Digital Signature + * Standard) keys. It encapsulates the three DSS numbers: p, + * q and g. + *

+ * According to the JDK, cryptographic Keys all have a format. + * The format used in this implementation is called Raw, and basically + * consists of the raw byte sequences of algorithm parameters. The exact order + * of the byte sequences and the implementation details are given in each of the + * relevant getEncoded() methods of each of the private and + * public keys. + *

+ * IMPORTANT: Under certain circumstances (e.g. in an X.509 certificate + * with inherited AlgorithmIdentifier's parameters of a SubjectPublicKeyInfo + * element) these three MPIs may be null. + * + * @see DSSPrivateKey#getEncoded + * @see DSSPublicKey#getEncoded + */ +public abstract class DSSKey + implements Key, DSAKey +{ + /** + * A prime modulus, where + * 2L-1 < p < 2L for + * 512 <= L <= 1024 and L a multiple of + * 64. + */ + protected final BigInteger p; + + /** + * A prime divisor of p - 1, where + * 2159 < q + * < 2160. + */ + protected final BigInteger q; + + /** + * g = h(p-1)/q mod p, where h is + * any integer with 1 < h < p - 1 such that h + * (p-1)/q mod p > 1 (g + * has order q mod p + * ). + */ + protected final BigInteger g; + + /** + * Identifier of the default encoding format to use when externalizing the key + * material. + */ + protected final int defaultFormat; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Trivial protected constructor. + * + * @param defaultFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param p the DSS parameter p. + * @param q the DSS parameter q. + * @param g the DSS parameter g. + */ + protected DSSKey(int defaultFormat, BigInteger p, BigInteger q, BigInteger g) + { + super(); + + this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID + : defaultFormat; + this.p = p; + this.q = q; + this.g = g; + } + + public DSAParams getParams() + { + return new DSAParameterSpec(p, q, g); + } + + public String getAlgorithm() + { + return Registry.DSS_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(defaultFormat); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + /** + * Returns true if the designated object is an instance of + * {@link DSAKey} and has the same DSS (Digital Signature Standard) parameter + * values as this one. + *

+ * Always returns false if the MPIs of this key are + * inherited. This may be the case when the key is re-constructed from + * an X.509 certificate with absent or NULL AlgorithmIdentifier's parameters + * field. + * + * @param obj the other non-null DSS key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (hasInheritedParameters()) + return false; + + if (obj == null) + return false; + + if (! (obj instanceof DSAKey)) + return false; + + DSAKey that = (DSAKey) obj; + return p.equals(that.getParams().getP()) + && q.equals(that.getParams().getQ()) + && g.equals(that.getParams().getG()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged(new GetPropertyAction("line.separator")); + CPStringBuilder sb = new CPStringBuilder(ls) + .append("defaultFormat=").append(defaultFormat).append(",") + .append(ls); + if (hasInheritedParameters()) + sb.append("p=inherited,").append(ls) + .append("q=inherited,").append(ls) + .append("g=inherited"); + else + sb.append("p=0x").append(p.toString(16)).append(",").append(ls) + .append("q=0x").append(q.toString(16)).append(",").append(ls) + .append("g=0x").append(g.toString(16)); + str = sb.toString(); + } + return str; + } + + public abstract byte[] getEncoded(int format); + + /** + * @return true if p, q and + * g are all null. Returns + * false otherwise. + */ + public boolean hasInheritedParameters() + { + return p == null && q == null && g == null; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java new file mode 100644 index 000000000..6bda4e88e --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java @@ -0,0 +1,382 @@ +/* DSSKeyPairGenerator.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.hash.Sha160; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.DSAParameterSpec; +import java.util.Map; +import java.util.logging.Logger; + +/** + * A key-pair generator for asymetric keys to use in conjunction with the DSS + * (Digital Signature Standard). + *

+ * References: + *

+ * Digital Signature + * Standard (DSS), Federal Information Processing Standards Publication + * 186. National Institute of Standards and Technology. + */ +public class DSSKeyPairGenerator + implements IKeyPairGenerator +{ + private static final Logger log = Logger.getLogger(DSSKeyPairGenerator.class.getName()); + + /** The BigInteger constant 2. */ + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** Property name of the length (Integer) of the modulus (p) of a DSS key. */ + public static final String MODULUS_LENGTH = "gnu.crypto.dss.L"; + + /** + * Property name of the Boolean indicating wether or not to use default pre- + * computed values of p, q and g + * for a given modulus length. The ultimate behaviour of this generator with + * regard to using pre-computed parameter sets will depend on the value of + * this property and of the following one {@link #STRICT_DEFAULTS}: + *

    + *
  1. If this property is {@link Boolean#FALSE} then this generator will + * accept being setup for generating parameters for any modulus length + * provided the modulus length is between 512 and + * 1024, and is of the form 512 + 64 * n. In + * addition, a new paramter set will always be generated; i.e. no pre- + * computed values are used.
  2. + *
  3. If this property is {@link Boolean#TRUE} and the value of + * {@link #STRICT_DEFAULTS} is also {@link Boolean#TRUE} then this generator + * will only accept being setup for generating parameters for modulus lengths + * of 512, 768 and 1024. Any + * other value, of the modulus length, even if between 512 and + * 1024, and of the form 512 + 64 * n, will + * cause an {@link IllegalArgumentException} to be thrown. When those modulus + * length (512, 768, and 1024) + * are specified, the paramter set is always the same.
  4. + *
  5. Finally, if this property is {@link Boolean#TRUE} and the value of + * {@link #STRICT_DEFAULTS} is {@link Boolean#FALSE} then this generator will + * behave as in point 1 above, except that it will use pre-computed values + * when possible; i.e. the modulus length is one of 512, + * 768, or 1024.
  6. + *
+ * The default value of this property is {@link Boolean#TRUE}. + */ + public static final String USE_DEFAULTS = "gnu.crypto.dss.use.defaults"; + + /** + * Property name of the Boolean indicating wether or not to generate new + * parameters, even if the modulus length L is not one of the pre- + * computed defaults (value {@link Boolean#FALSE}), or throw an exception + * (value {@link Boolean#TRUE}) -- the exception in this case is an + * {@link IllegalArgumentException}. The default value for this property is + * {@link Boolean#FALSE}. The ultimate behaviour of this generator will + * depend on the values of this and {@link #USE_DEFAULTS} properties -- see + * {@link #USE_DEFAULTS} for more information. + */ + public static final String STRICT_DEFAULTS = "gnu.crypto.dss.strict.defaults"; + + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dss.prng"; + + /** + * Property name of an optional {@link DSAParameterSpec} instance to use for + * this generator's p, q, and g + * values. The default is to generate these values or use pre-computed ones, + * depending on the value of the USE_DEFAULTS attribute. + */ + public static final String DSS_PARAMETERS = "gnu.crypto.dss.params"; + + /** + * Property name of the preferred encoding format to use when externalizing + * generated instance of key-pairs from this generator. The property is taken + * to be an {@link Integer} that encapsulates an encoding format identifier. + */ + public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dss.encoding"; + + /** Default value for the modulus length. */ + public static final int DEFAULT_MODULUS_LENGTH = 1024; + + /** Default encoding format to use when none was specified. */ + private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID; + + /** Initial SHS context. */ + private static final int[] T_SHS = new int[] { + 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 + }; + + // from jdk1.3.1/docs/guide/security/CryptoSpec.html#AppB + public static final DSAParameterSpec KEY_PARAMS_512 = new DSAParameterSpec( + new BigInteger( + "fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae" + + "01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16), + new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16), + new BigInteger( + "678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e" + + "35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16)); + public static final DSAParameterSpec KEY_PARAMS_768 = new DSAParameterSpec( + new BigInteger( + "e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d8901419" + + "22d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d77" + + "7d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16), + new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", 16), + new BigInteger( + "30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4" + + "dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d8" + + "3c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16)); + public static final DSAParameterSpec KEY_PARAMS_1024 = new DSAParameterSpec( + new BigInteger( + "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669" + + "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7" + + "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb" + + "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16), + new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16), + new BigInteger( + "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267" + + "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1" + + "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b" + + "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", 16)); + + private static final BigInteger TWO_POW_160 = TWO.pow(160); + + /** The length of the modulus of DSS keys generated by this instance. */ + private int L; + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + private BigInteger seed; + + private BigInteger counter; + + private BigInteger p; + + private BigInteger q; + + private BigInteger e; + + private BigInteger g; + + private BigInteger XKEY; + + /** Our default source of randomness. */ + private PRNG prng = null; + + /** Preferred encoding format of generated keys. */ + private int preferredFormat; + + public String name() + { + return Registry.DSS_KPG; + } + + /** + * Configures this instance. + * + * @param attributes the map of name/value pairs to use. + * @exception IllegalArgumentException if the designated MODULUS_LENGTH value + * is not greater than 512, less than 1024 and not of the form + * 512 + 64j. + */ + public void setup(Map attributes) + { + // find out the modulus length + Integer l = (Integer) attributes.get(MODULUS_LENGTH); + L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue()); + if ((L % 64) != 0 || L < 512 || L > 1024) + throw new IllegalArgumentException(MODULUS_LENGTH); + + // should we use the default pre-computed params? + Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS); + if (useDefaults == null) + useDefaults = Boolean.TRUE; + + Boolean strictDefaults = (Boolean) attributes.get(STRICT_DEFAULTS); + if (strictDefaults == null) + strictDefaults = Boolean.FALSE; + + // are we given a set of DSA params or we shall use/generate our own? + DSAParameterSpec params = (DSAParameterSpec) attributes.get(DSS_PARAMETERS); + if (params != null) + { + p = params.getP(); + q = params.getQ(); + g = params.getG(); + } + else if (useDefaults.equals(Boolean.TRUE)) + { + switch (L) + { + case 512: + p = KEY_PARAMS_512.getP(); + q = KEY_PARAMS_512.getQ(); + g = KEY_PARAMS_512.getG(); + break; + case 768: + p = KEY_PARAMS_768.getP(); + q = KEY_PARAMS_768.getQ(); + g = KEY_PARAMS_768.getG(); + break; + case 1024: + p = KEY_PARAMS_1024.getP(); + q = KEY_PARAMS_1024.getQ(); + g = KEY_PARAMS_1024.getG(); + break; + default: + if (strictDefaults.equals(Boolean.TRUE)) + throw new IllegalArgumentException( + "Does not provide default parameters for " + L + + "-bit modulus length"); + else + { + p = null; + q = null; + g = null; + } + } + } + else + { + p = null; + q = null; + g = null; + } + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // what is the preferred encoding format + Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT); + preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT + : formatID.intValue(); + // set the seed-key + byte[] kb = new byte[20]; // we need 160 bits of randomness + nextRandomBytes(kb); + XKEY = new BigInteger(1, kb).setBit(159).setBit(0); + } + + public KeyPair generate() + { + if (p == null) + { + BigInteger[] params = new FIPS186(L, rnd).generateParameters(); + seed = params[FIPS186.DSA_PARAMS_SEED]; + counter = params[FIPS186.DSA_PARAMS_COUNTER]; + q = params[FIPS186.DSA_PARAMS_Q]; + p = params[FIPS186.DSA_PARAMS_P]; + e = params[FIPS186.DSA_PARAMS_E]; + g = params[FIPS186.DSA_PARAMS_G]; + if (Configuration.DEBUG) + { + log.fine("seed: " + seed.toString(16)); + log.fine("counter: " + counter.intValue()); + log.fine("q: " + q.toString(16)); + log.fine("p: " + p.toString(16)); + log.fine("e: " + e.toString(16)); + log.fine("g: " + g.toString(16)); + } + } + BigInteger x = nextX(); + BigInteger y = g.modPow(x, p); + PublicKey pubK = new DSSPublicKey(preferredFormat, p, q, g, y); + PrivateKey secK = new DSSPrivateKey(preferredFormat, p, q, g, x); + return new KeyPair(pubK, secK); + } + + /** + * This method applies the following algorithm described in 3.1 of FIPS-186: + *
    + *
  1. XSEED = optional user input.
  2. + *
  3. XVAL = (XKEY + XSEED) mod 2b.
  4. + *
  5. x = G(t, XVAL) mod q.
  6. + *
  7. XKEY = (1 + XKEY + x) mod 2b.
  8. + *
+ *

+ * Where b is the length of a secret b-bit seed-key (XKEY). + *

+ * Note that in this implementation, XSEED, the optional user input, is always + * zero. + */ + private synchronized BigInteger nextX() + { + byte[] xk = XKEY.toByteArray(); + byte[] in = new byte[64]; // 512-bit block for SHS + System.arraycopy(xk, 0, in, 0, xk.length); + int[] H = Sha160.G(T_SHS[0], T_SHS[1], T_SHS[2], T_SHS[3], T_SHS[4], in, 0); + byte[] h = new byte[20]; + for (int i = 0, j = 0; i < 5; i++) + { + h[j++] = (byte)(H[i] >>> 24); + h[j++] = (byte)(H[i] >>> 16); + h[j++] = (byte)(H[i] >>> 8); + h[j++] = (byte) H[i]; + } + BigInteger result = new BigInteger(1, h).mod(q); + XKEY = XKEY.add(result).add(BigInteger.ONE).mod(TWO_POW_160); + return result; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java new file mode 100644 index 000000000..a59ca3cee --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java @@ -0,0 +1,249 @@ +/* DSSKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; +import gnu.java.security.util.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.logging.Logger; + +/** + * An implementation of an {@link IKeyPairCodec} that knows how to encode / + * decode PKCS#8 ASN.1 external representation of DSS private keys. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class DSSKeyPairPKCS8Codec + implements IKeyPairCodec +{ + private static final Logger log = Logger.getLogger(DSSKeyPairPKCS8Codec.class.getName()); + private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return PKCS8_FORMAT; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePublicKey(PublicKey key) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * Returns the PKCS#8 ASN.1 PrivateKeyInfo representation of a DSA + * private key. The ASN.1 specification is as follows: + * + *

+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * 
+ * + * @return the DER encoded form of the ASN.1 representation of the + * PrivateKeyInfo field in an X.509 certificate. + * @throw InvalidParameterException if an error occurs during the marshalling + * process. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof DSSPrivateKey)) + throw new InvalidParameterException("Wrong key type"); + + DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID); + + DSSPrivateKey pk = (DSSPrivateKey) key; + BigInteger p = pk.getParams().getP(); + BigInteger q = pk.getParams().getQ(); + BigInteger g = pk.getParams().getG(); + BigInteger x = pk.getX(); + + ArrayList params = new ArrayList(3); + params.add(new DERValue(DER.INTEGER, p)); + params.add(new DERValue(DER.INTEGER, q)); + params.add(new DERValue(DER.INTEGER, g)); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + // The OCTET STRING is the DER encoding of an INTEGER. + DERValue derX = new DERValue(DER.INTEGER, x); + DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, derX.getEncoded()); + + ArrayList pki = new ArrayList(3); + pki.add(derVersion); + pki.add(derAlgorithmID); + pki.add(derPrivateKey); + DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derPKI); + result = baos.toByteArray(); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(e.getMessage()); + y.initCause(e); + throw y; + } + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PublicKey decodePublicKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DSS + * {@link PrivateKey} instance. MUST NOT be null. + * @return a new instance of a {@link DSSPrivateKey} decoded from the + * PrivateKeyInfo material fed as input. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decodePrivateKey"); + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger version, p, q, g, x; + DERReader der = new DERReader(input); + try + { + DERValue derPKI = der.read(); + DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field"); + + DERValue derVersion = der.read(); + if (! (derVersion.getValue() instanceof BigInteger)) + throw new InvalidParameterException("Wrong Version field"); + + version = (BigInteger) derVersion.getValue(); + if (version.compareTo(BigInteger.ZERO) != 0) + throw new InvalidParameterException("Unexpected Version: " + version); + + DERValue derAlgoritmID = der.read(); + DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DSA_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + + val = der.read(); + if (Configuration.DEBUG) + log.fine("val = " + val); + byte[] xBytes = (byte[]) val.getValue(); + if (Configuration.DEBUG) + log.fine(Util.dumpString(xBytes, "xBytes: ")); + DERReader der2 = new DERReader(xBytes); + val = der2.read(); + DerUtil.checkIsBigInteger(val, "Wrong X field"); + x = (BigInteger) val.getValue(); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(e.getMessage()); + y.initCause(e); + throw y; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decodePrivateKey"); + return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java new file mode 100644 index 000000000..5b93c6b1e --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java @@ -0,0 +1,347 @@ +/* DSSKeyPairRawCodec.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * An object that implements the {@link IKeyPairCodec} operations for the + * Raw format to use with DSS keypairs. + */ +public class DSSKeyPairRawCodec + implements IKeyPairCodec +{ + // implicit 0-arguments constructor + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated DSS (Digital Signature Standard) + * public key according to the Raw format supported by this library. + *

+ * The Raw format for a DSA public key, in this implementation, is a + * byte sequence consisting of the following: + *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DSS_PUBLIC_KEY}, + *
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the DSA parameter + * p in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter p, + *
  8. + *
  9. 4-byte count of following bytes representing the DSA parameter + * q,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter q, + *
  12. + *
  13. 4-byte count of following bytes representing the DSA parameter + * g,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter g, + *
  16. + *
  17. 4-byte count of following bytes representing the DSA parameter + * y,
  18. + *
  19. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter y, + *
  20. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not a DSS + * (Digital Signature Standard) one. + * @see Registry#MAGIC_RAW_DSS_PUBLIC_KEY + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof DSSPublicKey)) + throw new IllegalArgumentException("key"); + + DSSPublicKey dssKey = (DSSPublicKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]); + baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[1]); + baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[2]); + baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[3]); + // version + baos.write(0x01); + // p + byte[] buffer = dssKey.getParams().getP().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // q + buffer = dssKey.getParams().getQ().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // g + buffer = dssKey.getParams().getG().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // y + buffer = dssKey.getY().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public PublicKey decodePublicKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0] + || k[1] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[1] + || k[2] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[2] + || k[3] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[3]) + throw new IllegalArgumentException("magic"); + + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + + int i = 5; + int l; + byte[] buffer; + // p + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + // q + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + // g + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + // y + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger y = new BigInteger(1, buffer); + return new DSSPublicKey(p, q, g, y); + } + + /** + * Returns the encoded form of the designated DSS (Digital Signature Standard) + * private key according to the Raw format supported by this library. + *

+ * The Raw format for a DSA private key, in this implementation, is a + * byte sequence consisting of the following: + *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DSS_PRIVATE_KEY}, + *
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the DSA parameter + * p in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter p, + *
  8. + *
  9. 4-byte count of following bytes representing the DSA parameter + * q,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter q, + *
  12. + *
  13. 4-byte count of following bytes representing the DSA parameter + * g,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter g, + *
  16. + *
  17. 4-byte count of following bytes representing the DSA parameter + * x,
  18. + *
  19. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter x, + *
  20. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not a DSS + * (Digital Signature Standard) one. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof DSSPrivateKey)) + throw new IllegalArgumentException("key"); + + DSSPrivateKey dssKey = (DSSPrivateKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]); + baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[1]); + baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[2]); + baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[3]); + // version + baos.write(0x01); + // p + byte[] buffer = dssKey.getParams().getP().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // q + buffer = dssKey.getParams().getQ().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // g + buffer = dssKey.getParams().getG().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // x + buffer = dssKey.getX().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public PrivateKey decodePrivateKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0] + || k[1] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[1] + || k[2] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[2] + || k[3] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[3]) + throw new IllegalArgumentException("magic"); + + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + + int i = 5; + int l; + byte[] buffer; + // p + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + // q + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + // g + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + // x + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger x = new BigInteger(1, buffer); + return new DSSPrivateKey(p, q, g, x); + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java new file mode 100644 index 000000000..8c26910f1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java @@ -0,0 +1,276 @@ +/* DSSKeyPairX509Codec.java -- X.509 Encoding/Decoding handler + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +/** + * An implementation of an {@link IKeyPairCodec} that knows how to encode / + * decode X.509 ASN.1 external representation of DSS public keys. + */ +public class DSSKeyPairX509Codec + implements IKeyPairCodec +{ + private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return X509_FORMAT; + } + + /** + * Returns the X.509 ASN.1 SubjectPublicKeyInfo representation of a + * DSA public key. The ASN.1 specification, as defined in RFC-3280, and + * RFC-2459, is as follows: + * + *
+   *   SubjectPublicKeyInfo ::= SEQUENCE {
+   *     algorithm         AlgorithmIdentifier,
+   *     subjectPublicKey  BIT STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * 
+ *

+ * Note that RFC-3280 (page 79) implies that some certificates MAY have an + * absent, or NULL, parameters field in their AlgorithmIdentifier element, + * implying that those parameters MUST be inherited from another + * certificate. This implementation, encodes a NULL element as the DER + * value of the parameters field when such is the case. + *

+ * The subjectPublicKey field, which is a BIT STRING, contains the + * DER-encoded form of the DSA public key as an INTEGER. + * + *

+   *       DSAPublicKey ::= INTEGER -- public key, Y
+   * 
+ * + * @param key the {@link PublicKey} instance to encode. MUST be an instance of + * {@link DSSPublicKey}. + * @return the ASN.1 representation of the SubjectPublicKeyInfo in an + * X.509 certificate. + * @throw InvalidParameterException if key is not an instance + * of {@link DSSPublicKey} or if an exception occurs during the + * marshalling process. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof DSSPublicKey)) + throw new InvalidParameterException("key"); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID); + + DSSPublicKey dssKey = (DSSPublicKey) key; + DERValue derParams; + if (dssKey.hasInheritedParameters()) + derParams = new DERValue(DER.NULL, null); + else + { + BigInteger p = dssKey.getParams().getP(); + BigInteger q = dssKey.getParams().getQ(); + BigInteger g = dssKey.getParams().getG(); + + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derQ = new DERValue(DER.INTEGER, q); + DERValue derG = new DERValue(DER.INTEGER, g); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derQ); + params.add(derG); + derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + } + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + BigInteger y = dssKey.getY(); + DERValue derDSAPublicKey = new DERValue(DER.INTEGER, y); + byte[] yBytes = derDSAPublicKey.getEncoded(); + DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes)); + + ArrayList spki = new ArrayList(2); + spki.add(derAlgorithmID); + spki.add(derSPK); + DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derSPKI); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(x.getMessage()); + e.initCause(x); + throw e; + } + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + throw new InvalidParameterException("Wrong format for private keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DSS + * {@link PublicKey} instance. MUST NOT be null. + * @return a new instance of a {@link DSSPublicKey} decoded from the + * SubjectPublicKeyInfo material in an X.509 certificate. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PublicKey decodePublicKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger p = null; + BigInteger g = null; + BigInteger q = null; + BigInteger y; + DERReader der = new DERReader(input); + try + { + DERValue derSPKI = der.read(); + DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); + + DERValue derAlgorithmID = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + if (! (derOID.getValue() instanceof OID)) + throw new InvalidParameterException("Wrong Algorithm field"); + + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DSA_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue val = der.read(); + // RFC-3280, page 79 states: "If the subjectPublicKeyInfo field of the + // certificate contains an algorithm field with null parameters or + // parameters are omitted, compare the certificate subjectPublicKey + // algorithm to the working_public_key_algorithm. If the certificate + // subjectPublicKey algorithm and the working_public_key_algorithm are + // different, set the working_public_key_parameters to null." + // in other words, the parameters field of an AlgorithmIdentifier + // element MAY NOT be present at all, or if present MAY be NULL! + // the Mauve test ValidDSAParameterInheritenceTest5, in + // gnu.testlet.java.security.cert.pkix.pkits, is/was failing because + // of this. + if (val.getTag() == DER.NULL) + val = der.read(); + else if (val.isConstructed()) + { + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + + val = der.read(); + } + + if (! (val.getValue() instanceof BitString)) + throw new InvalidParameterException("Wrong SubjectPublicKey field"); + + byte[] yBytes = ((BitString) val.getValue()).toByteArray(); + + DERReader dsaPub = new DERReader(yBytes); + val = dsaPub.read(); + DerUtil.checkIsBigInteger(val, "Wrong Y field"); + y = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(x.getMessage()); + e.initCause(x); + throw e; + } + return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for private keys"); + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java new file mode 100644 index 000000000..de3668c01 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java @@ -0,0 +1,205 @@ +/* DSSPrivateKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.PrivateKey; +import java.security.interfaces.DSAPrivateKey; + +/** + * An object that embodies a DSS (Digital Signature Standard) private key. + * + * @see #getEncoded + */ +public class DSSPrivateKey + extends DSSKey + implements PrivateKey, DSAPrivateKey +{ + /** + * A randomly or pseudorandomly generated integer with 0 < x < + * q. + */ + private final BigInteger x; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Convenience constructor. Calls the constructor with 5 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param x the private key part. + */ + public DSSPrivateKey(BigInteger p, BigInteger q, BigInteger g, BigInteger x) + { + this(Registry.RAW_ENCODING_ID, p, q, g, x); + } + + /** + * Constructs a new instance of a DSSPrivateKey given the + * designated arguments. + * + * @param preferredFormat the indetifier of the preferred encoding format to + * use when externalizing this key. + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param x the private key part. + */ + public DSSPrivateKey(int preferredFormat, BigInteger p, BigInteger q, + BigInteger g, BigInteger x) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID + : preferredFormat, + p, q, g); + this.x = x; + } + + /** + * A class method that takes the output of the encodePrivateKey() + * method of a DSS keypair codec object (an instance implementing + * {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs + * an instance of this object. + * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an + * instance of this object. + * @exception IllegalArgumentException if the byte sequence does not represent + * a valid encoding of an instance of this object. + */ + public static DSSPrivateKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]) + try + { + return (DSSPrivateKey) new DSSKeyPairRawCodec().decodePrivateKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try PKCS#8 codec + return (DSSPrivateKey) new DSSKeyPairPKCS8Codec().decodePrivateKey(k); + } + + public BigInteger getX() + { + return x; + } + + /** + * Returns the encoded form of this private key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + * @see DSSKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DSSKeyPairRawCodec().encodePrivateKey(this); + break; + case IKeyPairCodec.PKCS8_FORMAT: + result = new DSSKeyPairPKCS8Codec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of + * {@link DSAPrivateKey} and has the same DSS (Digital Signature Standard) + * parameter values as this one. + * + * @param obj the other non-null DSS key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof DSAPrivateKey)) + return false; + + DSAPrivateKey that = (DSAPrivateKey) obj; + return super.equals(that) && x.equals(that.getX()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("x=0x").append(Configuration.DEBUG ? x.toString(16) + : "**...*").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java new file mode 100644 index 000000000..d7c1afe15 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java @@ -0,0 +1,203 @@ +/* DSSPublicKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.PublicKey; +import java.security.interfaces.DSAPublicKey; + +/** + * An object that embodies a DSS (Digital Signature Standard) public key. + * + * @see #getEncoded + */ +public class DSSPublicKey + extends DSSKey + implements PublicKey, DSAPublicKey +{ + /** + * y = gx mod p where x is the + * private part of the DSA key. + */ + private final BigInteger y; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Conveience constructor. Calls the constructor with 5 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param y the public key part. + */ + public DSSPublicKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y) + { + this(Registry.RAW_ENCODING_ID, p, q, g, y); + } + + /** + * Constructs a new instance of DSSPublicKey given the + * designated arguments. + * + * @param preferredFormat the identifier of the preferred encoding format to + * use when externalizing this key. + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param y the public key part. + */ + public DSSPublicKey(int preferredFormat, BigInteger p, BigInteger q, + BigInteger g, BigInteger y) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID + : preferredFormat, + p, q, g); + this.y = y; + } + + /** + * A class method that takes the output of the encodePublicKey() + * method of a DSS keypair codec object (an instance implementing + * {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs + * an instance of this object. + * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an + * instance of this object. + * @exception IllegalArgumentException if the byte sequence does not represent + * a valid encoding of an instance of this object. + */ + public static DSSPublicKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]) + try + { + return (DSSPublicKey) new DSSKeyPairRawCodec().decodePublicKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try X.509 codec + return (DSSPublicKey) new DSSKeyPairX509Codec().decodePublicKey(k); + } + + public BigInteger getY() + { + return y; + } + + /** + * Returns the encoded form of this public key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + * @see DSSKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DSSKeyPairRawCodec().encodePublicKey(this); + break; + case IKeyPairCodec.X509_FORMAT: + result = new DSSKeyPairX509Codec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of + * {@link DSAPublicKey} and has the same DSS (Digital Signature Standard) + * parameter values as this one. + * + * @param obj the other non-null DSS key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof DSAPublicKey)) + return false; + + DSAPublicKey that = (DSAPublicKey) obj; + return super.equals(that) && y.equals(that.getY()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("y=0x").append(y.toString(16)).append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/FIPS186.java b/libjava/classpath/gnu/java/security/key/dss/FIPS186.java new file mode 100644 index 000000000..5d371e10c --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/FIPS186.java @@ -0,0 +1,262 @@ +/* FIPS186.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.hash.Sha160; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * An implementation of the DSA parameters generation as described in FIPS-186. + *

+ * References: + *

+ * Digital Signature + * Standard (DSS), Federal Information Processing Standards Publication + * 186. National Institute of Standards and Technology. + */ +public class FIPS186 +{ + public static final int DSA_PARAMS_SEED = 0; + + public static final int DSA_PARAMS_COUNTER = 1; + + public static final int DSA_PARAMS_Q = 2; + + public static final int DSA_PARAMS_P = 3; + + public static final int DSA_PARAMS_E = 4; + + public static final int DSA_PARAMS_G = 5; + + /** The BigInteger constant 2. */ + private static final BigInteger TWO = BigInteger.valueOf(2L); + + private static final BigInteger TWO_POW_160 = TWO.pow(160); + + /** The SHA instance to use. */ + private Sha160 sha = new Sha160(); + + /** The length of the modulus of DSS keys generated by this instance. */ + private int L; + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + /** Our default source of randomness. */ + private PRNG prng = null; + + public FIPS186(int L, SecureRandom rnd) + { + super(); + + this.L = L; + this.rnd = rnd; + } + + /** + * This method generates the DSS p, q, and + * g parameters only when L (the modulus length) + * is not one of the following: 512, 768 and + * 1024. For those values of L, this + * implementation uses pre-computed values of p, + * q, and g given in the document CryptoSpec + * included in the security guide documentation of the standard JDK + * distribution. + *

+ * The DSS requires two primes , p and q, + * satisfying the following three conditions: + *

+ * The algorithm used to find these primes is as described in FIPS-186, + * section 2.2: GENERATION OF PRIMES. This prime generation scheme starts by + * using the {@link Sha160} and a user supplied SEED to construct a + * prime, q, in the range 2159 < q < 2160. + * Once this is accomplished, the same SEED value is used to construct + * an X in the range 2L-1 + * < X < 2L. The prime, p, is then + * formed by rounding X to a number congruent to 1 mod + * 2q. In this implementation we use the same SEED value given + * in FIPS-186, Appendix 5. + */ + public BigInteger[] generateParameters() + { + int counter, offset; + BigInteger SEED, alpha, U, q, OFFSET, SEED_PLUS_OFFSET, W, X, p, c, g; + byte[] a, u; + byte[] kb = new byte[20]; // to hold 160 bits of randomness + + // Let L-1 = n*160 + b, where b and n are integers and 0 <= b < 160. + int b = (L - 1) % 160; + int n = (L - 1 - b) / 160; + BigInteger[] V = new BigInteger[n + 1]; + algorithm: while (true) + { + step1: while (true) + { + // 1. Choose an arbitrary sequence of at least 160 bits and + // call it SEED. + nextRandomBytes(kb); + SEED = new BigInteger(1, kb).setBit(159).setBit(0); + // Let g be the length of SEED in bits. here always 160 + // 2. Compute: U = SHA[SEED] XOR SHA[(SEED+1) mod 2**g] + alpha = SEED.add(BigInteger.ONE).mod(TWO_POW_160); + synchronized (sha) + { + a = SEED.toByteArray(); + sha.update(a, 0, a.length); + a = sha.digest(); + u = alpha.toByteArray(); + sha.update(u, 0, u.length); + u = sha.digest(); + } + for (int i = 0; i < a.length; i++) + a[i] ^= u[i]; + + U = new BigInteger(1, a); + // 3. Form q from U by setting the most significant bit (the + // 2**159 bit) and the least significant bit to 1. In terms of + // boolean operations, q = U OR 2**159 OR 1. Note that + // 2**159 < q < 2**160. + q = U.setBit(159).setBit(0); + // 4. Use a robust primality testing algorithm to test whether + // q is prime(1). A robust primality test is one where the + // probability of a non-prime number passing the test is at + // most 1/2**80. + // 5. If q is not prime, go to step 1. + if (q.isProbablePrime(80)) + break step1; + } // step1 + // 6. Let counter = 0 and offset = 2. + counter = 0; + offset = 2; + while (true) + { + OFFSET = BigInteger.valueOf(offset & 0xFFFFFFFFL); + SEED_PLUS_OFFSET = SEED.add(OFFSET); + // 7. For k = 0,...,n let V[k] = SHA[(SEED + offset + k) mod 2**g]. + synchronized (sha) + { + for (int k = 0; k <= n; k++) + { + a = SEED_PLUS_OFFSET + .add(BigInteger.valueOf(k & 0xFFFFFFFFL)) + .mod(TWO_POW_160).toByteArray(); + sha.update(a, 0, a.length); + V[k] = new BigInteger(1, sha.digest()); + } + } + // 8. Let W be the integer: + // V[0]+V[1]*2**160+...+V[n-1]*2**((n-1)*160)+(V[n]mod2**b)*2**(n*160) + // and let : X = W + 2**(L-1). + // Note that 0 <= W < 2**(L-1) and hence 2**(L-1) <= X < 2**L. + W = V[0]; + for (int k = 1; k < n; k++) + W = W.add(V[k].multiply(TWO.pow(k * 160))); + + W = W.add(V[n].mod(TWO.pow(b)).multiply(TWO.pow(n * 160))); + X = W.add(TWO.pow(L - 1)); + // 9. Let c = X mod 2q and set p = X - (c - 1). + // Note that p is congruent to 1 mod 2q. + c = X.mod(TWO.multiply(q)); + p = X.subtract(c.subtract(BigInteger.ONE)); + // 10. If p < 2**(L-1), then go to step 13. + if (p.compareTo(TWO.pow(L - 1)) >= 0) + { + // 11. Perform a robust primality test on p. + // 12. If p passes the test performed in step 11, go to step 15. + if (p.isProbablePrime(80)) + break algorithm; + } + // 13. Let counter = counter + 1 and offset = offset + n + 1. + counter++; + offset += n + 1; + // 14. If counter >= 4096 go to step 1, otherwise go to step 7. + if (counter >= 4096) + continue algorithm; + } // step7 + } // algorithm + // compute g. from FIPS-186, Appendix 4: + // 1. Generate p and q as specified in Appendix 2. + // 2. Let e = (p - 1) / q + BigInteger e = p.subtract(BigInteger.ONE).divide(q); + BigInteger h = TWO; + BigInteger p_minus_1 = p.subtract(BigInteger.ONE); + g = TWO; + // 3. Set h = any integer, where 1 < h < p - 1 and + // h differs from any value previously tried + for (; h.compareTo(p_minus_1) < 0; h = h.add(BigInteger.ONE)) + { + // 4. Set g = h**e mod p + g = h.modPow(e, p); + // 5. If g = 1, go to step 3 + if (! g.equals(BigInteger.ONE)) + break; + } + return new BigInteger[] { SEED, BigInteger.valueOf(counter), q, p, e, g }; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/GnuRSAKey.java b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAKey.java new file mode 100644 index 000000000..38530ee4c --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAKey.java @@ -0,0 +1,178 @@ +/* GnuRSAKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.util.FormatUtil; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.Key; +import java.security.interfaces.RSAKey; + +/** + * A base asbtract class for both public and private RSA keys. + */ +public abstract class GnuRSAKey + implements Key, RSAKey +{ + /** The public modulus of an RSA key pair. */ + private final BigInteger n; + + /** 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; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Trivial protected constructor. + * + * @param defaultFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param n the public modulus n. + * @param e the public exponent 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; + } + + public BigInteger getModulus() + { + return getN(); + } + + public String getAlgorithm() + { + return Registry.RSA_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(defaultFormat); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + /** + * Returns the modulus n. + * + * @return the modulus n. + */ + public BigInteger getN() + { + return n; + } + + /** + * Returns the public exponent e. + * + * @return the public exponent e. + */ + public BigInteger getPublicExponent() + { + return getE(); + } + + /** + * Same as {@link #getPublicExponent()}. + * + * @return the public exponent e. + */ + public BigInteger getE() + { + return e; + } + + /** + * Returns true if the designated object is an instance of + * {@link RSAKey} and has the same RSA parameter values as this one. + * + * @param obj the other non-null RSA key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(final Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof RSAKey)) + return false; + + final RSAKey that = (RSAKey) obj; + return n.equals(that.getModulus()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(ls) + .append("defaultFormat=").append(defaultFormat).append(",").append(ls) + .append("n=0x").append(n.toString(16)).append(",").append(ls) + .append("e=0x").append(e.toString(16)) + .toString(); + } + return str; + } + + public abstract byte[] getEncoded(int format); +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java new file mode 100644 index 000000000..39f91cbe4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java @@ -0,0 +1,313 @@ +/* GnuRSAPrivateKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.PrivateKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; + +/** + * An object that embodies an RSA private key. + *

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class GnuRSAPrivateKey + extends GnuRSAKey + implements PrivateKey, RSAPrivateCrtKey +{ + /** The first prime divisor of the modulus. */ + private final BigInteger p; + + /** The second prime divisor of the modulus. */ + private final BigInteger q; + + /** The private exponent of an RSA private key. */ + private final BigInteger d; + + /** The first factor's exponent. */ + private final BigInteger dP; + + /** The second factor's exponent. */ + private final BigInteger dQ; + + /** The CRT (Chinese Remainder Theorem) coefficient. */ + private final BigInteger qInv; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Convenience constructor. Calls the constructor with 5 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param p the modulus first prime divisor. + * @param q the modulus second prime divisor. + * @param e the public exponent. + * @param d the private exponent. + */ + public GnuRSAPrivateKey(BigInteger p, BigInteger q, BigInteger e, BigInteger d) + { + this(Registry.RAW_ENCODING_ID, p, q, e, d); + } + + /** + * Constructs a new instance of a GnuRSAPrivateKey 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 GnuRSAPrivateKey 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 p + * and q. + * @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 + * p and q, satisfying + * e * dP = 1 (mod p-1). + * @param dQ the second prime's exponent. A positive integer less than + * p and q, satisfying + * e * dQ = 1 (mod p-1). + * @param qInv the Chinese Remainder Theorem coefiicient. A positive integer + * less than p, satisfying + * q * qInv = 1 (mod p). + */ + public 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; + // 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), + this.dP = dP; + this.dQ = dQ; + // the CRT coefficient qInv is a positive integer less than p satisfying + // q * qInv = 1 (mod p). + this.qInv = qInv; + } + + /** + * A class method that takes the output of the encodePrivateKey() + * method of an RSA keypair codec object (an instance implementing + * {@link 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 + * k, 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. + */ + public static GnuRSAPrivateKey valueOf(final byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_RSA_PRIVATE_KEY[0]) + try + { + return (GnuRSAPrivateKey) new RSAKeyPairRawCodec().decodePrivateKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try PKCS#8 codec + return (GnuRSAPrivateKey) new RSAKeyPairPKCS8Codec().decodePrivateKey(k); + } + + public BigInteger getPrimeP() + { + return p; + } + + public BigInteger getPrimeQ() + { + return q; + } + + public BigInteger getPrimeExponentP() + { + return dP; + } + + public BigInteger getPrimeExponentQ() + { + return dQ; + } + + public BigInteger getCrtCoefficient() + { + return qInv; + } + + public BigInteger getPrivateExponent() + { + return d; + } + + /** + * 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 RSAKeyPairRawCodec + * @see RSAKeyPairPKCS8Codec + */ + public byte[] getEncoded(int format) + { + final byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new RSAKeyPairRawCodec().encodePrivateKey(this); + break; + case IKeyPairCodec.PKCS8_FORMAT: + result = new RSAKeyPairPKCS8Codec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of this + * class and has the same RSA parameter values as this one. + * + * @param obj the other non-null RSA key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(final Object obj) + { + if (obj == null) + return false; + + if (obj instanceof RSAPrivateKey) + { + final RSAPrivateKey that = (RSAPrivateKey) obj; + return super.equals(that) && d.equals(that.getPrivateExponent()); + } + if (obj instanceof RSAPrivateCrtKey) + { + final RSAPrivateCrtKey that = (RSAPrivateCrtKey) obj; + return super.equals(that) && p.equals(that.getPrimeP()) + && q.equals(that.getPrimeQ()) + && dP.equals(that.getPrimeExponentP()) + && dQ.equals(that.getPrimeExponentQ()) + && qInv.equals(that.getCrtCoefficient()); + } + return false; + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("d=0x").append(Configuration.DEBUG ? d.toString(16) + : "**...*").append(ls) + .append("p=0x").append(Configuration.DEBUG ? p.toString(16) + : "**...*").append(ls) + .append("q=0x").append(Configuration.DEBUG ? q.toString(16) + : "**...*").append(ls) + .append("dP=0x").append(Configuration.DEBUG ? dP.toString(16) + : "**...*").append(ls) + .append("dQ=0x").append(Configuration.DEBUG ? dQ.toString(16) + : "**...*").append(ls) + .append("qInv=0x").append(Configuration.DEBUG ? qInv.toString(16) + : "**...*").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java new file mode 100644 index 000000000..0bad92881 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java @@ -0,0 +1,190 @@ +/* GnuRSAPublicKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; + +/** + * An object that encapsulates an RSA public key. + *

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class GnuRSAPublicKey + extends GnuRSAKey + implements PublicKey, RSAPublicKey +{ + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Conveience constructor. Calls the constructor with 3 arguments passing + * {@link 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) + { + this(Registry.RAW_ENCODING_ID, n, e); + } + + /** + * Constructs a new instance of GnuRSAPublicKey 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); + } + + /** + * A class method that takes the output of the encodePublicKey() + * method of an RSA keypair codec object (an instance implementing + * {@link 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 + * k, 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. + */ + public static GnuRSAPublicKey valueOf(final byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_RSA_PUBLIC_KEY[0]) + try + { + return (GnuRSAPublicKey) new RSAKeyPairRawCodec().decodePublicKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try X.509 codec + return (GnuRSAPublicKey) new RSAKeyPairX509Codec().decodePublicKey(k); + } + + /** + * Returns the encoded form of this public key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + * @see RSAKeyPairRawCodec + */ + public byte[] getEncoded(final int format) + { + final byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new RSAKeyPairRawCodec().encodePublicKey(this); + break; + case IKeyPairCodec.X509_FORMAT: + result = new RSAKeyPairX509Codec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of this + * class and has the same RSA parameter values as this one. + * + * @param obj the other non-null RSA key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(final Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof RSAPublicKey)) + return false; + + final RSAPublicKey that = (RSAPublicKey) obj; + return super.equals(that) + && getPublicExponent().equals(that.getPublicExponent()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java new file mode 100644 index 000000000..bec60d350 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java @@ -0,0 +1,246 @@ +/* RSAKeyPairGenerator.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.RSAKeyGenParameterSpec; +import java.util.Map; +import java.util.logging.Logger; + +/** + * A key-pair generator for asymetric keys to use in conjunction with the RSA + * scheme. + *

+ * Reference: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B. Primitive specification + * and supporting documentation. Jakob Jonsson and Burt Kaliski.
  2. + *
  3. Handbook of Applied + * Cryptography, Alfred J. Menezes, Paul C. van Oorschot and Scott A. + * Vanstone. Section 11.3 RSA and related signature schemes.
  4. + *
+ */ +public class RSAKeyPairGenerator + implements IKeyPairGenerator +{ + private static final Logger log = Logger.getLogger(RSAKeyPairGenerator.class.getName()); + + /** The BigInteger constant 1. */ + private static final BigInteger ONE = BigInteger.ONE; + + /** The BigInteger constant 2. */ + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** Property name of the length (Integer) of the modulus of an RSA key. */ + public static final String MODULUS_LENGTH = "gnu.crypto.rsa.L"; + + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.rsa.prng"; + + /** + * Property name of an optional {@link RSAKeyGenParameterSpec} instance to use + * for this generator's n, and e values. The + * default is to generate n and use a fixed value for + * e (Fermat's F4 number). + */ + 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 {@link 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; + + /** + * This implementation uses, by default, Fermat's F4 number as the public + * exponent. + */ + private BigInteger e = BigInteger.valueOf(65537L); + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + /** Our default source of randomness. */ + private PRNG prng = null; + + /** Preferred encoding format of generated keys. */ + private int preferredFormat; + + // implicit 0-arguments constructor + + public String name() + { + return Registry.RSA_KPG; + } + + /** + * Configures this instance. + * + * @param attributes the map of name/value pairs to use. + * @exception IllegalArgumentException if the designated MODULUS_LENGTH value + * is less than 1024. + */ + public void setup(Map attributes) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "setup", attributes); + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // are we given a set of RSA params or we shall use our own? + RSAKeyGenParameterSpec params = (RSAKeyGenParameterSpec) attributes.get(RSA_PARAMETERS); + // find out the modulus length + if (params != null) + { + L = params.getKeysize(); + e = params.getPublicExponent(); + } + else + { + Integer l = (Integer) attributes.get(MODULUS_LENGTH); + L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue()); + } + if (L < 1024) + 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(); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "setup"); + } + + /** + *

+ * The algorithm used here is described in nessie-pss-B.pdf document + * which is part of the RSA-PSS submission to NESSIE. + *

+ * + * @return an RSA keypair. + */ + public KeyPair generate() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "generate"); + BigInteger p, q, n, d; + // 1. Generate a prime p in the interval [2**(M-1), 2**M - 1], where + // M = CEILING(L/2), and such that GCD(p, e) = 1 + int M = (L + 1) / 2; + BigInteger lower = TWO.pow(M - 1); + BigInteger upper = TWO.pow(M).subtract(ONE); + byte[] kb = new byte[(M + 7) / 8]; // enough bytes to frame M bits + step1: while (true) + { + nextRandomBytes(kb); + p = new BigInteger(1, kb).setBit(0); + if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0 + && p.isProbablePrime(80) && p.gcd(e).equals(ONE)) + break step1; + } + // 2. Generate a prime q such that the product of p and q is an L-bit + // number, and such that GCD(q, e) = 1 + step2: while (true) + { + nextRandomBytes(kb); + q = new BigInteger(1, kb).setBit(0); + n = p.multiply(q); + if (n.bitLength() == L && q.isProbablePrime(80) && q.gcd(e).equals(ONE)) + break step2; + // TODO: test for p != q + } + // TODO: ensure p < q + // 3. Put n = pq. The public key is (n, e). + // 4. Compute the parameters necessary for the private key K (see + // Section 2.2). + BigInteger phi = p.subtract(ONE).multiply(q.subtract(ONE)); + d = e.modInverse(phi); + // 5. Output the public key and the private key. + PublicKey pubK = new GnuRSAPublicKey(preferredFormat, n, e); + PrivateKey secK = new GnuRSAPrivateKey(preferredFormat, p, q, e, d); + KeyPair result = new KeyPair(pubK, secK); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "generate", result); + return result; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java new file mode 100644 index 000000000..2785f02c8 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java @@ -0,0 +1,299 @@ +/* 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 gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.logging.Logger; + +/** + * An implementation of an {@link IKeyPairCodec} that knows how to encode / + * decode PKCS#8 ASN.1 external representation of RSA private keys. + */ +public class RSAKeyPairPKCS8Codec + implements IKeyPairCodec +{ + private static final Logger log = Logger.getLogger(RSAKeyPairPKCS8Codec.class.getName()); + private static final OID RSA_ALG_OID = new OID(Registry.RSA_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return PKCS8_FORMAT; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePublicKey(PublicKey key) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * Returns the PKCS#8 ASN.1 PrivateKeyInfo representation of an RSA + * private key. The ASN.1 specification is as follows: + *
+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   * 
+ *

+ * As indicated in RFC-2459: "The parameters field shall have ASN.1 type NULL + * for this algorithm identifier.". + *

+ * The privateKey field, which is an OCTET STRING, contains the + * DER-encoded form of the RSA private key defined as: + *

+   *   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
+   *   }
+   * 
+ * + * @return the DER encoded form of the ASN.1 representation of the + * PrivateKeyInfo field for an RSA {@link PrivateKey}.. + * @throw InvalidParameterException if an error occurs during the marshalling + * process. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "encodePrivateKey()", key); + if (! (key instanceof GnuRSAPrivateKey)) + throw new InvalidParameterException("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(2); + algorithmID.add(derOID); + algorithmID.add(new DERValue(DER.NULL, null)); + 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; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "encodePrivateKey()", result); + 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 RSA + * {@link PrivateKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuRSAPrivateKey} decoded from the + * PrivateKeyInfo material fed as input. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decodePrivateKey()", 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(); + DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field"); + + DERValue derVersion = der.read(); + DerUtil.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(); + DerUtil.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); + + // rfc-2459 states that this field is OPTIONAL but NULL if/when present + DERValue val = der.read(); + if (val.getTag() == DER.NULL) + val = der.read(); + + byte[] pkBytes = (byte[]) val.getValue(); + der = new DERReader(pkBytes); + DERValue derRSAPrivateKey = der.read(); + DerUtil.checkIsConstructed(derRSAPrivateKey, "Wrong RSAPrivateKey field"); + + val = der.read(); + DerUtil.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(); + DerUtil.checkIsBigInteger(val, "Wrong modulus field"); + n = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong publicExponent field"); + e = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong privateExponent field"); + d = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong prime1 field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong prime2 field"); + q = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong exponent1 field"); + dP = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong exponent2 field"); + dQ = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong coefficient field"); + qInv = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + PrivateKey result = new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, + n, e, d, p, q, dP, dQ, qInv); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decodePrivateKey()", result); + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java new file mode 100644 index 000000000..f088e794e --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java @@ -0,0 +1,300 @@ +/* RSAKeyPairRawCodec.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * An object that implements the {@link IKeyPairCodec} interface for the Raw + * format to use with RSA keypairs. + */ +public class RSAKeyPairRawCodec + implements IKeyPairCodec +{ + // implicit 0-arguments constructor + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated RSA public key according to the + * Raw format supported by this library. + *

+ * The Raw format for an RSA public key, in this implementation, is a + * byte sequence consisting of the following: + *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_RSA_PUBLIC_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the RSA parameter + * n (the modulus) in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter n, + *
  8. + *
  9. 4-byte count of following bytes representing the RSA parameter + * e (the public exponent) in internet order,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter e. + *
  12. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @exception IllegalArgumentException if the designated key is not an RSA + * one. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof GnuRSAPublicKey)) + throw new IllegalArgumentException("key"); + + GnuRSAPublicKey rsaKey = (GnuRSAPublicKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[0]); + baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[1]); + baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[2]); + baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[3]); + // version + baos.write(0x01); + // n + byte[] buffer = rsaKey.getModulus().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // e + buffer = rsaKey.getPublicExponent().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public PublicKey decodePublicKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[0] + || k[1] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[1] + || k[2] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[2] + || k[3] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[3]) + throw new IllegalArgumentException("magic"); + + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + + int i = 5; + int l; + byte[] buffer; + // n + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger n = new BigInteger(1, buffer); + // e + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger e = new BigInteger(1, buffer); + return new GnuRSAPublicKey(n, e); + } + + /** + * Returns the encoded form of the designated RSA private key according to the + * Raw format supported by this library. + *

+ * The Raw format for an RSA private key, in this implementation, is a + * byte sequence consisting of the following: + *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_RSA_PRIVATE_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the RSA parameter + * p (the first prime factor of the modulus) in internet order, + *
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter p, + *
  8. + *
  9. 4-byte count of following bytes representing the RSA parameter + * q (the second prime factor of the modulus) in internet + * order,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter q, + *
  12. + *
  13. 4-byte count of following bytes representing the RSA parameter + * e (the public exponent) in internet order,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter e, + *
  16. + *
  17. 4-byte count of following bytes representing the RSA parameter + * d (the private exponent) in internet order,
  18. + *
  19. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter d, + *
  20. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof GnuRSAPrivateKey)) + throw new IllegalArgumentException("key"); + + GnuRSAPrivateKey rsaKey = (GnuRSAPrivateKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[0]); + baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[1]); + baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[2]); + baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[3]); + // version + baos.write(0x01); + // p + byte[] buffer = rsaKey.getPrimeP().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // q + buffer = rsaKey.getPrimeQ().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // e + buffer = rsaKey.getPublicExponent().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + // d + buffer = rsaKey.getPrivateExponent().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public PrivateKey decodePrivateKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[0] + || k[1] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[1] + || k[2] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[2] + || k[3] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[3]) + throw new IllegalArgumentException("magic"); + + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + + int i = 5; + int l; + byte[] buffer; + // p + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + // q + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + // e + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger e = new BigInteger(1, buffer); + // d + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger d = new BigInteger(1, buffer); + return new GnuRSAPrivateKey(p, q, e, d); + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java new file mode 100644 index 000000000..9ad6ae029 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java @@ -0,0 +1,250 @@ +/* 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.Configuration; +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.logging.Logger; + +/** + * An implementation of an {@link 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 Logger log = Logger.getLogger(RSAKeyPairX509Codec.class.getName()); + private static final OID RSA_ALG_OID = new OID(Registry.RSA_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return X509_FORMAT; + } + + /** + * Returns the X.509 ASN.1 SubjectPublicKeyInfo representation of an + * RSA public key. The ASN.1 specification, as defined in RFC-3280, and + * RFC-2459, is as follows: + * + *
+   *   SubjectPublicKeyInfo ::= SEQUENCE {
+   *     algorithm         AlgorithmIdentifier,
+   *     subjectPublicKey  BIT STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   * 
+ *

+ * As indicated in RFC-2459: "The parameters field shall have ASN.1 type NULL + * for this algorithm identifier.". + *

+ * The subjectPublicKey field, which is a BIT STRING, contains the + * DER-encoded form of the RSA public key defined as: + * + *

+   *   RSAPublicKey ::= SEQUENCE {
+   *     modulus         INTEGER, -- n
+   *     publicExponent  INTEGER  -- e
+   *   }
+   * 
+ * + * @param key the {@link PublicKey} instance to encode. MUST be an instance of + * {@link GnuRSAPublicKey}. + * @return the ASN.1 representation of the SubjectPublicKeyInfo in an + * X.509 certificate. + * @throw InvalidParameterException if key is not an instance + * of {@link GnuRSAPublicKey} or if an exception occurs during the + * marshalling process. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "encodePublicKey()", 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(2); + algorithmID.add(derOID); + algorithmID.add(new DERValue(DER.NULL, null)); + 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(x.getMessage()); + y.initCause(x); + throw y; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "encodePublicKey()", result); + 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 RSA + * {@link PublicKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuRSAPublicKey} decoded from the + * SubjectPublicKeyInfo material in an X.509 certificate. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PublicKey decodePublicKey(byte[] input) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decodePublicKey()", 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(); + DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); + + DERValue derAlgorithmID = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + if (! (derOID.getValue() instanceof OID)) + throw new InvalidParameterException("Wrong Algorithm field"); + + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(RSA_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + // rfc-2459 states that this field is OPTIONAL but NULL if/when present + DERValue val = der.read(); + if (val.getTag() == DER.NULL) + 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(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong subjectPublicKey field"); + + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong modulus field"); + n = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong publicExponent field"); + e = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(x.getMessage()); + y.initCause(x); + throw y; + } + PublicKey result = new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decodePublicKey()", result); + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for private keys"); + } +} -- cgit v1.2.3