OSDN Git Service

2006-08-14 Mark Wielaard <mark@klomp.org>
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / java / security / sig / rsa / EMSA_PSS.java
index c1c9760..97b3afc 100644 (file)
@@ -38,57 +38,42 @@ 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.io.PrintWriter;
 import java.util.Arrays;
+import java.util.logging.Logger;
 
 /**
- * <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
+ * 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>
- *
- * <p>References:</p>
+ * 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>
+ * <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
+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
-  // -------------------------------------------------------------------------
+  private static final Logger log = Logger.getLogger(EMSA_PSS.class.getName());
 
   /** The underlying hash function to use with this instance. */
   private IMessageDigest hash;
@@ -96,12 +81,9 @@ public class EMSA_PSS implements Cloneable
   /** 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>
-   *
+   * 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)
@@ -112,16 +94,13 @@ public class EMSA_PSS implements Cloneable
     hLen = hash.hashSize();
   }
 
-  // Class methods
-  // -------------------------------------------------------------------------
-
   /**
-   * <p>Returns an instance of this object given a designated name of a hash
-   * function.</p>
-   *
+   * 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.
+   *         options.
    */
   public static EMSA_PSS getInstance(String mdName)
   {
@@ -129,51 +108,38 @@ public class EMSA_PSS implements Cloneable
     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
+   * 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>
-   *
+   * function.
+   * 
    * @param mHash the byte sequence resulting from applying the message digest
-   * algorithm Hash to the message <i>M</i>.
+   *          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>.
+   *          <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>.
+   *         <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");
-      }
+      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");
-      }
+      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.
@@ -187,9 +153,8 @@ public class EMSA_PSS implements Cloneable
     synchronized (hash)
       {
         for (i = 0; i < 8; i++)
-          {
-            hash.update((byte) 0x00);
-          }
+          hash.update((byte) 0x00);
+
         hash.update(mHash, 0, hLen);
         hash.update(salt, 0, sLen);
         H = hash.digest();
@@ -202,16 +167,14 @@ public class EMSA_PSS implements Cloneable
     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)
+    if (Configuration.DEBUG)
       {
-        debug("dbMask (encode): " + Util.toString(dbMask));
-        debug("DB (encode): " + Util.toString(DB));
+        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]);
-      }
+      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));
@@ -226,14 +189,14 @@ public class EMSA_PSS implements Cloneable
   }
 
   /**
-   * <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>
-   *
+   * 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>.
+   *          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).
+   *          <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.
@@ -244,60 +207,50 @@ public class EMSA_PSS implements Cloneable
    */
   public boolean decode(byte[] mHash, byte[] EM, int emBits, int sLen)
   {
-    if (DEBUG && debuglevel > 8)
+    if (Configuration.DEBUG)
       {
-        debug("mHash: " + Util.toString(mHash));
-        debug("EM: " + Util.toString(EM));
-        debug("emBits: " + String.valueOf(emBits));
-        debug("sLen: " + String.valueOf(sLen));
+        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");
-      }
-
+      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.
+    // 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));
-          }
+        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 (DEBUG && debuglevel > 8)
-          {
-            debug("emBits < (8hLen + 8sLen + 9); sLen: " + String.valueOf(sLen));
-          }
+        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.
+    // output 'inconsistent' and stop.
     if ((EM[EM.length - 1] & 0xFF) != 0xBC)
       {
-        if (DEBUG && debuglevel > 8)
-          {
-            debug("EM does not end with 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.
+    // 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.
+    // 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");
-          }
+        if (Configuration.DEBUG)
+          log.fine("Leftmost 8emLen - emBits bits of EM are not 0s");
         return false;
       }
     byte[] DB = new byte[emLen - hLen - 1];
@@ -309,56 +262,48 @@ public class EMSA_PSS implements Cloneable
     // 8. Let DB = maskedDB XOR dbMask.
     int i;
     for (i = 0; i < DB.length; i++)
-      {
-        DB[i] = (byte) (DB[i] ^ dbMask[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)
+    if (Configuration.DEBUG)
       {
-        debug("dbMask (decode): " + Util.toString(dbMask));
-        debug("DB (decode): " + Util.toString(DB));
+        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.
+    // 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
+    // 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");
-              }
+            if (Configuration.DEBUG)
+              log.fine("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");
-          }
+        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.
+    // 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((byte) 0x00);
+
         hash.update(mHash, 0, hLen);
         hash.update(salt, 0, sLen);
         H0 = hash.digest();
@@ -367,34 +312,30 @@ public class EMSA_PSS implements Cloneable
     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>
-   *
+   * 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.
+   *              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");
-      }
+      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
@@ -409,14 +350,14 @@ public class EMSA_PSS implements Cloneable
     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)
+        // 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 >>> 24));
+        hashZC.update((byte)(i >>> 16));
+        hashZC.update((byte)(i >>> 8));
         hashZC.update((byte) i);
         t = hashZC.digest();
         length = l - sofar;