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,306 @@
/* EME_PKCS1_V1_5.java --
Copyright (C) 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.sig.rsa;
import gnu.java.security.prng.IRandom;
import gnu.java.security.prng.LimitReachedException;
import gnu.java.security.util.PRNG;
import java.io.ByteArrayOutputStream;
import java.security.interfaces.RSAKey;
import java.util.Random;
/**
* <p>An implementation of the EME-PKCS1-V1.5 encoding and decoding methods.</p>
*
* <p>EME-PKCS1-V1.5 is parameterised by the entity <code>k</code> which is the
* byte count of an RSA public shared modulus.</p>
*
* <p>References:</p>
* <ol>
* <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
* Standards (PKCS) #1:</a><br>
* RSA Cryptography Specifications Version 2.1.<br>
* Jakob Jonsson and Burt Kaliski.</li>
* </ol>
*/
public class EME_PKCS1_V1_5
{
// Constants and variables
// -------------------------------------------------------------------------
private int k;
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
/** Our default source of randomness. */
private PRNG prng = PRNG.getInstance();
// Constructor(s)
// -------------------------------------------------------------------------
private EME_PKCS1_V1_5(final int k)
{
super();
this.k = k;
}
// Class methods
// -------------------------------------------------------------------------
public static final EME_PKCS1_V1_5 getInstance(final int k)
{
if (k < 0)
{
throw new IllegalArgumentException("k must be a positive integer");
}
return new EME_PKCS1_V1_5(k);
}
public static final EME_PKCS1_V1_5 getInstance(final RSAKey key)
{
final int modBits = key.getModulus().bitLength();
final int k = (modBits + 7) / 8;
return EME_PKCS1_V1_5.getInstance(k);
}
// Instance methods
// -------------------------------------------------------------------------
/**
* <p>Generates an octet string <code>PS</code> of length <code>k - mLen -
* 3</code> consisting of pseudo-randomly generated nonzero octets. The
* length of <code>PS</code> will be at least eight octets.</p>
*
* <p>The method then concatenates <code>PS</code>, the message <code>M</code>,
* and other padding to form an encoded message <code>EM</code> of length
* <code>k</code> octets as:</p>
*
* <pre>
* EM = 0x00 || 0x02 || PS || 0x00 || M.
* </pre>
*
* <p>This method uses a default PRNG to obtain the padding bytes.</p>
*
* @param M the message to encode.
* @return the encoded message <code>EM</code>.
*/
public byte[] encode(final byte[] M)
{
// a. Generate an octet string PS of length k - mLen - 3 consisting
// of pseudo-randomly generated nonzero octets. The length of PS
// will be at least eight octets.
final byte[] PS = new byte[k - M.length - 3];
// FIXME. This should be configurable, somehow.
prng.nextBytes(PS);
int i = 0;
for (; i < PS.length; i++)
{
if (PS[i] == 0)
PS[i] = 1;
}
// b. Concatenate PS, the message M, and other padding to form an
// encoded message EM of length k octets as
//
// EM = 0x00 || 0x02 || PS || 0x00 || M.
return assembleEM(PS, M);
}
/**
* <p>Similar to {@link #encode(byte[])} method, except that the source of
* randomness to use for obtaining the padding bytes (an instance of
* {@link IRandom}) is given as a parameter.</p>
*
* @param M the message to encode.
* @param irnd the {@link IRandom} instance to use as a source of randomness.
* @return the encoded message <code>EM</code>.
*/
public byte[] encode(final byte[] M, final IRandom irnd)
{
final byte[] PS = new byte[k - M.length - 3];
try
{
irnd.nextBytes(PS, 0, PS.length);
int i = 0;
outer: while (true)
{
for (; i < PS.length; i++)
{
if (PS[i] == 0x00)
{
System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1);
irnd.nextBytes(PS, PS.length - 1, 1);
continue outer;
}
}
break;
}
}
catch (IllegalStateException x)
{
throw new RuntimeException("encode(): " + String.valueOf(x));
}
catch (LimitReachedException x)
{
throw new RuntimeException("encode(): " + String.valueOf(x));
}
return assembleEM(PS, M);
}
/**
* <p>Similar to the {@link #encode(byte[], IRandom)} method, except that
* the source of randmoness is an instance of {@link Random}.
*
* @param M the message to encode.
* @param rnd the {@link Random} instance to use as a source of randomness.
* @return the encoded message <code>EM</code>.
*/
public byte[] encode(final byte[] M, final Random rnd)
{
final byte[] PS = new byte[k - M.length - 3];
rnd.nextBytes(PS);
int i = 0;
outer: while (true)
{
for (; i < PS.length; i++)
{
if (PS[i] == 0x00)
{
System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1);
PS[PS.length - 1] = (byte) rnd.nextInt();
continue outer;
}
}
break;
}
return assembleEM(PS, M);
}
/**
* <p>Separate the encoded message <code>EM</code> into an octet string
* <code>PS</code> consisting of nonzero octets and a message <code>M</code>
* as:</p>
*
* <pre>
* EM = 0x00 || 0x02 || PS || 0x00 || M.
* </pre>
*
* <p>If the first octet of <code>EM</code> does not have hexadecimal value
* <code>0x00</code>, if the second octet of <code>EM</code> does not have
* hexadecimal value <code>0x02</code>, if there is no octet with hexadecimal
* value <code>0x00</code> to separate <code>PS</code> from <code>M</code>,
* or if the length of <code>PS</code> is less than <code>8</code> octets,
* output "decryption error" and stop.</p>
* @param EM the designated encoded message.
* @return the decoded message <code>M</code> framed in the designated
* <code>EM</code> value.
* @throws IllegalArgumentException if the length of the designated entity
* <code>EM</code> is different than <code>k</code> (the length in bytes of
* the public shared modulus), or if any of the conditions described above
* is detected.
*/
public byte[] decode(final byte[] EM)
{
// Separate the encoded message EM into an
// octet string PS consisting of nonzero octets and a message M as
//
// EM = 0x00 || 0x02 || PS || 0x00 || M.
//
// If the first octet of EM does not have hexadecimal value 0x00, if
// the second octet of EM does not have hexadecimal value 0x02, if
// there is no octet with hexadecimal value 0x00 to separate PS from
// M, or if the length of PS is less than 8 octets, output
// "decryption error" and stop. (See the note below.)
final int emLen = EM.length;
if (emLen != k)
{
throw new IllegalArgumentException("decryption error");
}
if (EM[0] != 0x00)
{
throw new IllegalArgumentException("decryption error");
}
if (EM[1] != 0x02)
{
throw new IllegalArgumentException("decryption error");
}
int i = 2;
for (; i < emLen; i++)
{
if (EM[i] == 0x00)
{
break;
}
}
if (i >= emLen || i < 11)
{
throw new IllegalArgumentException("decryption error");
}
i++;
final byte[] result = new byte[emLen - i];
System.arraycopy(EM, i, result, 0, result.length);
return result;
}
// helper methods ----------------------------------------------------------
private byte[] assembleEM(final byte[] PS, final byte[] M)
{
// b. Concatenate PS, the message M, and other padding to form an
// encoded message EM of length k octets as
//
// EM = 0x00 || 0x02 || PS || 0x00 || M.
baos.reset();
baos.write(0x00);
baos.write(0x02);
baos.write(PS, 0, PS.length);
baos.write(0x00);
baos.write(M, 0, M.length);
final byte[] result = baos.toByteArray();
baos.reset();
return result;
}
}
@@ -0,0 +1,299 @@
/* EMSA_PKCS1_V1_5.java --
Copyright (C) 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.sig.rsa;
import gnu.java.security.Registry;
import gnu.java.security.hash.HashFactory;
import gnu.java.security.hash.IMessageDigest;
import java.io.ByteArrayOutputStream;
/**
* <p>An implementation of the EMSA-PKCS1-V1.5 encoding scheme.</p>
*
* <p>EMSA-PKCS1-V1.5 is parameterised by the choice of hash function Hash and
* hLen which denotes the length in octets of the hash function output.</p>
*
* <p>References:</p>
* <ol>
* <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
* Standards (PKCS) #1:</a><br>
* RSA Cryptography Specifications Version 2.1.<br>
* Jakob Jonsson and Burt Kaliski.</li>
* </ol>
*
* @version $Revision: 1.2 $
*/
public class EMSA_PKCS1_V1_5 implements Cloneable
{
// Constants and variables
// -------------------------------------------------------------------------
/* Notes.
1. For the six hash functions mentioned in Appendix B.1, the DER encoding
T of the DigestInfo value is equal to the following:
MD2: (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 02 05 00 04 10 || H
MD5: (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 05 05 00 04 10 || H
SHA-1: (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H
SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H
SHA-384: (0x)30 41 30 0d 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30 || H
SHA-512: (0x)30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 || H
*/
private static final byte[] MD2_PREFIX = { (byte) 0x30, (byte) 0x20,
(byte) 0x30, (byte) 0x0c,
(byte) 0x06, (byte) 0x08,
(byte) 0x2a, (byte) 0x86,
(byte) 0x48, (byte) 0x86,
(byte) 0xf7, (byte) 0x0d,
(byte) 0x02, (byte) 0x02,
(byte) 0x05, (byte) 0x00,
(byte) 0x04, (byte) 0x10 };
private static final byte[] MD5_PREFIX = { (byte) 0x30, (byte) 0x20,
(byte) 0x30, (byte) 0x0c,
(byte) 0x06, (byte) 0x08,
(byte) 0x2a, (byte) 0x86,
(byte) 0x48, (byte) 0x86,
(byte) 0xf7, (byte) 0x0d,
(byte) 0x02, (byte) 0x05,
(byte) 0x05, (byte) 0x00,
(byte) 0x04, (byte) 0x10 };
private static final byte[] SHA160_PREFIX = { (byte) 0x30, (byte) 0x21,
(byte) 0x30, (byte) 0x09,
(byte) 0x06, (byte) 0x05,
(byte) 0x2b, (byte) 0x0e,
(byte) 0x03, (byte) 0x02,
(byte) 0x1a, (byte) 0x05,
(byte) 0x00, (byte) 0x04,
(byte) 0x14 };
private static final byte[] SHA256_PREFIX = { (byte) 0x30, (byte) 0x31,
(byte) 0x30, (byte) 0x0d,
(byte) 0x06, (byte) 0x09,
(byte) 0x60, (byte) 0x86,
(byte) 0x48, (byte) 0x01,
(byte) 0x65, (byte) 0x03,
(byte) 0x04, (byte) 0x02,
(byte) 0x01, (byte) 0x05,
(byte) 0x00, (byte) 0x04,
(byte) 0x20 };
private static final byte[] SHA384_PREFIX = { (byte) 0x30, (byte) 0x41,
(byte) 0x30, (byte) 0x0d,
(byte) 0x06, (byte) 0x09,
(byte) 0x60, (byte) 0x86,
(byte) 0x48, (byte) 0x01,
(byte) 0x65, (byte) 0x03,
(byte) 0x04, (byte) 0x02,
(byte) 0x02, (byte) 0x05,
(byte) 0x00, (byte) 0x04,
(byte) 0x30 };
private static final byte[] SHA512_PREFIX = { (byte) 0x30, (byte) 0x51,
(byte) 0x30, (byte) 0x0d,
(byte) 0x06, (byte) 0x09,
(byte) 0x60, (byte) 0x86,
(byte) 0x48, (byte) 0x01,
(byte) 0x65, (byte) 0x03,
(byte) 0x04, (byte) 0x02,
(byte) 0x03, (byte) 0x05,
(byte) 0x00, (byte) 0x04,
(byte) 0x40 };
/** The underlying hash function to use with this instance. */
private IMessageDigest hash;
/** The output size of the hash function in octets. */
private int hLen; // TODO: field not used!!! investigate
/** The DER part of DigestInfo not containing the hash value itself. */
private byte[] prefix;
// Constructor(s)
// -------------------------------------------------------------------------
/**
* <p>Trivial private constructor to enforce use through Factory method.</p>
*
* @param hash the message digest instance to use with this scheme instance.
*/
private EMSA_PKCS1_V1_5(final IMessageDigest hash)
{
super();
this.hash = hash;
hLen = hash.hashSize();
final String name = hash.name();
if (name.equals(Registry.MD2_HASH))
{
prefix = MD2_PREFIX;
}
else if (name.equals(Registry.MD5_HASH))
{
prefix = MD5_PREFIX;
}
else if (name.equals(Registry.SHA160_HASH))
{
prefix = SHA160_PREFIX;
}
else if (name.equals(Registry.SHA256_HASH))
{
prefix = SHA256_PREFIX;
}
else if (name.equals(Registry.SHA384_HASH))
{
prefix = SHA384_PREFIX;
}
else if (name.equals(Registry.SHA512_HASH))
{
prefix = SHA512_PREFIX;
}
else
{
throw new UnsupportedOperationException(); // should not happen
}
}
// Class methods
// -------------------------------------------------------------------------
/**
* <p>Returns an instance of this object given a designated name of a hash
* function.</p>
*
* @param mdName the canonical name of a hash function.
* @return an instance of this object configured for use with the designated
* options.
* @throws UnsupportedOperationException if the hash function is not
* implemented or does not have an ID listed in RFC-3447.
*/
public static final EMSA_PKCS1_V1_5 getInstance(final String mdName)
{
final IMessageDigest hash = HashFactory.getInstance(mdName);
final String name = hash.name();
if (!(name.equals(Registry.MD2_HASH) || name.equals(Registry.MD5_HASH)
|| name.equals(Registry.SHA160_HASH)
|| name.equals(Registry.SHA256_HASH)
|| name.equals(Registry.SHA384_HASH) || name.equals(Registry.SHA512_HASH)))
{
throw new UnsupportedOperationException("hash with no OID: " + name);
}
return new EMSA_PKCS1_V1_5(hash);
}
// Instance methods
// -------------------------------------------------------------------------
// Cloneable interface implementation --------------------------------------
public Object clone()
{
return getInstance(hash.name());
}
// own methods -------------------------------------------------------------
/**
* <p>Frames the hash of a message, along with an ID of the hash function in
* a DER sequence according to the specifications of EMSA-PKCS1-V1.5 as
* described in RFC-3447 (see class documentation).</p>
*
* @param mHash the byte sequence resulting from applying the message digest
* algorithm Hash to the message <i>M</i>.
* @param emLen intended length in octets of the encoded message, at least
* <code>tLen + 11</code>, where <code>tLen</code> is the octet length of the
* DER encoding <code>T</code> of a certain value computed during the
* encoding operation.
* @return encoded message, an octet string of length <code>emLen</code>.
* @throws IllegalArgumentException if the message is too long, or if the
* intended encoded message length is too short.
*/
public byte[] encode(final byte[] mHash, final int emLen)
{
// 1. Apply the hash function to the message M to produce a hash value
// H: H = Hash(M).
// If the hash function outputs "message too long," output "message
// too long" and stop.
// 2. Encode the algorithm ID for the hash function and the hash value
// into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with
// the Distinguished Encoding Rules (DER), where the type DigestInfo
// has the syntax
// DigestInfo ::= SEQUENCE {
// digestAlgorithm AlgorithmIdentifier,
// digest OCTET STRING
// }
// The first field identifies the hash function and the second contains
// the hash value. Let T be the DER encoding of the DigestInfo value
// (see the notes below) and let tLen be the length in octets of T.
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(prefix, 0, prefix.length);
baos.write(mHash, 0, mHash.length);
final byte[] T = baos.toByteArray();
final int tLen = T.length;
// 3. If emLen < tLen + 11, output "intended encoded message length too
// short" and stop.
if (emLen < tLen + 11)
{
throw new IllegalArgumentException("emLen too short");
}
// 4. Generate an octet string PS consisting of emLen - tLen - 3 octets
// with hexadecimal value 0xff. The length of PS will be at least 8
// octets.
final byte[] PS = new byte[emLen - tLen - 3];
for (int i = 0; i < PS.length; i++)
{
PS[i] = (byte) 0xFF;
}
// 5. Concatenate PS, the DER encoding T, and other padding to form the
// encoded message EM as: EM = 0x00 || 0x01 || PS || 0x00 || T.
baos.reset();
baos.write(0x00);
baos.write(0x01);
baos.write(PS, 0, PS.length);
baos.write(0x00);
baos.write(T, 0, tLen);
final byte[] result = baos.toByteArray();
baos.reset();
// 6. Output EM.
return result;
}
}
@@ -0,0 +1,432 @@
/* EMSA_PSS.java --
Copyright (C) 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.sig.rsa;
import gnu.java.security.hash.HashFactory;
import gnu.java.security.hash.IMessageDigest;
import gnu.java.security.util.Util;
import java.io.PrintWriter;
import java.util.Arrays;
/**
* <p>An implementation of the EMSA-PSS encoding/decoding scheme.</p>
*
* <p>EMSA-PSS coincides with EMSA4 in IEEE P1363a D5 except that EMSA-PSS acts
* on octet strings and not on bit strings. In particular, the bit lengths of
* the hash and the salt must be multiples of 8 in EMSA-PSS. Moreover, EMSA4
* outputs an integer of a desired bit length rather than an octet string.</p>
*
* <p>EMSA-PSS is parameterized by the choice of hash function Hash and mask
* generation function MGF. In this submission, MGF is based on a Hash
* definition that coincides with the corresponding definitions in IEEE Std
* 1363-2000, PKCS #1 v2.0, and the draft ANSI X9.44. In PKCS #1 v2.0 and the
* draft ANSI X9.44, the recommended hash function is SHA-1, while IEEE Std
* 1363-2000 recommends SHA-1 and RIPEMD-160.</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.1 $
*/
public class EMSA_PSS implements Cloneable
{
// Debugging methods and variables
// -------------------------------------------------------------------------
private static final String NAME = "emsa-pss";
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 underlying hash function to use with this instance. */
private IMessageDigest hash;
/** The output size of the hash function in octets. */
private int hLen;
// Constructor(s)
// -------------------------------------------------------------------------
/**
* <p>Trivial private constructor to enforce use through Factory method.</p>
*
* @param hash the message digest instance to use with this scheme instance.
*/
private EMSA_PSS(IMessageDigest hash)
{
super();
this.hash = hash;
hLen = hash.hashSize();
}
// Class methods
// -------------------------------------------------------------------------
/**
* <p>Returns an instance of this object given a designated name of a hash
* function.</p>
*
* @param mdName the canonical name of a hash function.
* @return an instance of this object configured for use with the designated
* options.
*/
public static EMSA_PSS getInstance(String mdName)
{
IMessageDigest hash = HashFactory.getInstance(mdName);
return new EMSA_PSS(hash);
}
// Instance methods
// -------------------------------------------------------------------------
// Cloneable interface implementation --------------------------------------
public Object clone()
{
return getInstance(hash.name());
}
// own methods -------------------------------------------------------------
/**
* <p>The encoding operation EMSA-PSS-Encode computes the hash of a message
* <code>M</code> using a hash function and maps the result to an encoded
* message <code>EM</code> of a specified length using a mask generation
* function.</p>
*
* @param mHash the byte sequence resulting from applying the message digest
* algorithm Hash to the message <i>M</i>.
* @param emBits the maximal bit length of the integer OS2IP(EM), at least
* <code>8.hLen + 8.sLen + 9</code>.
* @param salt the salt to use when encoding the output.
* @return the encoded message <code>EM</code>, an octet string of length
* <code>emLen = CEILING(emBits / 8)</code>.
* @exception IllegalArgumentException if an exception occurs.
*
*/
public byte[] encode(byte[] mHash, int emBits, byte[] salt)
{
int sLen = salt.length;
// 1. If the length of M is greater than the input limitation for the hash
// function (2**61 - 1 octets for SHA-1) then output "message too long"
// and stop.
// 2. Let mHash = Hash(M), an octet string of length hLen.
if (hLen != mHash.length)
{
throw new IllegalArgumentException("wrong hash");
}
// 3. If emBits < 8.hLen + 8.sLen + 9, output 'encoding error' and stop.
if (emBits < (8 * hLen + 8 * sLen + 9))
{
throw new IllegalArgumentException("encoding error");
}
int emLen = (emBits + 7) / 8;
// 4. Generate a random octet string salt of length sLen; if sLen = 0,
// then salt is the empty string.
// ...passed as argument to accomodate JCE
// 5. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt;
// M0 is an octet string of length 8 + hLen + sLen with eight initial zero
// octets.
// 6. Let H = Hash(M0), an octet string of length hLen.
byte[] H;
int i;
synchronized (hash)
{
for (i = 0; i < 8; i++)
{
hash.update((byte) 0x00);
}
hash.update(mHash, 0, hLen);
hash.update(salt, 0, sLen);
H = hash.digest();
}
// 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
// zero octets. The length of PS may be 0.
// 8. Let DB = PS || 01 || salt.
byte[] DB = new byte[emLen - sLen - hLen - 2 + 1 + sLen];
DB[emLen - sLen - hLen - 2] = 0x01;
System.arraycopy(salt, 0, DB, emLen - sLen - hLen - 1, sLen);
// 9. Let dbMask = MGF(H, emLen - hLen - 1).
byte[] dbMask = MGF(H, emLen - hLen - 1);
if (DEBUG && debuglevel > 8)
{
debug("dbMask (encode): " + Util.toString(dbMask));
debug("DB (encode): " + Util.toString(DB));
}
// 10. Let maskedDB = DB XOR dbMask.
for (i = 0; i < DB.length; i++)
{
DB[i] = (byte) (DB[i] ^ dbMask[i]);
}
// 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in
// maskedDB to zero.
DB[0] &= (0xFF >>> (8 * emLen - emBits));
// 12. Let EM = maskedDB || H || bc, where bc is the single octet with
// hexadecimal value 0xBC.
byte[] result = new byte[emLen];
System.arraycopy(DB, 0, result, 0, emLen - hLen - 1);
System.arraycopy(H, 0, result, emLen - hLen - 1, hLen);
result[emLen - 1] = (byte) 0xBC;
// 13. Output EM.
return result;
}
/**
* <p>The decoding operation EMSA-PSS-Decode recovers the message hash from
* an encoded message <code>EM</code> and compares it to the hash of
* <code>M</code>.</p>
*
* @param mHash the byte sequence resulting from applying the message digest
* algorithm Hash to the message <i>M</i>.
* @param EM the <i>encoded message</i>, an octet string of length
* <code>emLen = CEILING(emBits/8).
* @param emBits the maximal bit length of the integer OS2IP(EM), at least
* <code>8.hLen + 8.sLen + 9</code>.
* @param sLen the length, in octets, of the expected salt.
* @return <code>true</code> if the result of the verification was
* <i>consistent</i> with the expected reseult; and <code>false</code> if the
* result was <i>inconsistent</i>.
* @exception IllegalArgumentException if an exception occurs.
*/
public boolean decode(byte[] mHash, byte[] EM, int emBits, int sLen)
{
if (DEBUG && debuglevel > 8)
{
debug("mHash: " + Util.toString(mHash));
debug("EM: " + Util.toString(EM));
debug("emBits: " + String.valueOf(emBits));
debug("sLen: " + String.valueOf(sLen));
}
if (sLen < 0)
{
throw new IllegalArgumentException("sLen");
}
// 1. If the length of M is greater than the input limitation for the hash
// function (2**61 ? 1 octets for SHA-1) then output 'inconsistent' and
// stop.
// 2. Let mHash = Hash(M), an octet string of length hLen.
if (hLen != mHash.length)
{
if (DEBUG && debuglevel > 8)
{
debug("hLen != mHash.length; hLen: " + String.valueOf(hLen));
}
throw new IllegalArgumentException("wrong hash");
}
// 3. If emBits < 8.hLen + 8.sLen + 9, output 'decoding error' and stop.
if (emBits < (8 * hLen + 8 * sLen + 9))
{
if (DEBUG && debuglevel > 8)
{
debug("emBits < (8hLen + 8sLen + 9); sLen: " + String.valueOf(sLen));
}
throw new IllegalArgumentException("decoding error");
}
int emLen = (emBits + 7) / 8;
// 4. If the rightmost octet of EM does not have hexadecimal value bc,
// output 'inconsistent' and stop.
if ((EM[EM.length - 1] & 0xFF) != 0xBC)
{
if (DEBUG && debuglevel > 8)
{
debug("EM does not end with 0xBC");
}
return false;
}
// 5. Let maskedDB be the leftmost emLen ? hLen ? 1 octets of EM, and let
// H be the next hLen octets.
// 6. If the leftmost 8.emLen ? emBits bits of the leftmost octet in
// maskedDB are not all equal to zero, output 'inconsistent' and stop.
if ((EM[0] & (0xFF << (8 - (8 * emLen - emBits)))) != 0)
{
if (DEBUG && debuglevel > 8)
{
debug("Leftmost 8emLen - emBits bits of EM are not 0s");
}
return false;
}
byte[] DB = new byte[emLen - hLen - 1];
byte[] H = new byte[hLen];
System.arraycopy(EM, 0, DB, 0, emLen - hLen - 1);
System.arraycopy(EM, emLen - hLen - 1, H, 0, hLen);
// 7. Let dbMask = MGF(H, emLen ? hLen ? 1).
byte[] dbMask = MGF(H, emLen - hLen - 1);
// 8. Let DB = maskedDB XOR dbMask.
int i;
for (i = 0; i < DB.length; i++)
{
DB[i] = (byte) (DB[i] ^ dbMask[i]);
}
// 9. Set the leftmost 8.emLen ? emBits bits of DB to zero.
DB[0] &= (0xFF >>> (8 * emLen - emBits));
if (DEBUG && debuglevel > 8)
{
debug("dbMask (decode): " + Util.toString(dbMask));
debug("DB (decode): " + Util.toString(DB));
}
// 10. If the emLen -hLen -sLen -2 leftmost octets of DB are not zero or
// if the octet at position emLen -hLen -sLen -1 is not equal to 0x01,
// output 'inconsistent' and stop.
// IMPORTANT (rsn): this is an error in the specs, the index of the 0x01
// byte should be emLen -hLen -sLen -2 and not -1! authors have been
// advised
for (i = 0; i < (emLen - hLen - sLen - 2); i++)
{
if (DB[i] != 0)
{
if (DEBUG && debuglevel > 8)
{
debug("DB[" + String.valueOf(i) + "] != 0x00");
}
return false;
}
}
if (DB[i] != 0x01)
{ // i == emLen -hLen -sLen -2
if (DEBUG && debuglevel > 8)
{
debug("DB's byte at position (emLen -hLen -sLen -2); i.e. "
+ String.valueOf(i) + " is not 0x01");
}
return false;
}
// 11. Let salt be the last sLen octets of DB.
byte[] salt = new byte[sLen];
System.arraycopy(DB, DB.length - sLen, salt, 0, sLen);
// 12. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt;
// M0 is an octet string of length 8 + hLen + sLen with eight initial
// zero octets.
// 13. Let H0 = Hash(M0), an octet string of length hLen.
byte[] H0;
synchronized (hash)
{
for (i = 0; i < 8; i++)
{
hash.update((byte) 0x00);
}
hash.update(mHash, 0, hLen);
hash.update(salt, 0, sLen);
H0 = hash.digest();
}
// 14. If H = H0, output 'consistent.' Otherwise, output 'inconsistent.'
return Arrays.equals(H, H0);
}
// helper methods ----------------------------------------------------------
/**
* <p>A mask generation function takes an octet string of variable length
* and a desired output length as input, and outputs an octet string of the
* desired length. There may be restrictions on the length of the input and
* output octet strings, but such bounds are generally very large. Mask
* generation functions are deterministic; the octet string output is
* completely determined by the input octet string. The output of a mask
* generation function should be pseudorandom, that is, it should be
* infeasible to predict, given one part of the output but not the input,
* another part of the output. The provable security of RSA-PSS relies on
* the random nature of the output of the mask generation function, which in
* turn relies on the random nature of the underlying hash function.</p>
*
* @param Z a seed.
* @param l the desired output length in octets.
* @return the mask.
* @exception IllegalArgumentException if the desired output length is too
* long.
*/
private byte[] MGF(byte[] Z, int l)
{
// 1. If l > (2**32).hLen, output 'mask too long' and stop.
if (l < 1 || (l & 0xFFFFFFFFL) > ((hLen & 0xFFFFFFFFL) << 32L))
{
throw new IllegalArgumentException("mask too long");
}
// 2. Let T be the empty octet string.
byte[] result = new byte[l];
// 3. For i = 0 to CEILING(l/hLen) ? 1, do
int limit = ((l + hLen - 1) / hLen) - 1;
IMessageDigest hashZ = null;
hashZ = (IMessageDigest) hash.clone();
hashZ.digest();
hashZ.update(Z, 0, Z.length);
IMessageDigest hashZC = null;
byte[] t;
int sofar = 0;
int length;
for (int i = 0; i < limit; i++)
{
// 3.1 Convert i to an octet string C of length 4 with the primitive
// I2OSP: C = I2OSP(i, 4).
// 3.2 Concatenate the hash of the seed Z and C to the octet string T:
// T = T || Hash(Z || C)
hashZC = (IMessageDigest) hashZ.clone();
hashZC.update((byte) (i >>> 24));
hashZC.update((byte) (i >>> 16));
hashZC.update((byte) (i >>> 8));
hashZC.update((byte) i);
t = hashZC.digest();
length = l - sofar;
length = (length > hLen ? hLen : length);
System.arraycopy(t, 0, result, sofar, length);
sofar += length;
}
// 4. Output the leading l octets of T as the octet string mask.
return result;
}
}
@@ -0,0 +1,356 @@
/* RSA.java --
Copyright (C) 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.sig.rsa;
import gnu.java.security.Properties;
import gnu.java.security.util.PRNG;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
/**
* <p>Utility methods related to the RSA algorithm.</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>
*
* <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
* Standards (PKCS) #1:</a><br>
* RSA Cryptography Specifications Version 2.1.<br>
* Jakob Jonsson and Burt Kaliski.</li>
*
* <li><a href="http://crypto.stanford.edu/~dabo/abstracts/ssl-timing.html">
* Remote timing attacks are practical</a><br>
* D. Boneh and D. Brumley.</li>
* </ol>
*/
public class RSA
{
// Constants and variables
// -------------------------------------------------------------------------
private static final BigInteger ZERO = BigInteger.ZERO;
private static final BigInteger ONE = BigInteger.ONE;
/** Our default source of randomness. */
private static final PRNG prng = PRNG.getInstance();
// Constructor(s)
// -------------------------------------------------------------------------
/** Trivial private constructor to enforce Singleton pattern. */
private RSA()
{
super();
}
// Class methods
// -------------------------------------------------------------------------
// Signature and verification methods --------------------------------------
/**
* <p>An implementation of the <b>RSASP</b> method: Assuming that the
* designated RSA private key is a valid one, this method computes a
* <i>signature representative</i> for a designated <i>message
* representative</i> signed by the holder of the designated RSA private
* key.<p>
*
* @param K the RSA private key.
* @param m the <i>message representative</i>: an integer between
* <code>0</code> and <code>n - 1</code>, where <code>n</code> is the RSA
* <i>modulus</i>.
* @return the <i>signature representative</i>, an integer between
* <code>0</code> and <code>n - 1</code>, where <code>n</code> is the RSA
* <i>modulus</i>.
* @throws ClassCastException if <code>K</code> is not an RSA one.
* @throws IllegalArgumentException if <code>m</code> (the <i>message
* representative</i>) is out of range.
*/
public static final BigInteger sign(final PrivateKey K, final BigInteger m)
{
try
{
return RSADP((RSAPrivateKey) K, m);
}
catch (IllegalArgumentException x)
{
throw new IllegalArgumentException(
"message representative out of range");
}
}
/**
* <p>An implementation of the <b>RSAVP</b> method: Assuming that the
* designated RSA public key is a valid one, this method computes a
* <i>message representative</i> for the designated <i>signature
* representative</i> generated by an RSA private key, for a message
* intended for the holder of the designated RSA public key.</p>
*
* @param K the RSA public key.
* @param s the <i>signature representative</i>, an integer between
* <code>0</code> and <code>n - 1</code>, where <code>n</code> is the RSA
* <i>modulus</i>.
* @return a <i>message representative</i>: an integer between <code>0</code>
* and <code>n - 1</code>, where <code>n</code> is the RSA <i>modulus</i>.
* @throws ClassCastException if <code>K</code> is not an RSA one.
* @throws IllegalArgumentException if <code>s</code> (the <i>signature
* representative</i>) is out of range.
*/
public static final BigInteger verify(final PublicKey K, final BigInteger s)
{
try
{
return RSAEP((RSAPublicKey) K, s);
}
catch (IllegalArgumentException x)
{
throw new IllegalArgumentException(
"signature representative out of range");
}
}
// Encryption and decryption methods ---------------------------------------
/**
* <p>An implementation of the <code>RSAEP</code> algorithm.</p>
*
* @param K the recipient's RSA public key.
* @param m the message representative as an MPI.
* @return the resulting MPI --an MPI between <code>0</code> and
* <code>n - 1</code> (<code>n</code> being the public shared modulus)-- that
* will eventually be padded with an appropriate framing/padding scheme.
* @throws ClassCastException if <code>K</code> is not an RSA one.
* @throws IllegalArgumentException if <code>m</code>, the message
* representative is not between <code>0</code> and <code>n - 1</code>
* (<code>n</code> being the public shared modulus).
*/
public static final BigInteger encrypt(final PublicKey K, final BigInteger m)
{
try
{
return RSAEP((RSAPublicKey) K, m);
}
catch (IllegalArgumentException x)
{
throw new IllegalArgumentException(
"message representative out of range");
}
}
/**
* <p>An implementation of the <code>RSADP</code> algorithm.</p>
*
* @param K the recipient's RSA private key.
* @param c the ciphertext representative as an MPI.
* @return the message representative, an MPI between <code>0</code> and
* <code>n - 1</code> (<code>n</code> being the shared public modulus).
* @throws ClassCastException if <code>K</code> is not an RSA one.
* @throws IllegalArgumentException if <code>c</code>, the ciphertext
* representative is not between <code>0</code> and <code>n - 1</code>
* (<code>n</code> being the shared public modulus).
*/
public static final BigInteger decrypt(final PrivateKey K, final BigInteger c)
{
try
{
return RSADP((RSAPrivateKey) K, c);
}
catch (IllegalArgumentException x)
{
throw new IllegalArgumentException(
"ciphertext representative out of range");
}
}
// Conversion methods ------------------------------------------------------
/**
* <p>Converts a <i>multi-precision integer</i> (MPI) <code>s</code> into an
* octet sequence of length <code>k</code>.</p>
*
* @param s the multi-precision integer to convert.
* @param k the length of the output.
* @return the result of the transform.
* @exception IllegalArgumentException if the length in octets of meaningful
* bytes of <code>s</code> is greater than <code>k</code>.
*/
public static final byte[] I2OSP(final BigInteger s, final int k)
{
byte[] result = s.toByteArray();
if (result.length < k)
{
final byte[] newResult = new byte[k];
System.arraycopy(result, 0, newResult, k - result.length, result.length);
result = newResult;
}
else if (result.length > k)
{ // leftmost extra bytes should all be 0
final int limit = result.length - k;
for (int i = 0; i < limit; i++)
{
if (result[i] != 0x00)
{
throw new IllegalArgumentException("integer too large");
}
}
final byte[] newResult = new byte[k];
System.arraycopy(result, limit, newResult, 0, k);
result = newResult;
}
return result;
}
// helper methods ----------------------------------------------------------
private static final BigInteger RSAEP(final RSAPublicKey K, final BigInteger m)
{
// 1. If the representative m is not between 0 and n - 1, output
// "representative out of range" and stop.
final BigInteger n = K.getModulus();
if (m.compareTo(ZERO) < 0 || m.compareTo(n.subtract(ONE)) > 0)
{
throw new IllegalArgumentException();
}
// 2. Let c = m^e mod n.
final BigInteger e = K.getPublicExponent();
final BigInteger result = m.modPow(e, n);
// 3. Output c.
return result;
}
private static final BigInteger RSADP(final RSAPrivateKey K, BigInteger c)
{
// 1. If the representative c is not between 0 and n - 1, output
// "representative out of range" and stop.
final BigInteger n = K.getModulus();
if (c.compareTo(ZERO) < 0 || c.compareTo(n.subtract(ONE)) > 0)
{
throw new IllegalArgumentException();
}
// 2. The representative m is computed as follows.
BigInteger result;
if (!(K instanceof RSAPrivateCrtKey))
{
// a. If the first form (n, d) of K is used, let m = c^d mod n.
final BigInteger d = K.getPrivateExponent();
result = c.modPow(d, n);
}
else
{
// from [3] p.13 --see class docs:
// The RSA blinding operation calculates x = (r^e) * g mod n before
// decryption, where r is random, e is the RSA encryption exponent, and
// g is the ciphertext to be decrypted. x is then decrypted as normal,
// followed by division by r, i.e. (x^e) / r mod n. Since r is random,
// x is random and timing the decryption should not reveal information
// about the key. Note that r should be a new random number for every
// decryption.
final boolean rsaBlinding = Properties.doRSABlinding();
BigInteger r = null;
BigInteger e = null;
if (rsaBlinding)
{ // pre-decryption
r = newR(n);
e = ((RSAPrivateCrtKey) K).getPublicExponent();
final BigInteger x = r.modPow(e, n).multiply(c).mod(n);
c = x;
}
// b. If the second form (p, q, dP, dQ, qInv) and (r_i, d_i, t_i)
// of K is used, proceed as follows:
final BigInteger p = ((RSAPrivateCrtKey) K).getPrimeP();
final BigInteger q = ((RSAPrivateCrtKey) K).getPrimeQ();
final BigInteger dP = ((RSAPrivateCrtKey) K).getPrimeExponentP();
final BigInteger dQ = ((RSAPrivateCrtKey) K).getPrimeExponentQ();
final BigInteger qInv = ((RSAPrivateCrtKey) K).getCrtCoefficient();
// i. Let m_1 = c^dP mod p and m_2 = c^dQ mod q.
final BigInteger m_1 = c.modPow(dP, p);
final BigInteger m_2 = c.modPow(dQ, q);
// ii. If u > 2, let m_i = c^(d_i) mod r_i, i = 3, ..., u.
// iii. Let h = (m_1 - m_2) * qInv mod p.
final BigInteger h = m_1.subtract(m_2).multiply(qInv).mod(p);
// iv. Let m = m_2 + q * h.
result = m_2.add(q.multiply(h));
if (rsaBlinding)
{ // post-decryption
result = result.multiply(r.modInverse(n)).mod(n);
}
}
// 3. Output m
return result;
}
/**
* <p>Returns a random MPI with a random bit-length of the form <code>8b</code>,
* where <code>b</code> is in the range <code>[32..64]</code>.</p>
*
* @return a random MPI whose length in bytes is between 32 and 64 inclusive.
*/
private static final BigInteger newR(final BigInteger N)
{
final int upper = (N.bitLength() + 7) / 8;
final int lower = upper / 2;
final byte[] bl = new byte[1];
int b;
do
{
prng.nextBytes(bl);
b = bl[0] & 0xFF;
}
while (b < lower || b > upper);
final byte[] buffer = new byte[b]; // 256-bit MPI
prng.nextBytes(buffer);
return new BigInteger(1, buffer);
}
}
@@ -0,0 +1,247 @@
/* RSAPKCS1V1_5Signature.java --
Copyright (C) 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.sig.rsa;
import gnu.java.security.Registry;
import gnu.java.security.hash.HashFactory;
import gnu.java.security.hash.IMessageDigest;
import gnu.java.security.sig.BaseSignature;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Arrays;
/**
* <p>The RSA-PKCS1-V1.5 signature scheme is a digital signature scheme with
* appendix (SSA) combining the RSA algorithm with the EMSA-PKCS1-v1_5 encoding
* method.</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>
*
* <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
* Standards (PKCS) #1:</a><br>
* RSA Cryptography Specifications Version 2.1.<br>
* Jakob Jonsson and Burt Kaliski.</li>
* </ol>
*
* @version $Revision: 1.2 $
*/
public class RSAPKCS1V1_5Signature extends BaseSignature
{
// Constants and variables
// -------------------------------------------------------------------------
/** The underlying EMSA-PKCS1-v1.5 instance for this object. */
private EMSA_PKCS1_V1_5 pkcs1;
// Constructor(s)
// -------------------------------------------------------------------------
/**
* Default 0-arguments constructor. Uses SHA-1 as the default hash.
*/
public RSAPKCS1V1_5Signature()
{
this(Registry.SHA160_HASH);
}
/**
* <p>Constructs an instance of this object using the designated message
* digest algorithm as its underlying hash function.</p>
*
* @param mdName the canonical name of the underlying hash function.
*/
public RSAPKCS1V1_5Signature(final String mdName)
{
this(HashFactory.getInstance(mdName));
}
public RSAPKCS1V1_5Signature(IMessageDigest md)
{
super(Registry.RSA_PKCS1_V1_5_SIG, md);
pkcs1 = EMSA_PKCS1_V1_5.getInstance(md.name());
}
/** Private constructor for cloning purposes. */
private RSAPKCS1V1_5Signature(final RSAPKCS1V1_5Signature that)
{
this(that.md.name());
this.publicKey = that.publicKey;
this.privateKey = that.privateKey;
this.md = (IMessageDigest) that.md.clone();
this.pkcs1 = (EMSA_PKCS1_V1_5) that.pkcs1.clone();
}
// Class methods
// -------------------------------------------------------------------------
// Instance methods
// -------------------------------------------------------------------------
// Implementation of abstract methods in superclass ------------------------
public Object clone()
{
return new RSAPKCS1V1_5Signature(this);
}
protected void setupForVerification(final PublicKey k)
throws IllegalArgumentException
{
if (!(k instanceof RSAPublicKey))
{
throw new IllegalArgumentException();
}
publicKey = k;
}
protected void setupForSigning(final PrivateKey k)
throws IllegalArgumentException
{
if (!(k instanceof RSAPrivateKey))
{
throw new IllegalArgumentException();
}
privateKey = k;
}
protected Object generateSignature() throws IllegalStateException
{
// 1. EMSA-PKCS1-v1_5 encoding: Apply the EMSA-PKCS1-v1_5 encoding
// operation (Section 9.2) to the message M to produce an encoded
// message EM of length k octets:
//
// EM = EMSA-PKCS1-V1_5-ENCODE (M, k).
//
// If the encoding operation outputs "message too long," output
// "message too long" and stop. If the encoding operation outputs
// "intended encoded message length too short," output "RSA modulus
// too short" and stop.
final int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength();
final int k = (modBits + 7) / 8;
final byte[] EM = pkcs1.encode(md.digest(), k);
// 2. RSA signature:
// a. Convert the encoded message EM to an integer message epresentative
// m (see Section 4.2): m = OS2IP (EM).
final BigInteger m = new BigInteger(1, EM);
// b. Apply the RSASP1 signature primitive (Section 5.2.1) to the RSA
// private key K and the message representative m to produce an
// integer signature representative s: s = RSASP1 (K, m).
final BigInteger s = RSA.sign(privateKey, m);
// c. Convert the signature representative s to a signature S of length
// k octets (see Section 4.1): S = I2OSP (s, k).
// 3. Output the signature S.
return RSA.I2OSP(s, k);
}
protected boolean verifySignature(final Object sig)
throws IllegalStateException
{
if (publicKey == null)
{
throw new IllegalStateException();
}
final byte[] S = (byte[]) sig;
// 1. Length checking: If the length of the signature S is not k octets,
// output "invalid signature" and stop.
final int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength();
final int k = (modBits + 7) / 8;
if (S.length != k)
{
return false;
}
// 2. RSA verification:
// a. Convert the signature S to an integer signature representative
// s (see Section 4.2): s = OS2IP (S).
final BigInteger s = new BigInteger(1, S);
// b. Apply the RSAVP1 verification primitive (Section 5.2.2) to the
// RSA public key (n, e) and the signature representative s to
// produce an integer message representative m:
// m = RSAVP1 ((n, e), s).
// If RSAVP1 outputs "signature representative out of range,"
// output "invalid signature" and stop.
final BigInteger m;
try
{
m = RSA.verify(publicKey, s);
}
catch (IllegalArgumentException x)
{
return false;
}
// c. Convert the message representative m to an encoded message EM
// of length k octets (see Section 4.1): EM = I2OSP (m, k).
// If I2OSP outputs "integer too large," output "invalid signature"
// and stop.
final byte[] EM;
try
{
EM = RSA.I2OSP(m, k);
}
catch (IllegalArgumentException x)
{
return false;
}
// 3. EMSA-PKCS1-v1_5 encoding: Apply the EMSA-PKCS1-v1_5 encoding
// operation (Section 9.2) to the message M to produce a second
// encoded message EM' of length k octets:
// EM' = EMSA-PKCS1-V1_5-ENCODE (M, k).
// If the encoding operation outputs "message too long," output
// "message too long" and stop. If the encoding operation outputs
// "intended encoded message length too short," output "RSA modulus
// too short" and stop.
final byte[] EMp = pkcs1.encode(md.digest(), k);
// 4. Compare the encoded message EM and the second encoded message EM'.
// If they are the same, output "valid signature"; otherwise, output
// "invalid signature."
return Arrays.equals(EM, EMp);
}
}
@@ -0,0 +1,153 @@
/* RSAPKCS1V1_5SignatureRawCodec.java -- Raw RSA PKCS1 v1.5 signature codeec
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.sig.rsa;
import java.io.ByteArrayOutputStream;
import gnu.java.security.Registry;
import gnu.java.security.sig.ISignatureCodec;
/**
* An object that implements the {@link ISignatureCodec} operations for the
* <i>Raw</i> format to use with RSA-PKCS#1 v1.5 signatures.
*/
public class RSAPKCS1V1_5SignatureRawCodec
implements ISignatureCodec
{
public int getFormatID()
{
return RAW_FORMAT;
}
/**
* Returns the encoded form of the designated RSA-PKCS#1 (v1.5) signature
* object according to the <i>Raw</i> format supported by this library.
* <p>
* The <i>Raw</i> format for such a signature, 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_PKCS1V1_5_SIGNATURE},
* <li>
* <li>1-byte version consisting of the constant: 0x01,</li>
* <li>4-byte count of following bytes representing the RSA-PKCS#1 (v1.5)
* signature bytes in internet order,</li>
* <li>the RSA-PKCS#1 (v1.5) signature bytes in internet order.</li>
* </ol>
*
* @param signature the signature to encode, consisting of the output of the
* <code>sign()</code> method of a {@link RSAPKCS1V1_5Signature}
* instance --a byte array.
* @return the <i>Raw</i> format encoding of the designated signature.
* @exception IllegalArgumentException if the designated signature is not an
* RSA-PKCS#1 (v1.5) one.
*/
public byte[] encodeSignature(Object signature)
{
byte[] buffer;
try
{
buffer = (byte[]) signature;
}
catch (Exception x)
{
throw new IllegalArgumentException("Signature/codec mismatch");
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// magic
baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[0]);
baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[1]);
baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[2]);
baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[3]);
// version
baos.write(0x01);
// signature bytes
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);
return baos.toByteArray();
}
/**
* Returns the decoded object from a designated input assumed to have been
* generated by the {@link #encodeSignature(Object)} method.
*
* @param input the input bytes of a previously Raw-encoded RSA PKCS1 (v1.5)
* signature.
* @return the signature object.
* @throws IllegalArgumentException if the designated input does not start
* with the right <i>magic</i> characters, or if the <i>version</i>
* is not supported.
*/
public Object decodeSignature(byte[] input)
{
// magic
if (input[0] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[0]
|| input[1] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[1]
|| input[2] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[2]
|| input[3] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[3])
throw new IllegalArgumentException("Signature/codec mismatch");
// version
if (input[4] != 0x01)
throw new IllegalArgumentException("Wrong or unsupported format version");
int i = 5;
int l;
// signature bytes
l = input[i++] << 24
| (input[i++] & 0xFF) << 16
| (input[i++] & 0xFF) << 8
| (input[i++] & 0xFF);
byte[] result = new byte[l];
System.arraycopy(input, i, result, 0, l);
return result;
}
}
@@ -0,0 +1,128 @@
/* RSAPSSSignatureX509Codec.java -- X.509 encoder/decoder for RSA signatures
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.sig.rsa;
import gnu.java.security.Registry;
import gnu.java.security.sig.ISignatureCodec;
import java.security.InvalidParameterException;
/**
* An implementation of an {@link ISignatureCodec} that knows to encode and
* decode RSA PKCS1 (v1.5) signatures into the raw bytes which would constitute
* a DER-encoded form of the ASN.1 structure defined in RFC-2459, and RFC-2313
* as described in the next paragraphs.
* <p>
* Digital signatures when transmitted in an X.509 certificates are encoded
* in DER (Distinguished Encoding Rules) as a BIT STRING; i.e.
*
* <pre>
* Certificate ::= SEQUENCE {
* tbsCertificate TBSCertificate,
* signatureAlgorithm AlgorithmIdentifier,
* signature BIT STRING
* }
* </pre>
* <p>
* The output of the encoder, and the input of the decoder, of this codec are
* then the <i>raw</i> bytes of such a BIT STRING; i.e. not the DER-encoded
* form itself.
* <p>
* Our implementation of the RSA PKCS1 signature algorithm outputs a byte array
* as the result of generating a digital signature, in accordance with RFC-2313.
* As a consequence, the encoder and decoder of this codec, simply pass through
* such a byte array.
* <p>
* Client code that needs to build a DER BIT STRING <b>MUST</b> construct such
* an ASN.1 value. The following is an example of how to do this:
* <p>
* <pre>
* ...
* import gnu.java.security.der.BitString;
* import gnu.java.security.der.DER;
* import gnu.java.security.der.DERValue;
* ...
* DERValue bitString = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
* ...
* </pre>
*/
public class RSAPKCS1V1_5SignatureX509Codec
implements ISignatureCodec
{
// default 0-arguments constructor
public int getFormatID()
{
return Registry.X509_ENCODING_ID;
}
/**
* Encodes an RSA Signature output as a <i>signature</i> BIT STRING as
* defined in the documentation of this class.
*
* @param signature the output of the RSA PKCS1 (v1.5) signature algorithm;
* i.e. the value returned by the invocation of
* {@link gnu.java.security.sig.ISignature#sign()} method. In the
* case of the RSA PKCS1 (v1.5) signature this is an array of bytes.
* @return the raw bytes of an RSA signature which could be then used as the
* contents of a BIT STRING as per rfc-2459.
*/
public byte[] encodeSignature(Object signature)
{
byte[] result = (byte[]) signature;
return result;
}
/**
* Decodes a <i>signature</i> as defined in the documentation of this class.
*
* @param input the byte array to unmarshall into a valid RSA PKCS1 (v1.5)
* signature instance; i.e. a byte array. MUST NOT be null.
* @return an array of raw bytes decoded from the designated input. In the
* case of RSA PKCS1 (v1.5) this is the same as the input.
* @throw InvalidParameterException if the <code>input</code> array is null.
*/
public Object decodeSignature(byte[] input)
{
if (input == null)
throw new InvalidParameterException("Input bytes MUST NOT be null");
return input;
}
}
@@ -0,0 +1,348 @@
/* RSAPSSSignature.java --
Copyright (C) 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.sig.rsa;
import gnu.java.security.Registry;
import gnu.java.security.hash.HashFactory;
import gnu.java.security.hash.IMessageDigest;
import gnu.java.security.sig.BaseSignature;
import gnu.java.security.util.Util;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
/**
* <p>The RSA-PSS signature scheme is a public-key encryption scheme combining
* the RSA algorithm with the Probabilistic Signature Scheme (PSS) encoding
* method.</p>
*
* <p>The inventors of RSA are Ronald L. Rivest, Adi Shamir, and Leonard Adleman,
* while the inventors of the PSS encoding method are Mihir Bellare and Phillip
* Rogaway. During efforts to adopt RSA-PSS into the P1363a standards effort,
* certain adaptations to the original version of RSA-PSS were made by Mihir
* Bellare and Phillip Rogaway and also by Burt Kaliski (the editor of IEEE
* P1363a) to facilitate implementation and integration into existing protocols.</p>
*
* <p>References:</pr>
* <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 RSAPSSSignature extends BaseSignature
{
// Debugging methods and variables
// -------------------------------------------------------------------------
private static final String NAME = "rsa-pss";
private static final boolean DEBUG = false;
private static final int debuglevel = 1;
private static final PrintWriter err = new PrintWriter(System.out, true);
private static void debug(String s)
{
err.println(">>> " + NAME + ": " + s);
}
// Constants and variables
// -------------------------------------------------------------------------
/** The underlying EMSA-PSS instance for this object. */
private EMSA_PSS pss;
/** The desired length in octets of the EMSA-PSS salt. */
private int sLen;
// Constructor(s)
// -------------------------------------------------------------------------
/**
* Default 0-arguments constructor. Uses SHA-1 as the default hash and a
* 0-octet <i>salt</i>.
*/
public RSAPSSSignature()
{
this(Registry.SHA160_HASH, 0);
}
/**
* <p>Constructs an instance of this object using the designated message
* digest algorithm as its underlying hash function, and having 0-octet
* <i>salt</i>.</p>
*
* @param mdName the canonical name of the underlying hash function.
*/
public RSAPSSSignature(String mdName)
{
this(mdName, 0);
}
/**
* <p>Constructs an instance of this object using the designated message
* digest algorithm as its underlying hash function.</p>
*
* @param mdName the canonical name of the underlying hash function.
* @param sLen the desired length in octets of the salt to use for encoding /
* decoding signatures.
*/
public RSAPSSSignature(String mdName, int sLen)
{
this(HashFactory.getInstance(mdName), sLen);
}
public RSAPSSSignature(IMessageDigest md, int sLen)
{
super(Registry.RSA_PSS_SIG, md);
pss = EMSA_PSS.getInstance(md.name());
this.sLen = sLen;
}
/** Private constructor for cloning purposes. */
private RSAPSSSignature(RSAPSSSignature that)
{
this(that.md.name(), that.sLen);
this.publicKey = that.publicKey;
this.privateKey = that.privateKey;
this.md = (IMessageDigest) that.md.clone();
this.pss = (EMSA_PSS) that.pss.clone();
}
// Class methods
// -------------------------------------------------------------------------
// Instance methods
// -------------------------------------------------------------------------
// Implementation of abstract methods in superclass ------------------------
public Object clone()
{
return new RSAPSSSignature(this);
}
protected void setupForVerification(PublicKey k)
throws IllegalArgumentException
{
if (!(k instanceof RSAPublicKey))
{
throw new IllegalArgumentException();
}
publicKey = (RSAPublicKey) k;
}
protected void setupForSigning(PrivateKey k) throws IllegalArgumentException
{
if (!(k instanceof RSAPrivateKey))
{
throw new IllegalArgumentException();
}
privateKey = (RSAPrivateKey) k;
}
protected Object generateSignature() throws IllegalStateException
{
// 1. Apply the EMSA-PSS encoding operation to the message M to produce an
// encoded message EM of length CEILING((modBits ? 1)/8) octets such
// that the bit length of the integer OS2IP(EM) is at most modBits ? 1:
// EM = EMSA-PSS-Encode(M,modBits ? 1).
// Note that the octet length of EM will be one less than k if
// modBits ? 1 is divisible by 8. If the encoding operation outputs
// 'message too long' or 'encoding error,' then output 'message too
// long' or 'encoding error' and stop.
int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength();
byte[] salt = new byte[sLen];
this.nextRandomBytes(salt);
byte[] EM = pss.encode(md.digest(), modBits - 1, salt);
if (DEBUG && debuglevel > 8)
{
debug("EM (sign): " + Util.toString(EM));
}
// 2. Convert the encoded message EM to an integer message representative
// m (see Section 1.2.2): m = OS2IP(EM).
BigInteger m = new BigInteger(1, EM);
// 3. Apply the RSASP signature primitive to the public key K and the
// message representative m to produce an integer signature
// representative s: s = RSASP(K,m).
BigInteger s = RSA.sign(privateKey, m);
// 4. Convert the signature representative s to a signature S of length k
// octets (see Section 1.2.1): S = I2OSP(s, k).
// 5. Output the signature S.
int k = (modBits + 7) / 8;
// return encodeSignature(s, k);
return RSA.I2OSP(s, k);
}
protected boolean verifySignature(Object sig) throws IllegalStateException
{
if (publicKey == null)
{
throw new IllegalStateException();
}
// byte[] S = decodeSignature(sig);
byte[] S = (byte[]) sig;
// 1. If the length of the signature S is not k octets, output 'signature
// invalid' and stop.
int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength();
int k = (modBits + 7) / 8;
if (S.length != k)
{
return false;
}
// 2. Convert the signature S to an integer signature representative s:
// s = OS2IP(S).
BigInteger s = new BigInteger(1, S);
// 3. Apply the RSAVP verification primitive to the public key (n, e) and
// the signature representative s to produce an integer message
// representative m: m = RSAVP((n, e), s).
// If RSAVP outputs 'signature representative out of range,' then
// output 'signature invalid' and stop.
BigInteger m = null;
try
{
m = RSA.verify(publicKey, s);
}
catch (IllegalArgumentException x)
{
return false;
}
// 4. Convert the message representative m to an encoded message EM of
// length emLen = CEILING((modBits - 1)/8) octets, where modBits is
// equal to the bit length of the modulus: EM = I2OSP(m, emLen).
// Note that emLen will be one less than k if modBits - 1 is divisible
// by 8. If I2OSP outputs 'integer too large,' then output 'signature
// invalid' and stop.
int emBits = modBits - 1;
int emLen = (emBits + 7) / 8;
byte[] EM = m.toByteArray();
if (DEBUG && debuglevel > 8)
{
debug("EM (verify): " + Util.toString(EM));
}
if (EM.length > emLen)
{
return false;
}
else if (EM.length < emLen)
{
byte[] newEM = new byte[emLen];
System.arraycopy(EM, 0, newEM, emLen - EM.length, EM.length);
EM = newEM;
}
// 5. Apply the EMSA-PSS decoding operation to the message M and the
// encoded message EM: Result = EMSA-PSS-Decode(M, EM, emBits). If
// Result = 'consistent,' output 'signature verified.' Otherwise,
// output 'signature invalid.'
byte[] mHash = md.digest();
boolean result = false;
try
{
result = pss.decode(mHash, EM, emBits, sLen);
}
catch (IllegalArgumentException x)
{
result = false;
}
return result;
}
// Other instance methods --------------------------------------------------
/**
* Converts the <i>signature representative</i> <code>s</code> to a signature
* <code>S</code> of length <code>k</code> octets; i.e.
* <code>S = I2OSP(s, k)</code>, where <code>k = CEILING(modBits/8)</code>.
*
* @param s the <i>signature representative</i>.
* @param k the length of the output.
* @return the signature as an octet sequence.
* @exception IllegalArgumentException if the length in octets of meaningful
* bytes of <code>s</code> is greater than <code>k</code>, implying that
* <code>s</code> is not less than the RSA <i>modulus</i>.
*/
// private Object encodeSignature(BigInteger s, int k) {
// if (DEBUG && debuglevel > 8) {
// debug("s.bitLength(): "+String.valueOf(s.bitLength()));
// debug("k: "+String.valueOf(k));
// }
// byte[] result = s.toByteArray();
// if (DEBUG && debuglevel > 8) {
// debug("s: "+Util.toString(result));
// debug("s (bytes): "+String.valueOf(result.length));
// }
// if (result.length < k) {
// byte[] newResult = new byte[k];
// System.arraycopy(result, 0, newResult, k-result.length, result.length);
// result = newResult;
// } else if (result.length > k) { // leftmost extra bytes should all be 0
// int limit = result.length - k;
// for (int i = 0; i < limit; i++) {
// if (result[i] != 0x00) {
// throw new IllegalArgumentException("integer too large");
// }
// }
// byte[] newResult = new byte[k];
// System.arraycopy(result, limit, newResult, 0, k);
// result = newResult;
// }
// return result;
// }
/**
* Returns the output of a previously generated signature object as an octet
* sequence.<p>
*
* @return the octet sequence <code>S</code>.
*/
// private byte[] decodeSignature(Object signature) {
// return (byte[]) signature;
// }
}
@@ -0,0 +1,159 @@
/* RSAPSSSignatureRawCodec.java --
Copyright (C) 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.sig.rsa;
import gnu.java.security.Registry;
import gnu.java.security.sig.ISignatureCodec;
import java.io.ByteArrayOutputStream;
/**
* <p>An object that implements the {@link gnu.crypto.sig.ISignatureCodec}
* operations for the <i>Raw</i> format to use with RSA-PSS signatures.</p>
*
* @version $Revision: 1.1 $
*/
public class RSAPSSSignatureRawCodec implements ISignatureCodec
{
// Constants and variables
// -------------------------------------------------------------------------
// Constructor(s)
// -------------------------------------------------------------------------
// implicit 0-arguments constructor
// Class methods
// -------------------------------------------------------------------------
// gnu.crypto.keys.IKeyPairCodec interface implementation
// -------------------------------------------------------------------------
public int getFormatID()
{
return RAW_FORMAT;
}
/**
* <p>Returns the encoded form of the designated RSA-PSS signature object
* according to the <i>Raw</i> format supported by this library.</p>
*
* <p>The <i>Raw</i> format for an RSA-PSS signature, 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_PSS_SIGNATURE},<li>
* <li>1-byte version consisting of the constant: 0x01,</li>
* <li>4-byte count of following bytes representing the RSA-PSS signature
* bytes in internet order,</li>
* <li>the RSA-PSS signature bytes in internet order.</li>
* </ol>
*
* @param signature the signature to encode, consisting of the output of the
* <code>sign()</code> method of a {@link RSAPSSSignature} instance --a byte
* array.
* @return the <i>Raw</i> format encoding of the designated signature.
* @exception IllegalArgumentException if the designated signature is not an
* RSA-PSS one.
*/
public byte[] encodeSignature(Object signature)
{
byte[] buffer;
try
{
buffer = (byte[]) signature;
}
catch (Exception x)
{
throw new IllegalArgumentException("key");
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// magic
baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[0]);
baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[1]);
baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[2]);
baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[3]);
// version
baos.write(0x01);
// signature bytes
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);
return baos.toByteArray();
}
public Object decodeSignature(byte[] k)
{
// magic
if (k[0] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[0]
|| k[1] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[1]
|| k[2] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[2]
|| k[3] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[3])
{
throw new IllegalArgumentException("magic");
}
// version
if (k[4] != 0x01)
{
throw new IllegalArgumentException("version");
}
int i = 5;
int l;
// signature bytes
l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8
| (k[i++] & 0xFF);
byte[] result = new byte[l];
System.arraycopy(k, i, result, 0, l);
return result;
}
}
@@ -0,0 +1,176 @@
/* RSASignatureFactory.java -- A Factory class to instantiate RSA Signatures
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.sig.rsa;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import gnu.java.security.Registry;
import gnu.java.security.hash.HashFactory;
import gnu.java.security.hash.IMessageDigest;
import gnu.java.security.sig.ISignature;
/**
* A Factory class to instantiate RSA Signature classes.
*/
public class RSASignatureFactory
{
private static Set names;
/**
* Private constructor to enforce usage through Factory (class) methods.
*/
private RSASignatureFactory()
{
super();
}
/**
* Returns a new instance of an RSA Signature given its name. The name of an
* RSA Signature always starts with <code>rsa-</code>, followed by either
* <code>pss</code> or <code>pkcs1_v1.5</code>. An optional message digest
* name, to be used with the RSA signature may be specified by appending the
* hyphen chanaracter <code>-</code> followed by the canonical message digest
* algorithm name. When no message digest algorithm name is given, SHA-160 is
* used.
*
* @param name the composite RSA signature name.
* @return a new instance of an RSA Signature algorithm implementation.
* Returns <code>null</code> if the given name does not correspond to any
* supported RSA Signature encoding and message digest combination.
*/
public static final ISignature getInstance(String name)
{
if (name == null)
return null;
name = name.trim();
if (name.length() == 0)
return null;
name = name.toLowerCase();
if (! name.startsWith(Registry.RSA_SIG_PREFIX))
return null;
name = name.substring(Registry.RSA_SIG_PREFIX.length()).trim();
if (name.startsWith(Registry.RSA_PSS_ENCODING))
return getPSSSignature(name);
else if (name.startsWith(Registry.RSA_PKCS1_V1_5_ENCODING))
return getPKCS1Signature(name);
else
return null;
}
/**
* Returns a {@link Set} of names of <i>RSA</i> signatures supported by this
* <i>Factory</i>.
*
* @return a {@link Set} of RSA Signature algorithm names (Strings).
*/
public static synchronized final Set getNames()
{
if (names == null)
{
Set hashNames = HashFactory.getNames();
HashSet hs = new HashSet();
for (Iterator it = hashNames.iterator(); it.hasNext();)
{
String mdName = (String) it.next();
hs.add(Registry.RSA_PSS_SIG + "-" + mdName);
}
hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD2_HASH);
hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD5_HASH);
hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA160_HASH);
hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA256_HASH);
hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA384_HASH);
hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA512_HASH);
names = Collections.unmodifiableSet(hs);
}
return names;
}
private static final ISignature getPSSSignature(String name)
{
name = name.substring(Registry.RSA_PSS_ENCODING.length()).trim();
// remove the hyphen if found at the beginning
if (name.startsWith("-"))
name = name.substring(1).trim();
IMessageDigest md;
if (name.length() == 0)
md = HashFactory.getInstance(Registry.SHA160_HASH);
else
{
// check if there is such a hash
md = HashFactory.getInstance(name);
if (md == null)
return null;
}
ISignature result = new RSAPSSSignature(md, 0);
return result;
}
private static final ISignature getPKCS1Signature(String name)
{
name = name.substring(Registry.RSA_PKCS1_V1_5_ENCODING.length()).trim();
// remove the hyphen if found at the beginning
if (name.startsWith("-"))
name = name.substring(1).trim();
IMessageDigest md;
if (name.length() == 0)
md = HashFactory.getInstance(Registry.SHA160_HASH);
else
{
// check if there is such a hash
md = HashFactory.getInstance(name);
if (md == null)
return null;
}
ISignature result = new RSAPKCS1V1_5Signature(md);
return result;
}
}