summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu/java/security/sig/rsa
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/gnu/java/security/sig/rsa')
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java274
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java243
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java371
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSA.java324
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java224
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java153
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java128
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java255
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java134
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java176
10 files changed, 2282 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java b/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java
new file mode 100644
index 000000000..329ca8ed6
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java
@@ -0,0 +1,274 @@
+/* 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;
+
+/**
+ * An implementation of the EME-PKCS1-V1.5 encoding and decoding methods.
+ * <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>
+ * References:
+ * <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
+{
+ private int k;
+
+ private ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ /** Our default source of randomness. */
+ private PRNG prng = PRNG.getInstance();
+
+ private EME_PKCS1_V1_5(final int k)
+ {
+ super();
+
+ this.k = k;
+ }
+
+ 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);
+ }
+
+ /**
+ * 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>
+ * 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:
+ * <pre>
+ * EM = 0x00 || 0x02 || PS || 0x00 || M.
+ * </pre>
+ * <p>
+ * This method uses a default PRNG to obtain the padding bytes.
+ *
+ * @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);
+ }
+
+ /**
+ * 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.
+ *
+ * @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);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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:
+ * <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.
+ *
+ * @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;
+ }
+
+ 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;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java
new file mode 100644
index 000000000..3cddab4aa
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java
@@ -0,0 +1,243 @@
+/* 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;
+
+/**
+ * An implementation of the EMSA-PKCS1-V1.5 encoding scheme.
+ * <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>
+ * References:
+ * <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 EMSA_PKCS1_V1_5
+ implements Cloneable
+{
+ /* 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;
+
+ /**
+ * Trivial private constructor to enforce use through Factory method.
+ *
+ * @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
+ }
+
+ /**
+ * Returns an instance of this object given a designated name of a hash
+ * function.
+ *
+ * @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);
+ }
+
+ public Object clone()
+ {
+ return getInstance(hash.name());
+ }
+
+ /**
+ * 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).
+ *
+ * @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;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java
new file mode 100644
index 000000000..917d96323
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java
@@ -0,0 +1,371 @@
+/* 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.Configuration;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.util.Util;
+
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+/**
+ * An implementation of the EMSA-PSS encoding/decoding scheme.
+ * <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>
+ * 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>
+ * References:
+ * <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>
+ */
+public class EMSA_PSS
+ implements Cloneable
+{
+ private static final Logger log = Logger.getLogger(EMSA_PSS.class.getName());
+
+ /** The underlying hash function to use with this instance. */
+ private IMessageDigest hash;
+
+ /** The output size of the hash function in octets. */
+ private int hLen;
+
+ /**
+ * Trivial private constructor to enforce use through Factory method.
+ *
+ * @param hash the message digest instance to use with this scheme instance.
+ */
+ private EMSA_PSS(IMessageDigest hash)
+ {
+ super();
+
+ this.hash = hash;
+ hLen = hash.hashSize();
+ }
+
+ /**
+ * Returns an instance of this object given a designated name of a hash
+ * function.
+ *
+ * @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);
+ }
+
+ public Object clone()
+ {
+ return getInstance(hash.name());
+ }
+
+ /**
+ * 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.
+ *
+ * @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 (Configuration.DEBUG)
+ {
+ log.fine("dbMask (encode): " + Util.toString(dbMask));
+ log.fine("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;
+ }
+
+ /**
+ * 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>.
+ *
+ * @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 (Configuration.DEBUG)
+ {
+ log.fine("mHash: " + Util.toString(mHash));
+ log.fine("EM: " + Util.toString(EM));
+ log.fine("emBits: " + String.valueOf(emBits));
+ log.fine("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 (Configuration.DEBUG)
+ log.fine("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 (Configuration.DEBUG)
+ log.fine("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 (Configuration.DEBUG)
+ log.fine("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 (Configuration.DEBUG)
+ log.fine("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 (Configuration.DEBUG)
+ {
+ log.fine("dbMask (decode): " + Util.toString(dbMask));
+ log.fine("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 (Configuration.DEBUG)
+ log.fine("DB[" + String.valueOf(i) + "] != 0x00");
+ return false;
+ }
+ }
+ if (DB[i] != 0x01)
+ { // i == emLen -hLen -sLen -2
+ if (Configuration.DEBUG)
+ log.fine("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);
+ }
+
+ /**
+ * 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.
+ *
+ * @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;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSA.java b/libjava/classpath/gnu/java/security/sig/rsa/RSA.java
new file mode 100644
index 000000000..343b2cf65
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/sig/rsa/RSA.java
@@ -0,0 +1,324 @@
+/* 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;
+
+/**
+ * Utility methods related to the RSA algorithm.
+ * <p>
+ * References:
+ * <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
+{
+ 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();
+
+ /** Trivial private constructor to enforce Singleton pattern. */
+ private RSA()
+ {
+ super();
+ }
+
+ /**
+ * 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.
+ *
+ * @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");
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * @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");
+ }
+ }
+
+ /**
+ * An implementation of the <code>RSAEP</code> algorithm.
+ *
+ * @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");
+ }
+ }
+
+ /**
+ * An implementation of the <code>RSADP</code> algorithm.
+ *
+ * @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");
+ }
+ }
+
+ /**
+ * Converts a <i>multi-precision integer</i> (MPI) <code>s</code> into an
+ * octet sequence of length <code>k</code>.
+ *
+ * @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;
+ }
+
+ 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;
+ }
+
+ /**
+ * 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>.
+ *
+ * @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);
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java
new file mode 100644
index 000000000..1420331de
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java
@@ -0,0 +1,224 @@
+/* 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;
+
+/**
+ * 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>
+ * References:
+ * <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>
+ */
+public class RSAPKCS1V1_5Signature
+ extends BaseSignature
+{
+ /** The underlying EMSA-PKCS1-v1.5 instance for this object. */
+ private EMSA_PKCS1_V1_5 pkcs1;
+
+ /**
+ * Default 0-arguments constructor. Uses SHA-1 as the default hash.
+ */
+ public RSAPKCS1V1_5Signature()
+ {
+ this(Registry.SHA160_HASH);
+ }
+
+ /**
+ * Constructs an instance of this object using the designated message digest
+ * algorithm as its underlying hash function.
+ *
+ * @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();
+ }
+
+ 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);
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java
new file mode 100644
index 000000000..548dc3deb
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java
@@ -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;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java
new file mode 100644
index 000000000..ee8586f7d
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java
@@ -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;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java
new file mode 100644
index 000000000..d8f8327f1
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java
@@ -0,0 +1,255 @@
+/* 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.Configuration;
+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.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.logging.Logger;
+
+/**
+ * The RSA-PSS signature scheme is a public-key encryption scheme combining the
+ * RSA algorithm with the Probabilistic Signature Scheme (PSS) encoding method.
+ * <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>
+ * References:
+ * <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>
+ */
+public class RSAPSSSignature
+ extends BaseSignature
+{
+ private static final Logger log = Logger.getLogger(RSAPSSSignature.class.getName());
+
+ /** 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;
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Constructs an instance of this object using the designated message digest
+ * algorithm as its underlying hash function, and having 0-octet <i>salt</i>.
+ *
+ * @param mdName the canonical name of the underlying hash function.
+ */
+ public RSAPSSSignature(String mdName)
+ {
+ this(mdName, 0);
+ }
+
+ /**
+ * Constructs an instance of this object using the designated message digest
+ * algorithm as its underlying hash function.
+ *
+ * @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();
+ }
+
+ 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 (Configuration.DEBUG)
+ log.fine("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 (Configuration.DEBUG)
+ log.fine("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;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java
new file mode 100644
index 000000000..b147ea3ea
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java
@@ -0,0 +1,134 @@
+/* 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;
+
+/**
+ * An object that implements the {@link ISignatureCodec} operations for the
+ * <i>Raw</i> format to use with RSA-PSS signatures.
+ */
+public class RSAPSSSignatureRawCodec
+ implements ISignatureCodec
+{
+ // implicit 0-arguments constructor
+
+ public int getFormatID()
+ {
+ return RAW_FORMAT;
+ }
+
+ /**
+ * Returns the encoded form of the designated RSA-PSS signature object
+ * according to the <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for an RSA-PSS signature, in this implementation, is
+ * a byte sequence consisting of the following:
+ * <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("signature");
+ }
+ 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;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java b/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java
new file mode 100644
index 000000000..ba5121b46
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java
@@ -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;
+ }
+}