Imported GNU Classpath 0.90

Imported GNU Classpath 0.90
       * scripts/makemake.tcl: Set gnu/java/awt/peer/swing to ignore.
       * gnu/classpath/jdwp/VMFrame.java (SIZE): New constant.
       * java/lang/VMCompiler.java: Use gnu.java.security.hash.MD5.
       * java/lang/Math.java: New override file.
       * java/lang/Character.java: Merged from Classpath.
       (start, end): Now 'int's.
       (canonicalName): New field.
       (CANONICAL_NAME, NO_SPACES_NAME, CONSTANT_NAME): New constants.
       (UnicodeBlock): Added argument.
       (of): New overload.
       (forName): New method.
       Updated unicode blocks.
       (sets): Updated.
       * sources.am: Regenerated.
       * Makefile.in: Likewise.

From-SVN: r111942
This commit is contained in:
Mark Wielaard
2006-03-10 21:46:48 +00:00
parent 27079765d0
commit 8aa540d2f7
1367 changed files with 188789 additions and 22762 deletions
@@ -0,0 +1,132 @@
/* 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;
/**
* <p>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.</p>
*
* @version $Revision: 1.2 $
*/
public interface IKeyPairCodec
{
// Constants
// -------------------------------------------------------------------------
/** Constant identifying the <i>Raw</i> encoding format. */
int RAW_FORMAT = Registry.RAW_ENCODING_ID;
/** Constant identifying the <i>X.509</i> encoding format. */
int X509_FORMAT = Registry.X509_ENCODING_ID;
/** Constant identifying the <i>PKCS#8</i> encoding format. */
int PKCS8_FORMAT = Registry.PKCS8_ENCODING_ID;
/**
* Constant identifying the <i>ASN.1</i> encoding format: a combined encoding
* of <i>X.509</i> for public keys, and <i>PKCS#8</i> for private ones.
*/
int ASN1_FORMAT = Registry.ASN1_ENCODING_ID;
// Method(s)
// -------------------------------------------------------------------------
/**
* <p>Returns the unique identifier (within this library) of the format used
* to externalise public and private keys.</p>
*
* @return the identifier of the format, the object supports.
*/
int getFormatID();
/**
* <p>Encodes an instance of a public key for storage or transmission purposes.</p>
*
* @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);
/**
* <p>Encodes an instance of a private key for storage or transmission purposes.</p>
*
* @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);
/**
* <p>Decodes an instance of an external public key into its native Java
* representation.</p>
*
* @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);
/**
* <p>Decodes an instance of an external private key into its native Java
* representation.</p>
*
* @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);
}
@@ -0,0 +1,82 @@
/* 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.<p>
*
* @version $Revision: 1.1 $
*/
public interface IKeyPairGenerator
{
// Constants
// -------------------------------------------------------------------------
// Methods
// -------------------------------------------------------------------------
/**
* Returns the canonical name of this keypair generator.<p>
*
* @return the canonical name of this instance.
*/
String name();
/**
* [Re]-initialises this instance for use with a given set of attributes.<p>
*
* @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();
}
@@ -0,0 +1,362 @@
/* 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 <i>Factory</i> 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
* <code>/</code> and the canonical name of the encoding format.
* <p>
* <b>IMPORTANT</b>: 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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
* <code>null</code> 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
* <code>null</code> 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
* <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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;
}
}
@@ -0,0 +1,148 @@
/* 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;
/**
* <p>A Factory to instantiate asymmetric keypair generators.</p>
*
* @version $Revision: 1.1 $
*/
public class KeyPairGeneratorFactory
{
// Constants and variables
// -------------------------------------------------------------------------
// Constructor(s)
// -------------------------------------------------------------------------
/** Trivial constructor to enforce Singleton pattern. */
private KeyPairGeneratorFactory()
{
super();
}
// Class methods
// -------------------------------------------------------------------------
/**
* <p>Returns an instance of a keypair generator given its name.</p>
*
* @param name the case-insensitive key generator name.
* @return an instance of the keypair generator, or <code>null</code> 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.equals(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;
}
/**
* <p>Returns a {@link Set} of keypair generator names supported by this
* <i>Factory</i>. Those keypair generators may be used in conjunction with
* the digital signature schemes with appendix supported by this library.</p>
*
* @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.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)
{
IllegalArgumentException iae =
new IllegalArgumentException ("strong crypto key pair generator not available: "
+ clazz);
iae.initCause (x);
throw iae;
}
}
// Instance methods
// -------------------------------------------------------------------------
}
@@ -0,0 +1,182 @@
/* 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.security.Registry;
import gnu.java.security.util.FormatUtil;
import java.math.BigInteger;
import java.security.Key;
import java.security.interfaces.DSAKey;
import java.security.interfaces.DSAParams;
import java.security.spec.DSAParameterSpec;
/**
* <p>A base asbtract class for both public and private DSS (Digital Signature
* Standard) keys. It encapsulates the three DSS numbers: <code>p</code>,
* <code>q</code> and <code>g</code>.</p>
*
* <p>According to the JDK, cryptographic <i>Keys</i> all have a <i>format</i>.
* The format used in this implementation is called <i>Raw</i>, and basically
* consists of the raw byte sequences of algorithm parameters. The exact order
* of the byte sequences and the implementation details are given in each of
* the relevant <code>getEncoded()</code> methods of each of the private and
* public keys.</p>
*
* @version $Revision: 1.4 $
* @see DSSPrivateKey#getEncoded
* @see DSSPublicKey#getEncoded
*/
public abstract class DSSKey implements Key, DSAKey
{
// Constants and variables
// -------------------------------------------------------------------------
/**
* A prime modulus, where <code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup></code>
* for <code>512 &lt;= L &lt;= 1024</code> and <code>L</code> a multiple of
* <code>64</code>.
*/
protected final BigInteger p;
/**
* A prime divisor of <code>p - 1</code>, where <code>2<sup>159</sup> &lt; q
* &lt; 2<sup>160</sup></code>.
*/
protected final BigInteger q;
/**
* <code>g = h<sup>(p-1)</sup>/q mod p</code>, where <code>h</code> is any
* integer with <code>1 &lt; h &lt; p - 1</code> such that <code>h<sup>
* (p-1)</sup>/q mod p > 1</code> (<code>g</code> has order <code>q mod p
* </code>).
*/
protected final BigInteger g;
/**
* Identifier of the default encoding format to use when externalizing the
* key material.
*/
protected final int defaultFormat;
// Constructor(s)
// -------------------------------------------------------------------------
/**
* Trivial protected constructor.
*
* @param defaultFormat the identifier of the encoding format to use by
* default when externalizing the key.
* @param p the DSS parameter <code>p</code>.
* @param q the DSS parameter <code>q</code>.
* @param g the DSS parameter <code>g</code>.
*/
protected DSSKey(int defaultFormat, BigInteger p, BigInteger q, BigInteger g)
{
super();
this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID
: defaultFormat;
this.p = p;
this.q = q;
this.g = g;
}
// Class methods
// -------------------------------------------------------------------------
// Instance methods
// -------------------------------------------------------------------------
// java.security.interfaces.DSAKey interface implementation ----------------
public DSAParams getParams()
{
return new DSAParameterSpec(p, q, g);
}
// java.security.Key interface implementation ------------------------------
public String getAlgorithm()
{
return Registry.DSS_KPG;
}
/** @deprecated see getEncoded(int). */
public byte[] getEncoded()
{
return getEncoded(defaultFormat);
}
public String getFormat()
{
return FormatUtil.getEncodingShortName(defaultFormat);
}
// Other instance methods --------------------------------------------------
/**
* <p>Returns <code>true</code> if the designated object is an instance of
* {@link DSAKey} and has the same DSS (Digital Signature Standard) parameter
* values as this one.</p>
*
* @param obj the other non-null DSS key to compare to.
* @return <code>true</code> if the designated object is of the same type and
* value as this one.
*/
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (!(obj instanceof DSAKey))
{
return false;
}
DSAKey that = (DSAKey) obj;
return p.equals(that.getParams().getP())
&& q.equals(that.getParams().getQ())
&& g.equals(that.getParams().getG());
}
// abstract methods to be implemented by subclasses ------------------------
public abstract byte[] getEncoded(int format);
}
@@ -0,0 +1,445 @@
/* 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.Registry;
import gnu.java.security.hash.Sha160;
import gnu.java.security.key.IKeyPairGenerator;
import gnu.java.security.util.PRNG;
import java.io.PrintWriter;
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;
/**
* <p>A key-pair generator for asymetric keys to use in conjunction with the DSS
* (Digital Signature Standard).</p>
*
* References:<br>
* <a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
* Standard (DSS)</a>, Federal Information Processing Standards Publication 186.
* National Institute of Standards and Technology.
*/
public class DSSKeyPairGenerator implements IKeyPairGenerator
{
// Debugging methods and variables
// -------------------------------------------------------------------------
private static final String NAME = "dss";
private static final boolean DEBUG = false;
private static final int debuglevel = 5;
private static final PrintWriter err = new PrintWriter(System.out, true);
private static void debug(String s)
{
err.println(">>> " + NAME + ": " + s);
}
// Constants and variables
// -------------------------------------------------------------------------
/** The BigInteger constant 2. */
private static final BigInteger TWO = new BigInteger("2");
/** Property name of the length (Integer) of the modulus (p) of a DSS key. */
public static final String MODULUS_LENGTH = "gnu.crypto.dss.L";
/**
* Property name of the Boolean indicating wether or not to use default pre-
* computed values of <code>p</code>, <code>q</code> and <code>g</code> for
* a given modulus length. The ultimate behaviour of this generator with
* regard to using pre-computed parameter sets will depend on the value of
* this property and of the following one {@link #STRICT_DEFAULTS}:
*
* <ol>
* <li>If this property is {@link Boolean#FALSE} then this generator
* will accept being setup for generating parameters for any modulus length
* provided the modulus length is between <code>512</code> and
* <code>1024</code>, and is of the form <code>512 + 64 * n</code>. In
* addition, a new paramter set will always be generated; i.e. no pre-
* computed values are used.</li>
*
* <li>If this property is {@link Boolean#TRUE} and the value of
* {@link #STRICT_DEFAULTS} is also {@link Boolean#TRUE} then this generator
* will only accept being setup for generating parameters for modulus
* lengths of <code>512</code>, <code>768</code> and <code>1024</code>. Any
* other value, of the modulus length, even if between <code>512</code> and
* <code>1024</code>, and of the form <code>512 + 64 * n</code>, will cause
* an {@link IllegalArgumentException} to be thrown. When those modulus
* length (<code>512</code>, <code>768</code>, and <code>1024</code>) are
* specified, the paramter set is always the same.</li>
*
* <li>Finally, if this property is {@link Boolean#TRUE} and the value of
* {@link #STRICT_DEFAULTS} is {@link Boolean#FALSE} then this generator
* will behave as in point 1 above, except that it will use pre-computed
* values when possible; i.e. the modulus length is one of <code>512</code>,
* <code>768</code>, or <code>1024</code>.</li>
* </ol>
*
* The default value of this property is {@link Boolean#TRUE}.
*/
public static final String USE_DEFAULTS = "gnu.crypto.dss.use.defaults";
/**
* Property name of the Boolean indicating wether or not to generate new
* parameters, even if the modulus length <i>L</i> is not one of the pre-
* computed defaults (value {@link Boolean#FALSE}), or throw an exception
* (value {@link Boolean#TRUE}) -- the exception in this case is an
* {@link IllegalArgumentException}. The default value for this property is
* {@link Boolean#FALSE}. The ultimate behaviour of this generator will
* depend on the values of this and {@link #USE_DEFAULTS} properties -- see
* {@link #USE_DEFAULTS} for more information.
*/
public static final String STRICT_DEFAULTS = "gnu.crypto.dss.strict.defaults";
/**
* Property name of an optional {@link SecureRandom} instance to use. The
* default is to use a classloader singleton from {@link PRNG}.
*/
public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dss.prng";
/**
* Property name of an optional {@link DSAParameterSpec} instance to use for
* this generator's <code>p</code>, <code>q</code>, and <code>g</code> values.
* The default is to generate these values or use pre-computed ones,
* depending on the value of the <code>USE_DEFAULTS</code> attribute.
*/
public static final String DSS_PARAMETERS = "gnu.crypto.dss.params";
/**
* Property name of the preferred encoding format to use when externalizing
* generated instance of key-pairs from this generator. The property is taken
* to be an {@link Integer} that encapsulates an encoding format identifier.
*/
public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dss.encoding";
/** Default value for the modulus length. */
public static final int DEFAULT_MODULUS_LENGTH = 1024;
/** Default encoding format to use when none was specified. */
private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID;
/** Initial SHS context. */
private static final int[] T_SHS = new int[] { 0x67452301, 0xEFCDAB89,
0x98BADCFE, 0x10325476,
0xC3D2E1F0 };
// from jdk1.3.1/docs/guide/security/CryptoSpec.html#AppB
public static final DSAParameterSpec KEY_PARAMS_512 = new DSAParameterSpec(
new BigInteger(
"fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae"
+ "01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17",
16),
new BigInteger(
"962eddcc369cba8ebb260ee6b6a126d9346e38c5",
16),
new BigInteger(
"678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e"
+ "35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4",
16));
public static final DSAParameterSpec KEY_PARAMS_768 = new DSAParameterSpec(
new BigInteger(
"e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d8901419"
+ "22d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d77"
+ "7d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf",
16),
new BigInteger(
"9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511",
16),
new BigInteger(
"30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4"
+ "dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d8"
+ "3c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252",
16));
public static final DSAParameterSpec KEY_PARAMS_1024 = new DSAParameterSpec(
new BigInteger(
"fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669"
+ "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7"
+ "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb"
+ "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7",
16),
new BigInteger(
"9760508f15230bccb292b982a2eb840bf0581cf5",
16),
new BigInteger(
"f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267"
+ "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1"
+ "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b"
+ "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a",
16));
private static final BigInteger TWO_POW_160 = TWO.pow(160);
/** The length of the modulus of DSS keys generated by this instance. */
private int L;
/** The optional {@link SecureRandom} instance to use. */
private SecureRandom rnd = null;
private BigInteger seed;
private BigInteger counter;
private BigInteger p;
private BigInteger q;
private BigInteger e;
private BigInteger g;
private BigInteger XKEY;
/** Our default source of randomness. */
private PRNG prng = null;
/** Preferred encoding format of generated keys. */
private int preferredFormat;
// Constructor(s)
// -------------------------------------------------------------------------
// implicit 0-arguments constructor
// Class methods
// -------------------------------------------------------------------------
// Instance methods
// -------------------------------------------------------------------------
// gnu.crypto.key.IKeyPairGenerator interface implementation ---------------
public String name()
{
return Registry.DSS_KPG;
}
/**
* <p>Configures this instance.</p>
*
* @param attributes the map of name/value pairs to use.
* @exception IllegalArgumentException if the designated MODULUS_LENGTH
* value is not greater than 512, less than 1024 and not of the form
* <code>512 + 64j</code>.
*/
public void setup(Map attributes)
{
// find out the modulus length
Integer l = (Integer) attributes.get(MODULUS_LENGTH);
L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue());
if ((L % 64) != 0 || L < 512 || L > 1024)
throw new IllegalArgumentException(MODULUS_LENGTH);
// should we use the default pre-computed params?
Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS);
if (useDefaults == null)
{
useDefaults = Boolean.TRUE;
}
Boolean strictDefaults = (Boolean) attributes.get(STRICT_DEFAULTS);
if (strictDefaults == null)
strictDefaults = Boolean.FALSE;
// are we given a set of DSA params or we shall use/generate our own?
DSAParameterSpec params = (DSAParameterSpec) attributes.get(DSS_PARAMETERS);
if (params != null)
{
p = params.getP();
q = params.getQ();
g = params.getG();
}
else if (useDefaults.equals(Boolean.TRUE))
{
switch (L)
{
case 512:
p = KEY_PARAMS_512.getP();
q = KEY_PARAMS_512.getQ();
g = KEY_PARAMS_512.getG();
break;
case 768:
p = KEY_PARAMS_768.getP();
q = KEY_PARAMS_768.getQ();
g = KEY_PARAMS_768.getG();
break;
case 1024:
p = KEY_PARAMS_1024.getP();
q = KEY_PARAMS_1024.getQ();
g = KEY_PARAMS_1024.getG();
break;
default:
if (strictDefaults.equals(Boolean.TRUE))
throw new IllegalArgumentException(
"Does not provide default parameters for " + L
+ "-bit modulus length");
else
{
p = null;
q = null;
g = null;
}
}
}
else
{
p = null;
q = null;
g = null;
}
// do we have a SecureRandom, or should we use our own?
rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
// what is the preferred encoding format
Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
preferredFormat = formatID == null
? DEFAULT_ENCODING_FORMAT
: formatID.intValue();
// set the seed-key
byte[] kb = new byte[20]; // we need 160 bits of randomness
nextRandomBytes(kb);
XKEY = new BigInteger(1, kb).setBit(159).setBit(0);
}
public KeyPair generate()
{
if (p == null)
{
BigInteger[] params = new FIPS186(L, rnd).generateParameters();
seed = params[FIPS186.DSA_PARAMS_SEED];
counter = params[FIPS186.DSA_PARAMS_COUNTER];
q = params[FIPS186.DSA_PARAMS_Q];
p = params[FIPS186.DSA_PARAMS_P];
e = params[FIPS186.DSA_PARAMS_E];
g = params[FIPS186.DSA_PARAMS_G];
if (DEBUG && debuglevel > 0)
{
debug("seed: " + seed.toString(16));
debug("counter: " + counter.intValue());
debug("q: " + q.toString(16));
debug("p: " + p.toString(16));
debug("e: " + e.toString(16));
debug("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);
}
// Other instance methods --------------------------------------------------
/**
* <p>This method applies the following algorithm described in 3.1 of
* FIPS-186:</p>
*
* <ol>
* <li>XSEED = optional user input.</li>
* <li>XVAL = (XKEY + XSEED) mod 2<sup>b</sup>.</li>
* <li>x = G(t, XVAL) mod q.</li>
* <li>XKEY = (1 + XKEY + x) mod 2<sup>b</sup>.</li>
* </ol>
*
* <p>Where <code>b</code> is the length of a secret b-bit seed-key (XKEY).</p>
*
* <p>Note that in this implementation, XSEED, the optional user input, is
* always zero.</p>
*/
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;
}
/**
* <p>Fills the designated byte array with random data.</p>
*
* @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;
}
}
@@ -0,0 +1,235 @@
/* 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.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;
/**
* 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 OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
// implicit 0-arguments constructor
public int getFormatID()
{
return PKCS8_FORMAT;
}
/**
* @throws InvalidParameterException ALWAYS.
*/
public byte[] encodePublicKey(PublicKey key)
{
throw new InvalidParameterException("Wrong format for public keys");
}
/**
* Returns the PKCS#8 ASN.1 <i>PrivateKeyInfo</i> representation of a DSA
* private key. The ASN.1 specification is as follows:
*
* <pre>
* PrivateKeyInfo ::= SEQUENCE {
* version INTEGER, -- MUST be 0
* privateKeyAlgorithm AlgorithmIdentifier,
* privateKey OCTET STRING
* }
*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL
* }
*
* DssParams ::= SEQUENCE {
* p INTEGER,
* q INTEGER,
* g INTEGER
* }
* </pre>
*
* @return the DER encoded form of the ASN.1 representation of the
* <i>PrivateKeyInfo</i> field in an X.509 certificate.
* @throw InvalidParameterException if an error occurs during the marshalling
* process.
*/
public byte[] encodePrivateKey(PrivateKey key)
{
if (! (key instanceof DSSPrivateKey))
throw new InvalidParameterException("Wrong key type");
DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
DSSPrivateKey pk = (DSSPrivateKey) key;
BigInteger p = pk.getParams().getP();
BigInteger q = pk.getParams().getQ();
BigInteger g = pk.getParams().getG();
BigInteger x = pk.getX();
ArrayList params = new ArrayList(3);
params.add(new DERValue(DER.INTEGER, p));
params.add(new DERValue(DER.INTEGER, q));
params.add(new DERValue(DER.INTEGER, g));
DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
ArrayList algorithmID = new ArrayList(2);
algorithmID.add(derOID);
algorithmID.add(derParams);
DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
algorithmID);
DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, Util.trim(x));
ArrayList pki = new ArrayList(3);
pki.add(derVersion);
pki.add(derAlgorithmID);
pki.add(derPrivateKey);
DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
byte[] result;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
DERWriter.write(baos, derPKI);
result = baos.toByteArray();
}
catch (IOException e)
{
InvalidParameterException y = new InvalidParameterException();
y.initCause(e);
throw y;
}
return result;
}
/**
* @throws InvalidParameterException ALWAYS.
*/
public PublicKey decodePublicKey(byte[] input)
{
throw new InvalidParameterException("Wrong format for public keys");
}
/**
* @param input the byte array to unmarshall into a valid DSS
* {@link PrivateKey} instance. MUST NOT be null.
* @return a new instance of a {@link DSSPrivateKey} decoded from the
* <i>PrivateKeyInfo</i> material fed as <code>input</code>.
* @throw InvalidParameterException if an exception occurs during the
* unmarshalling process.
*/
public PrivateKey decodePrivateKey(byte[] input)
{
if (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();
byte[] xBytes = (byte[]) val.getValue();
x = new BigInteger(1, xBytes);
}
catch (IOException e)
{
InvalidParameterException y = new InvalidParameterException();
y.initCause(e);
throw y;
}
return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x);
}
}
@@ -0,0 +1,383 @@
/* 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;
/**
* <p>An object that implements the {@link IKeyPairCodec} operations for the
* <i>Raw</i> format to use with DSS keypairs.</p>
*
* @version $Revision: 1.1 $
*/
public class DSSKeyPairRawCodec implements IKeyPairCodec
{
// Constants and variables
// -------------------------------------------------------------------------
// Constructor(s)
// -------------------------------------------------------------------------
// implicit 0-arguments constructor
// Class methods
// -------------------------------------------------------------------------
// Instance methods
// -------------------------------------------------------------------------
// gnu.crypto.keys.IKeyPairCodec interface implementation ------------------
public int getFormatID()
{
return RAW_FORMAT;
}
/**
* <p>Returns the encoded form of the designated DSS (Digital Signature
* Standard) public key according to the <i>Raw</i> format supported by
* this library.</p>
*
* <p>The <i>Raw</i> format for a DSA public key, in this implementation, is
* a byte sequence consisting of the following:</p>
* <ol>
* <li>4-byte magic consisting of the value of the literal
* {@link Registry#MAGIC_RAW_DSS_PUBLIC_KEY},<li>
* <li>1-byte version consisting of the constant: 0x01,</li>
* <li>4-byte count of following bytes representing the DSA parameter
* <code>p</code> in internet order,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the DSA parameter
* <code>p</code>,</li>
* <li>4-byte count of following bytes representing the DSA parameter
* <code>q</code>,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the DSA parameter
* <code>q</code>,</li>
* <li>4-byte count of following bytes representing the DSA parameter
* <code>g</code>,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the DSA parameter
* <code>g</code>,</li>
* <li>4-byte count of following bytes representing the DSA parameter
* <code>y</code>,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the DSA parameter
* <code>y</code>,</li>
* </ol>
*
* @param key the key to encode.
* @return the <i>Raw</i> format encoding of the designated key.
* @throws IllegalArgumentException if the designated key is not a DSS
* (Digital Signature Standard) one.
* @see Registry#MAGIC_RAW_DSS_PUBLIC_KEY
*/
public byte[] encodePublicKey(PublicKey key)
{
if (!(key instanceof DSSPublicKey))
{
throw new IllegalArgumentException("key");
}
DSSPublicKey dssKey = (DSSPublicKey) key;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// magic
baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]);
baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[1]);
baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[2]);
baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[3]);
// version
baos.write(0x01);
// p
byte[] buffer = dssKey.getParams().getP().toByteArray();
int length = buffer.length;
baos.write(length >>> 24);
baos.write((length >>> 16) & 0xFF);
baos.write((length >>> 8) & 0xFF);
baos.write(length & 0xFF);
baos.write(buffer, 0, length);
// q
buffer = dssKey.getParams().getQ().toByteArray();
length = buffer.length;
baos.write(length >>> 24);
baos.write((length >>> 16) & 0xFF);
baos.write((length >>> 8) & 0xFF);
baos.write(length & 0xFF);
baos.write(buffer, 0, length);
// g
buffer = dssKey.getParams().getG().toByteArray();
length = buffer.length;
baos.write(length >>> 24);
baos.write((length >>> 16) & 0xFF);
baos.write((length >>> 8) & 0xFF);
baos.write(length & 0xFF);
baos.write(buffer, 0, length);
// y
buffer = dssKey.getY().toByteArray();
length = buffer.length;
baos.write(length >>> 24);
baos.write((length >>> 16) & 0xFF);
baos.write((length >>> 8) & 0xFF);
baos.write(length & 0xFF);
baos.write(buffer, 0, length);
return baos.toByteArray();
}
public PublicKey decodePublicKey(byte[] k)
{
// magic
if (k[0] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]
|| k[1] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[1]
|| k[2] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[2]
|| k[3] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[3])
{
throw new IllegalArgumentException("magic");
}
// version
if (k[4] != 0x01)
{
throw new IllegalArgumentException("version");
}
int i = 5;
int l;
byte[] buffer;
// p
l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8
| (k[i++] & 0xFF);
buffer = new byte[l];
System.arraycopy(k, i, buffer, 0, l);
i += l;
BigInteger p = new BigInteger(1, buffer);
// q
l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8
| (k[i++] & 0xFF);
buffer = new byte[l];
System.arraycopy(k, i, buffer, 0, l);
i += l;
BigInteger q = new BigInteger(1, buffer);
// g
l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8
| (k[i++] & 0xFF);
buffer = new byte[l];
System.arraycopy(k, i, buffer, 0, l);
i += l;
BigInteger g = new BigInteger(1, buffer);
// y
l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8
| (k[i++] & 0xFF);
buffer = new byte[l];
System.arraycopy(k, i, buffer, 0, l);
i += l;
BigInteger y = new BigInteger(1, buffer);
return new DSSPublicKey(p, q, g, y);
}
/**
* <p>Returns the encoded form of the designated DSS (Digital Signature
* Standard) private key according to the <i>Raw</i> format supported by
* this library.</p>
*
* <p>The <i>Raw</i> format for a DSA private key, in this implementation, is
* a byte sequence consisting of the following:</p>
* <ol>
* <li>4-byte magic consisting of the value of the literal
* {@link Registry#MAGIC_RAW_DSS_PRIVATE_KEY},<li>
* <li>1-byte version consisting of the constant: 0x01,</li>
* <li>4-byte count of following bytes representing the DSA parameter
* <code>p</code> in internet order,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the DSA parameter
* <code>p</code>,</li>
* <li>4-byte count of following bytes representing the DSA parameter
* <code>q</code>,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the DSA parameter
* <code>q</code>,</li>
* <li>4-byte count of following bytes representing the DSA parameter
* <code>g</code>,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the DSA parameter
* <code>g</code>,</li>
* <li>4-byte count of following bytes representing the DSA parameter
* <code>x</code>,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the DSA parameter
* <code>x</code>,</li>
* </ol>
*
* @param key the key to encode.
* @return the <i>Raw</i> format encoding of the designated key.
* @throws IllegalArgumentException if the designated key is not a DSS
* (Digital Signature Standard) one.
*/
public byte[] encodePrivateKey(PrivateKey key)
{
if (!(key instanceof DSSPrivateKey))
{
throw new IllegalArgumentException("key");
}
DSSPrivateKey dssKey = (DSSPrivateKey) key;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// magic
baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]);
baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[1]);
baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[2]);
baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[3]);
// version
baos.write(0x01);
// p
byte[] buffer = dssKey.getParams().getP().toByteArray();
int length = buffer.length;
baos.write(length >>> 24);
baos.write((length >>> 16) & 0xFF);
baos.write((length >>> 8) & 0xFF);
baos.write(length & 0xFF);
baos.write(buffer, 0, length);
// q
buffer = dssKey.getParams().getQ().toByteArray();
length = buffer.length;
baos.write(length >>> 24);
baos.write((length >>> 16) & 0xFF);
baos.write((length >>> 8) & 0xFF);
baos.write(length & 0xFF);
baos.write(buffer, 0, length);
// g
buffer = dssKey.getParams().getG().toByteArray();
length = buffer.length;
baos.write(length >>> 24);
baos.write((length >>> 16) & 0xFF);
baos.write((length >>> 8) & 0xFF);
baos.write(length & 0xFF);
baos.write(buffer, 0, length);
// x
buffer = dssKey.getX().toByteArray();
length = buffer.length;
baos.write(length >>> 24);
baos.write((length >>> 16) & 0xFF);
baos.write((length >>> 8) & 0xFF);
baos.write(length & 0xFF);
baos.write(buffer, 0, length);
return baos.toByteArray();
}
public PrivateKey decodePrivateKey(byte[] k)
{
// magic
if (k[0] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]
|| k[1] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[1]
|| k[2] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[2]
|| k[3] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[3])
{
throw new IllegalArgumentException("magic");
}
// version
if (k[4] != 0x01)
{
throw new IllegalArgumentException("version");
}
int i = 5;
int l;
byte[] buffer;
// p
l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8
| (k[i++] & 0xFF);
buffer = new byte[l];
System.arraycopy(k, i, buffer, 0, l);
i += l;
BigInteger p = new BigInteger(1, buffer);
// q
l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8
| (k[i++] & 0xFF);
buffer = new byte[l];
System.arraycopy(k, i, buffer, 0, l);
i += l;
BigInteger q = new BigInteger(1, buffer);
// g
l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8
| (k[i++] & 0xFF);
buffer = new byte[l];
System.arraycopy(k, i, buffer, 0, l);
i += l;
BigInteger g = new BigInteger(1, buffer);
// x
l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8
| (k[i++] & 0xFF);
buffer = new byte[l];
System.arraycopy(k, i, buffer, 0, l);
i += l;
BigInteger x = new BigInteger(1, buffer);
return new DSSPrivateKey(p, q, g, x);
}
}
@@ -0,0 +1,248 @@
/* DSSKeyPairX509Codec.java -- X.509 Encoding/Decoding handler
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.security.key.dss;
import gnu.java.security.OID;
import gnu.java.security.Registry;
import gnu.java.security.der.BitString;
import gnu.java.security.der.DER;
import gnu.java.security.der.DERReader;
import gnu.java.security.der.DERValue;
import gnu.java.security.der.DERWriter;
import gnu.java.security.key.IKeyPairCodec;
import gnu.java.security.util.DerUtil;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidParameterException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
/**
* An implementation of an {@link IKeyPairCodec} that knows how to encode /
* decode X.509 ASN.1 external representation of DSS public keys.
*/
public class DSSKeyPairX509Codec
implements IKeyPairCodec
{
private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING);
// implicit 0-arguments constructor
public int getFormatID()
{
return X509_FORMAT;
}
/**
* Returns the X.509 ASN.1 <i>SubjectPublicKeyInfo</i> representation of a
* DSA public key. The ASN.1 specification, as defined in RFC-3280, and
* RFC-2459, is as follows:
*
* <pre>
* SubjectPublicKeyInfo ::= SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING
* }
*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL
* }
*
* DssParams ::= SEQUENCE {
* p INTEGER,
* q INTEGER,
* g INTEGER
* }
* </pre>
*
* <p>The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
* DER-encoded form of the DSA public key as an INTEGER.</p>
*
* <pre>
* DSAPublicKey ::= INTEGER -- public key, Y
* </pre>
*
* @param key the {@link PublicKey} instance to encode. MUST be an instance of
* {@link DSSPublicKey}.
* @return the ASN.1 representation of the <i>SubjectPublicKeyInfo</i> in an
* X.509 certificate.
* @throw InvalidParameterException if <code>key</code> is not an instance
* of {@link DSSPublicKey} or if an exception occurs during the
* marshalling process.
*/
public byte[] encodePublicKey(PublicKey key)
{
if (! (key instanceof DSSPublicKey))
throw new InvalidParameterException("key");
DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID);
DSSPublicKey dssKey = (DSSPublicKey) key;
BigInteger p = dssKey.getParams().getP();
BigInteger q = dssKey.getParams().getQ();
BigInteger g = dssKey.getParams().getG();
BigInteger y = dssKey.getY();
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);
DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params);
ArrayList algorithmID = new ArrayList(2);
algorithmID.add(derOID);
algorithmID.add(derParams);
DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
algorithmID);
DERValue 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();
e.initCause(x);
throw e;
}
return result;
}
/**
* @throws InvalidParameterException ALWAYS.
*/
public byte[] encodePrivateKey(PrivateKey key)
{
throw new InvalidParameterException("Wrong format for private keys");
}
/**
* @param input the byte array to unmarshall into a valid DSS
* {@link PublicKey} instance. MUST NOT be null.
* @return a new instance of a {@link DSSPublicKey} decoded from the
* <i>SubjectPublicKeyInfo</i> material in an X.509 certificate.
* @throw InvalidParameterException if an exception occurs during the
* unmarshalling process.
*/
public PublicKey decodePublicKey(byte[] input)
{
if (input == null)
throw new InvalidParameterException("Input bytes MUST NOT be null");
BigInteger p, g, q, 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 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 (! (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();
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");
}
}
@@ -0,0 +1,201 @@
/* 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.security.Registry;
import gnu.java.security.key.IKeyPairCodec;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.interfaces.DSAPrivateKey;
/**
* <p>An object that embodies a DSS (Digital Signature Standard) private key.</p>
*
* @version $Revision: 1.2 $
* @see #getEncoded
*/
public class DSSPrivateKey extends DSSKey implements PrivateKey, DSAPrivateKey
{
// Constants and variables
// -------------------------------------------------------------------------
/**
* <p>A randomly or pseudorandomly generated integer with <code>0 &lt; x &lt;
* q</code>.</p>
*/
private final BigInteger x;
// Constructor(s)
// -------------------------------------------------------------------------
/**
* Convenience constructor. Calls the constructor with 5 arguments passing
* {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred
* encoding format.
*
* @param p the public modulus.
* @param q the public prime divisor of <code>p-1</code>.
* @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
* <sub>p</sub></code>.
* @param x the private key part.
*/
public DSSPrivateKey(BigInteger p, BigInteger q, BigInteger g, BigInteger x)
{
this(Registry.RAW_ENCODING_ID, p, q, g, x);
}
/**
* Constructs a new instance of a <code>DSSPrivateKey</code> given the
* designated arguments.
*
* @param preferredFormat the indetifier of the preferred encoding format to
* use when externalizing this key.
* @param p the public modulus.
* @param q the public prime divisor of <code>p-1</code>.
* @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
* <sub>p</sub></code>.
* @param x the private key part.
*/
public DSSPrivateKey(int preferredFormat, BigInteger p, BigInteger q,
BigInteger g, BigInteger x)
{
super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID
: preferredFormat,
p, q, g);
this.x = x;
}
// Class methods
// -------------------------------------------------------------------------
/**
* A class method that takes the output of the <code>encodePrivateKey()</code>
* method of a DSS keypair codec object (an instance implementing
* {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs
* an instance of this object.
*
* @param k the contents of a previously encoded instance of this object.
* @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in
* <code>k</code>, to represent a valid encoding of an
* instance of this object.
* @exception IllegalArgumentException if the byte sequence does not represent
* a valid encoding of an instance of this object.
*/
public static DSSPrivateKey valueOf(byte[] k)
{
// try RAW codec
if (k[0] == Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0])
try
{
return (DSSPrivateKey) new DSSKeyPairRawCodec().decodePrivateKey(k);
}
catch (IllegalArgumentException ignored)
{
}
// try PKCS#8 codec
return (DSSPrivateKey) new DSSKeyPairPKCS8Codec().decodePrivateKey(k);
}
// Instance methods
// -------------------------------------------------------------------------
// java.security.interfaces.DSAPrivateKey interface implementation ---------
public BigInteger getX()
{
return x;
}
// Other instance methods --------------------------------------------------
/**
* <p>Returns the encoded form of this private key according to the
* designated format.</p>
*
* @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;
}
/**
* <p>Returns <code>true</code> if the designated object is an instance of
* {@link DSAPrivateKey} and has the same DSS (Digital Signature Standard)
* parameter values as this one.</p>
*
* @param obj the other non-null DSS key to compare to.
* @return <code>true</code> if the designated object is of the same type and
* value as this one.
*/
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (!(obj instanceof DSAPrivateKey))
{
return false;
}
DSAPrivateKey that = (DSAPrivateKey) obj;
return super.equals(that) && x.equals(that.getX());
}
}
@@ -0,0 +1,201 @@
/* 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.security.Registry;
import gnu.java.security.key.IKeyPairCodec;
import java.math.BigInteger;
import java.security.PublicKey;
import java.security.interfaces.DSAPublicKey;
/**
* <p>An object that embodies a DSS (Digital Signature Standard) public key.</p>
*
* @version $Revision: 1.2 $
* @see #getEncoded
*/
public class DSSPublicKey extends DSSKey implements PublicKey, DSAPublicKey
{
// Constants and variables
// -------------------------------------------------------------------------
/**
* <code>y = g<sup>x</sup> mod p</code> where <code>x</code> is the private
* part of the DSA key.
*/
private final BigInteger y;
// Constructor(s)
// -------------------------------------------------------------------------
/**
* Conveience constructor. Calls the constructor with 5 arguments passing
* {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred
* encoding format.
*
* @param p the public modulus.
* @param q the public prime divisor of <code>p-1</code>.
* @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
* <sub>p</sub></code>.
* @param y the public key part.
*/
public DSSPublicKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y)
{
this(Registry.RAW_ENCODING_ID, p, q, g, y);
}
/**
* Constructs a new instance of <code>DSSPublicKey</code> given the designated
* arguments.
*
* @param preferredFormat the identifier of the preferred encoding format to
* use when externalizing this key.
* @param p the public modulus.
* @param q the public prime divisor of <code>p-1</code>.
* @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
* <sub>p</sub></code>.
* @param y the public key part.
*/
public DSSPublicKey(int preferredFormat, BigInteger p, BigInteger q,
BigInteger g, BigInteger y)
{
super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID
: preferredFormat,
p, q, g);
this.y = y;
}
// Class methods
// -------------------------------------------------------------------------
/**
* A class method that takes the output of the <code>encodePublicKey()</code>
* method of a DSS keypair codec object (an instance implementing
* {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs
* an instance of this object.
*
* @param k the contents of a previously encoded instance of this object.
* @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in
* <code>k</code>, to represent a valid encoding of an
* instance of this object.
* @exception IllegalArgumentException if the byte sequence does not represent
* a valid encoding of an instance of this object.
*/
public static DSSPublicKey valueOf(byte[] k)
{
// try RAW codec
if (k[0] == Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0])
try
{
return (DSSPublicKey) new DSSKeyPairRawCodec().decodePublicKey(k);
}
catch (IllegalArgumentException ignored)
{
}
// try X.509 codec
return (DSSPublicKey) new DSSKeyPairX509Codec().decodePublicKey(k);
}
// Instance methods
// -------------------------------------------------------------------------
// java.security.interfaces.DSAPublicKey interface implementation ----------
public BigInteger getY()
{
return y;
}
// Other instance methods --------------------------------------------------
/**
* <p>Returns the encoded form of this public key according to the designated
* format.</p>
*
* @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;
}
/**
* <p>Returns <code>true</code> if the designated object is an instance of
* {@link DSAPublicKey} and has the same DSS (Digital Signature Standard)
* parameter values as this one.</p>
*
* @param obj the other non-null DSS key to compare to.
* @return <code>true</code> if the designated object is of the same type and
* value as this one.
*/
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (!(obj instanceof DSAPublicKey))
{
return false;
}
DSAPublicKey that = (DSAPublicKey) obj;
return super.equals(that) && y.equals(that.getY());
}
}
@@ -0,0 +1,296 @@
/* 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 gnu.java.security.util.Prime2;
import java.math.BigInteger;
import java.security.SecureRandom;
/**
* <p>An implementation of the DSA parameters generation as described in
* FIPS-186.</p>
*
* References:<br>
* <a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
* Standard (DSS)</a>, Federal Information Processing Standards Publication 186.
* National Institute of Standards and Technology.
*
* @version $Revision: 1.2 $
*/
public class FIPS186
{
// Constants and variables
// -------------------------------------------------------------------------
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 = new BigInteger("2");
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;
// Constructor(s)
// -------------------------------------------------------------------------
public FIPS186(int L, SecureRandom rnd)
{
super();
this.L = L;
this.rnd = rnd;
}
// Class methods
// -------------------------------------------------------------------------
// Instance methods
// -------------------------------------------------------------------------
/**
* This method generates the DSS <code>p</code>, <code>q</code>, and
* <code>g</code> parameters only when <code>L</code> (the modulus length)
* is not one of the following: <code>512</code>, <code>768</code> and
* <code>1024</code>. For those values of <code>L</code>, this implementation
* uses pre-computed values of <code>p</code>, <code>q</code>, and
* <code>g</code> given in the document <i>CryptoSpec</i> included in the
* security guide documentation of the standard JDK distribution.<p>
*
* The DSS requires two primes , <code>p</code> and <code>q</code>,
* satisfying the following three conditions:
*
* <ul>
* <li><code>2<sup>159</sup> &lt; q &lt; 2<sup>160</sup></code></li>
* <li><code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup></code> for a
* specified <code>L</code>, where <code>L = 512 + 64j</code> for some
* <code>0 &lt;= j &lt;= 8</code></li>
* <li>q divides p - 1.</li>
* </ul>
*
* The algorithm used to find these primes is as described in FIPS-186,
* section 2.2: GENERATION OF PRIMES. This prime generation scheme starts by
* using the {@link Sha160} and a user supplied <i>SEED</i>
* to construct a prime, <code>q</code>, in the range 2<sup>159</sup> &lt; q
* &lt; 2<sup>160</sup>. Once this is accomplished, the same <i>SEED</i>
* value is used to construct an <code>X</code> in the range <code>2<sup>L-1
* </sup> &lt; X &lt; 2<sup>L</sup>. The prime, <code>p</code>, is then
* formed by rounding <code>X</code> to a number congruent to <code>1 mod
* 2q</code>. In this implementation we use the same <i>SEED</i> value given
* in FIPS-186, Appendix 5.
*/
public BigInteger[] generateParameters()
{
int counter, offset;
BigInteger SEED, alpha, U, q, OFFSET, SEED_PLUS_OFFSET, W, X, p, c, g;
byte[] a, u;
byte[] kb = new byte[20]; // to hold 160 bits of randomness
// Let L-1 = n*160 + b, where b and n are integers and 0 <= b < 160.
int b = (L - 1) % 160;
int n = (L - 1 - b) / 160;
BigInteger[] V = new BigInteger[n + 1];
algorithm: while (true)
{
step1: while (true)
{
// 1. Choose an arbitrary sequence of at least 160 bits and
// call it SEED.
nextRandomBytes(kb);
SEED = new BigInteger(1, kb).setBit(159).setBit(0);
// Let g be the length of SEED in bits. here always 160
// 2. Compute: U = SHA[SEED] XOR SHA[(SEED+1) mod 2**g]
alpha = SEED.add(BigInteger.ONE).mod(TWO_POW_160);
synchronized (sha)
{
a = SEED.toByteArray();
sha.update(a, 0, a.length);
a = sha.digest();
u = alpha.toByteArray();
sha.update(u, 0, u.length);
u = sha.digest();
}
for (int i = 0; i < a.length; i++)
{
a[i] ^= u[i];
}
U = new BigInteger(1, a);
// 3. Form q from U by setting the most significant bit (the
// 2**159 bit) and the least significant bit to 1. In terms of
// boolean operations, q = U OR 2**159 OR 1. Note that
// 2**159 < q < 2**160.
q = U.setBit(159).setBit(0);
// 4. Use a robust primality testing algorithm to test whether
// q is prime(1). A robust primality test is one where the
// probability of a non-prime number passing the test is at
// most 1/2**80.
// 5. If q is not prime, go to step 1.
if (Prime2.isProbablePrime(q))
{
break step1;
}
} // step1
// 6. Let counter = 0 and offset = 2.
counter = 0;
offset = 2;
step7: 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 (Prime2.isProbablePrime(p))
{
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 };
}
// helper methods ----------------------------------------------------------
/**
* 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;
}
}
@@ -0,0 +1,181 @@
/* 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.security.Registry;
import gnu.java.security.key.IKeyPairCodec;
import gnu.java.security.util.FormatUtil;
import java.math.BigInteger;
import java.security.Key;
import java.security.interfaces.RSAKey;
/**
* <p>A base asbtract class for both public and private RSA keys.</p>
*
* @version $Revision: 1.3 $
*/
public abstract class GnuRSAKey implements Key, RSAKey
{
// Constants and variables
// -------------------------------------------------------------------------
/** 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;
// Constructor(s)
// -------------------------------------------------------------------------
/**
* Trivial protected constructor.
*
* @param defaultFormat the identifier of the encoding format to use by
* default when externalizing the key.
* @param n the public modulus <code>n</code>.
* @param e the public exponent <code>e</code>.
*/
protected GnuRSAKey(int defaultFormat, BigInteger n, BigInteger e)
{
super();
this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID
: defaultFormat;
this.n = n;
this.e = e;
}
// Class methods
// -------------------------------------------------------------------------
// Instance methods
// -------------------------------------------------------------------------
// java.security.interfaces.RSAKey interface implementation ----------------
public BigInteger getModulus()
{
return getN();
}
// java.security.Key interface implementation ------------------------------
public String getAlgorithm()
{
return Registry.RSA_KPG;
}
/** @deprecated see getEncoded(int). */
public byte[] getEncoded()
{
return getEncoded(IKeyPairCodec.RAW_FORMAT);
}
public String getFormat()
{
return FormatUtil.getEncodingShortName(defaultFormat);
}
// Other instance methods --------------------------------------------------
/**
* <p>Returns the modulus <code>n</code>.</p>
*
* @return the modulus <code>n</code>.
*/
public BigInteger getN()
{
return n;
}
/**
* <p>Returns the public exponent <code>e</code>.</p>
*
* @return the public exponent <code>e</code>.
*/
public BigInteger getPublicExponent()
{
return getE();
}
/**
* <p>Same as {@link #getPublicExponent()}.</p>
*
* @return the public exponent <code>e</code>.
*/
public BigInteger getE()
{
return e;
}
/**
* <p>Returns <code>true</code> if the designated object is an instance of
* {@link RSAKey} and has the same RSA parameter values as this one.</p>
*
* @param obj the other non-null RSA key to compare to.
* @return <code>true</code> if the designated object is of the same type and
* value as this one.
*/
public boolean equals(final Object obj)
{
if (obj == null)
{
return false;
}
if (!(obj instanceof RSAKey))
{
return false;
}
final RSAKey that = (RSAKey) obj;
return n.equals(that.getModulus());
}
// abstract methods to be implemented by subclasses ------------------------
public abstract byte[] getEncoded(int format);
}
@@ -0,0 +1,299 @@
/* 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.security.Registry;
import gnu.java.security.key.IKeyPairCodec;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
/**
* <p>An object that embodies an RSA private key.</p>
*
* <p>References:</p>
* <ol>
* <li><a href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
* RSA-PSS Signature Scheme with Appendix, part B.</a><br>
* Primitive specification and supporting documentation.<br>
* Jakob Jonsson and Burt Kaliski.</li>
* </ol>
*
* @version $Revision: 1.3 $
*/
public class GnuRSAPrivateKey extends GnuRSAKey implements PrivateKey,
RSAPrivateCrtKey
{
// Constants and variables
// -------------------------------------------------------------------------
/** The first prime divisor of the modulus. */
private final BigInteger p;
/** The second prime divisor of the modulus. */
private final BigInteger q;
/** The public exponent of an RSA key. */
// private final BigInteger e;
/** 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;
// Constructor(s)
// -------------------------------------------------------------------------
/**
* 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 <code>GnuRSAPrivateKey</code> given the
* designated arguments.
*
* @param preferredFormat the indetifier of the preferred encoding format to
* use when externalizing this key.
* @param p the modulus first prime divisor.
* @param q the modulus second prime divisor.
* @param e the public exponent.
* @param d the private exponent.
*/
public GnuRSAPrivateKey(int preferredFormat, BigInteger p, BigInteger q,
BigInteger e, BigInteger d)
{
this(preferredFormat, p.multiply(q), e, d, p, q,
e.modInverse(p.subtract(BigInteger.ONE)),
e.modInverse(q.subtract(BigInteger.ONE)),
q.modInverse(p));
}
/**
* Constructs a new instance of a <code>GnuRSAPrivateKey</code> given the
* designated arguments.
*
* @param preferredFormat the indetifier of the preferred encoding format to
* use when externalizing this key.
* @param n the public modulus, which is also the product of <code>p</code>
* and <code>q</code>.
* @param e the public exponent.
* @param d the private exponent.
* @param p the modulus first prime divisor.
* @param q the modulus second prime divisor.
* @param dP the first prime's exponen. A positive integer less than
* <code>p</code> and <code>q</code>, satisfying <code>e * dP = 1 (mod p-1)
* </code>.
* @param dQ the second prime's exponent. A positive integer less than
* <code>p</code> and <code>q</code>, satisfying <code>e * dQ = 1 (mod p-1)
* </code>.
* @param qInv the Chinese Remainder Theorem coefiicient. A positive integer
* less than <code>p</code>, satisfying <code>q * qInv = 1 (mod p)</code>.
*/
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;
}
// Class methods
// -------------------------------------------------------------------------
/**
* A class method that takes the output of the <code>encodePrivateKey()</code>
* 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
* <code>k</code>, to represent a valid encoding of an instance
* of this object.
* @throws IllegalArgumentException if the byte sequence does not represent a
* valid encoding of an instance of this object.
*/
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);
}
// Instance methods
// -------------------------------------------------------------------------
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;
}
// java.security.interfaces.RSAPrivateKey interface implementation ---------
public BigInteger getPrivateExponent()
{
return d;
}
// Other instance methods --------------------------------------------------
/**
* 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;
}
/**
* <p>Returns <code>true</code> if the designated object is an instance of
* this class and has the same RSA parameter values as this one.</p>
*
* @param obj the other non-null RSA key to compare to.
* @return <code>true</code> if the designated object is of the same type
* and value as this one.
*/
public boolean equals(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;
}
}
@@ -0,0 +1,185 @@
/* 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.security.Registry;
import gnu.java.security.key.IKeyPairCodec;
import java.math.BigInteger;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
/**
* <p>An object that encapsulates an RSA public key.</p>
*
* <p>References:</p>
* <ol>
* <li><a href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
* RSA-PSS Signature Scheme with Appendix, part B.</a><br>
* Primitive specification and supporting documentation.<br>
* Jakob Jonsson and Burt Kaliski.</li>
* </ol>
*
* @version $Revision: 1.2 $
*/
public class GnuRSAPublicKey extends GnuRSAKey implements PublicKey,
RSAPublicKey
{
// Constants and variables
// -------------------------------------------------------------------------
// Constructor(s)
// -------------------------------------------------------------------------
/**
* 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 <code>GnuRSAPublicKey</code> given the
* designated arguments.
*
* @param preferredFormat the identifier of the preferred encoding format to
* use when externalizing this key.
* @param n the modulus.
* @param e the public exponent.
*/
public GnuRSAPublicKey(int preferredFormat, BigInteger n, BigInteger e)
{
super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID
: preferredFormat,
n, e);
}
// Class methods
// -------------------------------------------------------------------------
/**
* A class method that takes the output of the <code>encodePublicKey()</code>
* 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
* <code>k</code>, to represent a valid encoding of an instance
* of this object.
* @throws IllegalArgumentException if the byte sequence does not represent a
* valid encoding of an instance of this object.
*/
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);
}
// Instance methods
// -------------------------------------------------------------------------
/**
* <p>Returns the encoded form of this public key according to the designated
* format.</p>
*
* @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;
}
/**
* <p>Returns <code>true</code> if the designated object is an instance of
* this class and has the same RSA parameter values as this one.</p>
*
* @param obj the other non-null RSA key to compare to.
* @return <code>true</code> if the designated object is of the same type and
* value as this one.
*/
public boolean equals(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());
}
}
@@ -0,0 +1,264 @@
/* 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.Registry;
import gnu.java.security.key.IKeyPairGenerator;
import gnu.java.security.util.PRNG;
import gnu.java.security.util.Prime2;
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;
/**
* <p>A key-pair generator for asymetric keys to use in conjunction with the RSA
* scheme.</p>
*
* <p>Reference:</p>
* <ol>
* <li><a href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
* RSA-PSS Signature Scheme with Appendix</a>, part B. Primitive
* specification and supporting documentation. Jakob Jonsson and Burt Kaliski.
* </li>
* <li><a href="http://www.cacr.math.uwaterloo.ca/hac/">Handbook of Applied
* Cryptography</a>, Alfred J. Menezes, Paul C. van Oorschot and Scott A.
* Vanstone. Section 11.3 RSA and related signature schemes.</li>
* </ol>
*/
public class RSAKeyPairGenerator implements IKeyPairGenerator
{
// Constants and variables
// -------------------------------------------------------------------------
/** 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 <code>n</code>, and <code>e</code> values. The
* default is to generate <code>n</code> and use a fixed value for
* <code>e</.code> (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;
// Constructor(s)
// -------------------------------------------------------------------------
// implicit 0-arguments constructor
// Class methods
// -------------------------------------------------------------------------
// gnu.crypto.key.IKeyPairGenerator interface implementation ---------------
public String name()
{
return Registry.RSA_KPG;
}
/**
* <p>Configures this instance.</p>
*
* @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)
{
// 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();
}
/**
* <p>The algorithm used here is described in <i>nessie-pss-B.pdf</i>
* document which is part of the RSA-PSS submission to NESSIE.</p>
*
* @return an RSA keypair.
*/
public KeyPair 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
&& Prime2.isProbablePrime(p) && 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 && Prime2.isProbablePrime(q)
&& 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);
return new KeyPair(pubK, secK);
}
// helper methods ----------------------------------------------------------
/**
* <p>Fills the designated byte array with random data.</p>
*
* @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;
}
}
@@ -0,0 +1,284 @@
/* RSAKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.security.key.rsa;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidParameterException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import gnu.java.security.OID;
import gnu.java.security.Registry;
import gnu.java.security.der.DER;
import gnu.java.security.der.DERReader;
import gnu.java.security.der.DERValue;
import gnu.java.security.der.DERWriter;
import gnu.java.security.key.IKeyPairCodec;
import gnu.java.security.util.DerUtil;
/**
* 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 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 <i>PrivateKeyInfo</i> representation of an RSA
* private key. The ASN.1 specification is as follows:
*
* <pre>
* PrivateKeyInfo ::= SEQUENCE {
* version INTEGER, -- MUST be 0
* privateKeyAlgorithm AlgorithmIdentifier,
* privateKey OCTET STRING
* }
*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL
* }
* </pre>
*
* <p>The <i>privateKey</i> field, which is an OCTET STRING, contains the
* DER-encoded form of the RSA private key defined as:</p>
*
* <pre>
* RSAPrivateKey ::= SEQUENCE {
* version INTEGER, -- MUST be 0
* modulus INTEGER, -- n
* publicExponent INTEGER, -- e
* privateExponent INTEGER, -- d
* prime1 INTEGER, -- p
* prime2 INTEGER, -- q
* exponent1 INTEGER, -- d mod (p-1)
* exponent2 INTEGER, -- d mod (q-1)
* coefficient INTEGER, -- (inverse of q) mod p
* }
* </pre>
*
* @return the DER encoded form of the ASN.1 representation of the
* <i>PrivateKeyInfo</i> field for an RSA {@link PrivateKey}..
* @throw InvalidParameterException if an error occurs during the marshalling
* process.
*/
public byte[] encodePrivateKey(PrivateKey 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(1);
algorithmID.add(derOID);
DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
algorithmID);
DERValue derRSAVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
DERValue derN = new DERValue(DER.INTEGER, n);
DERValue derE = new DERValue(DER.INTEGER, e);
DERValue derD = new DERValue(DER.INTEGER, d);
DERValue derP = new DERValue(DER.INTEGER, p);
DERValue derQ = new DERValue(DER.INTEGER, q);
DERValue derDP = new DERValue(DER.INTEGER, dP);
DERValue derDQ = new DERValue(DER.INTEGER, dQ);
DERValue derQInv = new DERValue(DER.INTEGER, qInv);
ArrayList rsaPrivateKey = new ArrayList();
rsaPrivateKey.add(derRSAVersion);
rsaPrivateKey.add(derN);
rsaPrivateKey.add(derE);
rsaPrivateKey.add(derD);
rsaPrivateKey.add(derP);
rsaPrivateKey.add(derQ);
rsaPrivateKey.add(derDP);
rsaPrivateKey.add(derDQ);
rsaPrivateKey.add(derQInv);
DERValue derRSAPrivateKey = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
rsaPrivateKey);
byte[] pkBytes = derRSAPrivateKey.getEncoded();
DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, pkBytes);
ArrayList pki = new ArrayList(3);
pki.add(derVersion);
pki.add(derAlgorithmID);
pki.add(derPrivateKey);
DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki);
byte[] result;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
DERWriter.write(baos, derPKI);
result = baos.toByteArray();
}
catch (IOException x)
{
InvalidParameterException y = new InvalidParameterException();
y.initCause(x);
throw y;
}
return result;
}
/**
* @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
* <i>PrivateKeyInfo</i> material fed as <code>input</code>.
* @throw InvalidParameterException if an exception occurs during the
* unmarshalling process.
*/
public PrivateKey decodePrivateKey(byte[] input)
{
if (input == null)
throw new InvalidParameterException("Input bytes MUST NOT be null");
BigInteger version, n, e, d, p, q, dP, dQ, qInv;
DERReader der = new DERReader(input);
try
{
DERValue derPKI = der.read();
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);
DERValue 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;
}
return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, n, e, d, p, q,
dP, dQ, qInv);
}
}
@@ -0,0 +1,332 @@
/* 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;
/**
* <p>An object that implements the {@link IKeyPairCodec} interface for the
* <i>Raw</i> format to use with RSA keypairs.</p>
*
* @version $Revision: 1.1 $
*/
public class RSAKeyPairRawCodec implements IKeyPairCodec
{
// Constants and variables
// -------------------------------------------------------------------------
// Constructor(s)
// -------------------------------------------------------------------------
// implicit 0-arguments constructor
// Class methods
// -------------------------------------------------------------------------
// Instance methods
// -------------------------------------------------------------------------
// gnu.crypto.key.IKeyPairCodec interface implementation -------------------
public int getFormatID()
{
return RAW_FORMAT;
}
/**
* <p>Returns the encoded form of the designated RSA public key according to
* the <i>Raw</i> format supported by this library.</p>
*
* <p>The <i>Raw</i> format for an RSA public key, in this implementation, is
* a byte sequence consisting of the following:</p>
*
* <ol>
* <li>4-byte magic consisting of the value of the literal
* {@link Registry#MAGIC_RAW_RSA_PUBLIC_KEY},<li>
* <li>1-byte version consisting of the constant: 0x01,</li>
* <li>4-byte count of following bytes representing the RSA parameter
* <code>n</code> (the modulus) in internet order,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the RSA parameter <code>n</code>,</li>
* <li>4-byte count of following bytes representing the RSA parameter
* <code>e</code> (the public exponent) in internet order,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the RSA parameter <code>e</code>.</li>
* </ol>
*
* @param key the key to encode.
* @return the <i>Raw</i> 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);
}
/**
* <p>Returns the encoded form of the designated RSA private key according to
* the <i>Raw</i> format supported by this library.</p>
*
* <p>The <i>Raw</i> format for an RSA private key, in this implementation,
* is a byte sequence consisting of the following:</p>
*
* <ol>
* <li>4-byte magic consisting of the value of the literal
* {@link Registry#MAGIC_RAW_RSA_PRIVATE_KEY},<li>
* <li>1-byte version consisting of the constant: 0x01,</li>
* <li>4-byte count of following bytes representing the RSA parameter
* <code>p</code> (the first prime factor of the modulus) in internet
* order,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the RSA parameter <code>p</code>,</li>
* <li>4-byte count of following bytes representing the RSA parameter
* <code>q</code> (the second prime factor of the modulus) in internet
* order,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the RSA parameter <code>q</code>,</li>
* <li>4-byte count of following bytes representing the RSA parameter
* <code>e</code> (the public exponent) in internet order,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the RSA parameter <code>e</code>,</li>
* <li>4-byte count of following bytes representing the RSA parameter
* <code>d</code> (the private exponent) in internet order,</li>
* <li>n-bytes representation of a {@link BigInteger} obtained by invoking
* the <code>toByteArray()</code> method on the RSA parameter <code>d</code>,</li>
* </ol>
*
* @param key the key to encode.
* @return the <i>Raw</i> 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);
}
}
@@ -0,0 +1,248 @@
/* RSAKeyPairX509Codec.java -- X.509 Encoding/Decoding handler
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.security.key.rsa;
import gnu.java.security.OID;
import gnu.java.security.Registry;
import gnu.java.security.der.BitString;
import gnu.java.security.der.DER;
import gnu.java.security.der.DERReader;
import gnu.java.security.der.DERValue;
import gnu.java.security.der.DERWriter;
import gnu.java.security.key.IKeyPairCodec;
import 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 <i>SubjectPublicKeyInfo</i> representation of an
* RSA public key. The ASN.1 specification, as defined in RFC-3280, and
* RFC-2459, is as follows:
*
* <pre>
* SubjectPublicKeyInfo ::= SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING
* }
*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL
* }
* </pre>
* <p>
* As indicated in RFC-2459: "The parameters field shall have ASN.1 type NULL
* for this algorithm identifier.".
* <p>
* The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
* DER-encoded form of the RSA public key defined as:
*
* <pre>
* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
* publicExponent INTEGER -- e
* }
* </pre>
*
* @param key the {@link PublicKey} instance to encode. MUST be an instance of
* {@link GnuRSAPublicKey}.
* @return the ASN.1 representation of the <i>SubjectPublicKeyInfo</i> in an
* X.509 certificate.
* @throw InvalidParameterException if <code>key</code> is not an instance
* of {@link GnuRSAPublicKey} or if an exception occurs during the
* marshalling process.
*/
public byte[] encodePublicKey(PublicKey key)
{
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(1);
algorithmID.add(derOID);
DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
algorithmID);
ArrayList publicKey = new ArrayList(2);
publicKey.add(derN);
publicKey.add(derE);
DERValue derPublicKey = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
publicKey);
byte[] spkBytes = derPublicKey.getEncoded();
DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(spkBytes));
ArrayList spki = new ArrayList(2);
spki.add(derAlgorithmID);
spki.add(derSPK);
DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki);
byte[] result;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
DERWriter.write(baos, derSPKI);
result = baos.toByteArray();
}
catch (IOException x)
{
InvalidParameterException y = new InvalidParameterException();
y.initCause(x);
throw y;
}
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
* <i>SubjectPublicKeyInfo</i> material in an X.509 certificate.
* @throw InvalidParameterException if an exception occurs during the
* unmarshalling process.
*/
public PublicKey decodePublicKey(byte[] input)
{
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();
y.initCause(x);
throw y;
}
PublicKey result = new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e);
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");
}
}