diff options
Diffstat (limited to 'libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java')
-rw-r--r-- | libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java | 267 |
1 files changed, 104 insertions, 163 deletions
diff --git a/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java index c1c9760ed5c..97b3afcf8c1 100644 --- a/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java +++ b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java @@ -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; |