2 Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
4 This file is a part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or (at
9 your option) any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.java.security.sig.rsa;
41 import gnu.java.security.hash.HashFactory;
42 import gnu.java.security.hash.IMessageDigest;
43 import gnu.java.security.util.Util;
45 import java.io.PrintWriter;
46 import java.util.Arrays;
49 * <p>An implementation of the EMSA-PSS encoding/decoding scheme.</p>
51 * <p>EMSA-PSS coincides with EMSA4 in IEEE P1363a D5 except that EMSA-PSS acts
52 * on octet strings and not on bit strings. In particular, the bit lengths of
53 * the hash and the salt must be multiples of 8 in EMSA-PSS. Moreover, EMSA4
54 * outputs an integer of a desired bit length rather than an octet string.</p>
56 * <p>EMSA-PSS is parameterized by the choice of hash function Hash and mask
57 * generation function MGF. In this submission, MGF is based on a Hash
58 * definition that coincides with the corresponding definitions in IEEE Std
59 * 1363-2000, PKCS #1 v2.0, and the draft ANSI X9.44. In PKCS #1 v2.0 and the
60 * draft ANSI X9.44, the recommended hash function is SHA-1, while IEEE Std
61 * 1363-2000 recommends SHA-1 and RIPEMD-160.</p>
65 * <li><a href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
66 * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
67 * Primitive specification and supporting documentation.<br>
68 * Jakob Jonsson and Burt Kaliski.</li>
71 public class EMSA_PSS implements Cloneable
74 // Debugging methods and variables
75 // -------------------------------------------------------------------------
77 private static final String NAME = "emsa-pss";
79 private static final boolean DEBUG = false;
81 private static final int debuglevel = 5;
83 private static final PrintWriter err = new PrintWriter(System.out, true);
85 private static void debug(String s)
87 err.println(">>> " + NAME + ": " + s);
90 // Constants and variables
91 // -------------------------------------------------------------------------
93 /** The underlying hash function to use with this instance. */
94 private IMessageDigest hash;
96 /** The output size of the hash function in octets. */
100 // -------------------------------------------------------------------------
103 * <p>Trivial private constructor to enforce use through Factory method.</p>
105 * @param hash the message digest instance to use with this scheme instance.
107 private EMSA_PSS(IMessageDigest hash)
112 hLen = hash.hashSize();
116 // -------------------------------------------------------------------------
119 * <p>Returns an instance of this object given a designated name of a hash
122 * @param mdName the canonical name of a hash function.
123 * @return an instance of this object configured for use with the designated
126 public static EMSA_PSS getInstance(String mdName)
128 IMessageDigest hash = HashFactory.getInstance(mdName);
129 return new EMSA_PSS(hash);
133 // -------------------------------------------------------------------------
135 // Cloneable interface implementation --------------------------------------
137 public Object clone()
139 return getInstance(hash.name());
142 // own methods -------------------------------------------------------------
145 * <p>The encoding operation EMSA-PSS-Encode computes the hash of a message
146 * <code>M</code> using a hash function and maps the result to an encoded
147 * message <code>EM</code> of a specified length using a mask generation
150 * @param mHash the byte sequence resulting from applying the message digest
151 * algorithm Hash to the message <i>M</i>.
152 * @param emBits the maximal bit length of the integer OS2IP(EM), at least
153 * <code>8.hLen + 8.sLen + 9</code>.
154 * @param salt the salt to use when encoding the output.
155 * @return the encoded message <code>EM</code>, an octet string of length
156 * <code>emLen = CEILING(emBits / 8)</code>.
157 * @exception IllegalArgumentException if an exception occurs.
160 public byte[] encode(byte[] mHash, int emBits, byte[] salt)
162 int sLen = salt.length;
164 // 1. If the length of M is greater than the input limitation for the hash
165 // function (2**61 - 1 octets for SHA-1) then output "message too long"
167 // 2. Let mHash = Hash(M), an octet string of length hLen.
168 if (hLen != mHash.length)
170 throw new IllegalArgumentException("wrong hash");
172 // 3. If emBits < 8.hLen + 8.sLen + 9, output 'encoding error' and stop.
173 if (emBits < (8 * hLen + 8 * sLen + 9))
175 throw new IllegalArgumentException("encoding error");
177 int emLen = (emBits + 7) / 8;
178 // 4. Generate a random octet string salt of length sLen; if sLen = 0,
179 // then salt is the empty string.
180 // ...passed as argument to accomodate JCE
181 // 5. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt;
182 // M0 is an octet string of length 8 + hLen + sLen with eight initial zero
184 // 6. Let H = Hash(M0), an octet string of length hLen.
189 for (i = 0; i < 8; i++)
191 hash.update((byte) 0x00);
193 hash.update(mHash, 0, hLen);
194 hash.update(salt, 0, sLen);
197 // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
198 // zero octets. The length of PS may be 0.
199 // 8. Let DB = PS || 01 || salt.
200 byte[] DB = new byte[emLen - sLen - hLen - 2 + 1 + sLen];
201 DB[emLen - sLen - hLen - 2] = 0x01;
202 System.arraycopy(salt, 0, DB, emLen - sLen - hLen - 1, sLen);
203 // 9. Let dbMask = MGF(H, emLen - hLen - 1).
204 byte[] dbMask = MGF(H, emLen - hLen - 1);
205 if (DEBUG && debuglevel > 8)
207 debug("dbMask (encode): " + Util.toString(dbMask));
208 debug("DB (encode): " + Util.toString(DB));
210 // 10. Let maskedDB = DB XOR dbMask.
211 for (i = 0; i < DB.length; i++)
213 DB[i] = (byte) (DB[i] ^ dbMask[i]);
215 // 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in
217 DB[0] &= (0xFF >>> (8 * emLen - emBits));
218 // 12. Let EM = maskedDB || H || bc, where bc is the single octet with
219 // hexadecimal value 0xBC.
220 byte[] result = new byte[emLen];
221 System.arraycopy(DB, 0, result, 0, emLen - hLen - 1);
222 System.arraycopy(H, 0, result, emLen - hLen - 1, hLen);
223 result[emLen - 1] = (byte) 0xBC;
229 * <p>The decoding operation EMSA-PSS-Decode recovers the message hash from
230 * an encoded message <code>EM</code> and compares it to the hash of
231 * <code>M</code>.</p>
233 * @param mHash the byte sequence resulting from applying the message digest
234 * algorithm Hash to the message <i>M</i>.
235 * @param EM the <i>encoded message</i>, an octet string of length
236 * <code>emLen = CEILING(emBits/8).
237 * @param emBits the maximal bit length of the integer OS2IP(EM), at least
238 * <code>8.hLen + 8.sLen + 9</code>.
239 * @param sLen the length, in octets, of the expected salt.
240 * @return <code>true</code> if the result of the verification was
241 * <i>consistent</i> with the expected reseult; and <code>false</code> if the
242 * result was <i>inconsistent</i>.
243 * @exception IllegalArgumentException if an exception occurs.
245 public boolean decode(byte[] mHash, byte[] EM, int emBits, int sLen)
247 if (DEBUG && debuglevel > 8)
249 debug("mHash: " + Util.toString(mHash));
250 debug("EM: " + Util.toString(EM));
251 debug("emBits: " + String.valueOf(emBits));
252 debug("sLen: " + String.valueOf(sLen));
256 throw new IllegalArgumentException("sLen");
259 // 1. If the length of M is greater than the input limitation for the hash
260 // function (2**61 ? 1 octets for SHA-1) then output 'inconsistent' and
262 // 2. Let mHash = Hash(M), an octet string of length hLen.
263 if (hLen != mHash.length)
265 if (DEBUG && debuglevel > 8)
267 debug("hLen != mHash.length; hLen: " + String.valueOf(hLen));
269 throw new IllegalArgumentException("wrong hash");
271 // 3. If emBits < 8.hLen + 8.sLen + 9, output 'decoding error' and stop.
272 if (emBits < (8 * hLen + 8 * sLen + 9))
274 if (DEBUG && debuglevel > 8)
276 debug("emBits < (8hLen + 8sLen + 9); sLen: " + String.valueOf(sLen));
278 throw new IllegalArgumentException("decoding error");
280 int emLen = (emBits + 7) / 8;
281 // 4. If the rightmost octet of EM does not have hexadecimal value bc,
282 // output 'inconsistent' and stop.
283 if ((EM[EM.length - 1] & 0xFF) != 0xBC)
285 if (DEBUG && debuglevel > 8)
287 debug("EM does not end with 0xBC");
291 // 5. Let maskedDB be the leftmost emLen ? hLen ? 1 octets of EM, and let
292 // H be the next hLen octets.
293 // 6. If the leftmost 8.emLen ? emBits bits of the leftmost octet in
294 // maskedDB are not all equal to zero, output 'inconsistent' and stop.
295 if ((EM[0] & (0xFF << (8 - (8 * emLen - emBits)))) != 0)
297 if (DEBUG && debuglevel > 8)
299 debug("Leftmost 8emLen - emBits bits of EM are not 0s");
303 byte[] DB = new byte[emLen - hLen - 1];
304 byte[] H = new byte[hLen];
305 System.arraycopy(EM, 0, DB, 0, emLen - hLen - 1);
306 System.arraycopy(EM, emLen - hLen - 1, H, 0, hLen);
307 // 7. Let dbMask = MGF(H, emLen ? hLen ? 1).
308 byte[] dbMask = MGF(H, emLen - hLen - 1);
309 // 8. Let DB = maskedDB XOR dbMask.
311 for (i = 0; i < DB.length; i++)
313 DB[i] = (byte) (DB[i] ^ dbMask[i]);
315 // 9. Set the leftmost 8.emLen ? emBits bits of DB to zero.
316 DB[0] &= (0xFF >>> (8 * emLen - emBits));
317 if (DEBUG && debuglevel > 8)
319 debug("dbMask (decode): " + Util.toString(dbMask));
320 debug("DB (decode): " + Util.toString(DB));
322 // 10. If the emLen -hLen -sLen -2 leftmost octets of DB are not zero or
323 // if the octet at position emLen -hLen -sLen -1 is not equal to 0x01,
324 // output 'inconsistent' and stop.
325 // IMPORTANT (rsn): this is an error in the specs, the index of the 0x01
326 // byte should be emLen -hLen -sLen -2 and not -1! authors have been
328 for (i = 0; i < (emLen - hLen - sLen - 2); i++)
332 if (DEBUG && debuglevel > 8)
334 debug("DB[" + String.valueOf(i) + "] != 0x00");
340 { // i == emLen -hLen -sLen -2
341 if (DEBUG && debuglevel > 8)
343 debug("DB's byte at position (emLen -hLen -sLen -2); i.e. "
344 + String.valueOf(i) + " is not 0x01");
348 // 11. Let salt be the last sLen octets of DB.
349 byte[] salt = new byte[sLen];
350 System.arraycopy(DB, DB.length - sLen, salt, 0, sLen);
351 // 12. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt;
352 // M0 is an octet string of length 8 + hLen + sLen with eight initial
354 // 13. Let H0 = Hash(M0), an octet string of length hLen.
358 for (i = 0; i < 8; i++)
360 hash.update((byte) 0x00);
362 hash.update(mHash, 0, hLen);
363 hash.update(salt, 0, sLen);
366 // 14. If H = H0, output 'consistent.' Otherwise, output 'inconsistent.'
367 return Arrays.equals(H, H0);
370 // helper methods ----------------------------------------------------------
373 * <p>A mask generation function takes an octet string of variable length
374 * and a desired output length as input, and outputs an octet string of the
375 * desired length. There may be restrictions on the length of the input and
376 * output octet strings, but such bounds are generally very large. Mask
377 * generation functions are deterministic; the octet string output is
378 * completely determined by the input octet string. The output of a mask
379 * generation function should be pseudorandom, that is, it should be
380 * infeasible to predict, given one part of the output but not the input,
381 * another part of the output. The provable security of RSA-PSS relies on
382 * the random nature of the output of the mask generation function, which in
383 * turn relies on the random nature of the underlying hash function.</p>
386 * @param l the desired output length in octets.
388 * @exception IllegalArgumentException if the desired output length is too
391 private byte[] MGF(byte[] Z, int l)
393 // 1. If l > (2**32).hLen, output 'mask too long' and stop.
394 if (l < 1 || (l & 0xFFFFFFFFL) > ((hLen & 0xFFFFFFFFL) << 32L))
396 throw new IllegalArgumentException("mask too long");
398 // 2. Let T be the empty octet string.
399 byte[] result = new byte[l];
400 // 3. For i = 0 to CEILING(l/hLen) ? 1, do
401 int limit = ((l + hLen - 1) / hLen) - 1;
402 IMessageDigest hashZ = null;
403 hashZ = (IMessageDigest) hash.clone();
405 hashZ.update(Z, 0, Z.length);
406 IMessageDigest hashZC = null;
410 for (int i = 0; i < limit; i++)
412 // 3.1 Convert i to an octet string C of length 4 with the primitive
413 // I2OSP: C = I2OSP(i, 4).
414 // 3.2 Concatenate the hash of the seed Z and C to the octet string T:
415 // T = T || Hash(Z || C)
416 hashZC = (IMessageDigest) hashZ.clone();
417 hashZC.update((byte) (i >>> 24));
418 hashZC.update((byte) (i >>> 16));
419 hashZC.update((byte) (i >>> 8));
420 hashZC.update((byte) i);
423 length = (length > hLen ? hLen : length);
424 System.arraycopy(t, 0, result, sofar, length);
427 // 4. Output the leading l octets of T as the octet string mask.