OSDN Git Service

Imported GNU Classpath 0.90
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / java / security / sig / rsa / EMSA_PSS.java
1 /* EMSA_PSS.java -- 
2    Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
3
4 This file is a part of GNU Classpath.
5
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.
10
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.
15
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
19 USA
20
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
24 combination.
25
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.  */
37
38
39 package gnu.java.security.sig.rsa;
40
41 import gnu.java.security.hash.HashFactory;
42 import gnu.java.security.hash.IMessageDigest;
43 import gnu.java.security.util.Util;
44
45 import java.io.PrintWriter;
46 import java.util.Arrays;
47
48 /**
49  * <p>An implementation of the EMSA-PSS encoding/decoding scheme.</p>
50  *
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>
55  *
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>
62  *
63  * <p>References:</p>
64  * <ol>
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>
69  * </ol>
70  */
71 public class EMSA_PSS implements Cloneable
72 {
73
74   // Debugging methods and variables
75   // -------------------------------------------------------------------------
76
77   private static final String NAME = "emsa-pss";
78
79   private static final boolean DEBUG = false;
80
81   private static final int debuglevel = 5;
82
83   private static final PrintWriter err = new PrintWriter(System.out, true);
84
85   private static void debug(String s)
86   {
87     err.println(">>> " + NAME + ": " + s);
88   }
89
90   // Constants and variables
91   // -------------------------------------------------------------------------
92
93   /** The underlying hash function to use with this instance. */
94   private IMessageDigest hash;
95
96   /** The output size of the hash function in octets. */
97   private int hLen;
98
99   // Constructor(s)
100   // -------------------------------------------------------------------------
101
102   /**
103    * <p>Trivial private constructor to enforce use through Factory method.</p>
104    *
105    * @param hash the message digest instance to use with this scheme instance.
106    */
107   private EMSA_PSS(IMessageDigest hash)
108   {
109     super();
110
111     this.hash = hash;
112     hLen = hash.hashSize();
113   }
114
115   // Class methods
116   // -------------------------------------------------------------------------
117
118   /**
119    * <p>Returns an instance of this object given a designated name of a hash
120    * function.</p>
121    *
122    * @param mdName the canonical name of a hash function.
123    * @return an instance of this object configured for use with the designated
124    * options.
125    */
126   public static EMSA_PSS getInstance(String mdName)
127   {
128     IMessageDigest hash = HashFactory.getInstance(mdName);
129     return new EMSA_PSS(hash);
130   }
131
132   // Instance methods
133   // -------------------------------------------------------------------------
134
135   // Cloneable interface implementation --------------------------------------
136
137   public Object clone()
138   {
139     return getInstance(hash.name());
140   }
141
142   // own methods -------------------------------------------------------------
143
144   /**
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
148    * function.</p>
149    *
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.
158    *
159    */
160   public byte[] encode(byte[] mHash, int emBits, byte[] salt)
161   {
162     int sLen = salt.length;
163
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"
166     // and stop.
167     // 2. Let mHash = Hash(M), an octet string of length hLen.
168     if (hLen != mHash.length)
169       {
170         throw new IllegalArgumentException("wrong hash");
171       }
172     // 3. If emBits < 8.hLen + 8.sLen + 9, output 'encoding error' and stop.
173     if (emBits < (8 * hLen + 8 * sLen + 9))
174       {
175         throw new IllegalArgumentException("encoding error");
176       }
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
183     // octets.
184     // 6. Let H = Hash(M0), an octet string of length hLen.
185     byte[] H;
186     int i;
187     synchronized (hash)
188       {
189         for (i = 0; i < 8; i++)
190           {
191             hash.update((byte) 0x00);
192           }
193         hash.update(mHash, 0, hLen);
194         hash.update(salt, 0, sLen);
195         H = hash.digest();
196       }
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)
206       {
207         debug("dbMask (encode): " + Util.toString(dbMask));
208         debug("DB (encode): " + Util.toString(DB));
209       }
210     // 10. Let maskedDB = DB XOR dbMask.
211     for (i = 0; i < DB.length; i++)
212       {
213         DB[i] = (byte) (DB[i] ^ dbMask[i]);
214       }
215     // 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in
216     // maskedDB to zero.
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;
224     // 13. Output EM.
225     return result;
226   }
227
228   /**
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>
232    *
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.
244    */
245   public boolean decode(byte[] mHash, byte[] EM, int emBits, int sLen)
246   {
247     if (DEBUG && debuglevel > 8)
248       {
249         debug("mHash: " + Util.toString(mHash));
250         debug("EM: " + Util.toString(EM));
251         debug("emBits: " + String.valueOf(emBits));
252         debug("sLen: " + String.valueOf(sLen));
253       }
254     if (sLen < 0)
255       {
256         throw new IllegalArgumentException("sLen");
257       }
258
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
261     //    stop.
262     // 2. Let mHash = Hash(M), an octet string of length hLen.
263     if (hLen != mHash.length)
264       {
265         if (DEBUG && debuglevel > 8)
266           {
267             debug("hLen != mHash.length; hLen: " + String.valueOf(hLen));
268           }
269         throw new IllegalArgumentException("wrong hash");
270       }
271     // 3. If emBits < 8.hLen + 8.sLen + 9, output 'decoding error' and stop.
272     if (emBits < (8 * hLen + 8 * sLen + 9))
273       {
274         if (DEBUG && debuglevel > 8)
275           {
276             debug("emBits < (8hLen + 8sLen + 9); sLen: " + String.valueOf(sLen));
277           }
278         throw new IllegalArgumentException("decoding error");
279       }
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)
284       {
285         if (DEBUG && debuglevel > 8)
286           {
287             debug("EM does not end with 0xBC");
288           }
289         return false;
290       }
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)
296       {
297         if (DEBUG && debuglevel > 8)
298           {
299             debug("Leftmost 8emLen - emBits bits of EM are not 0s");
300           }
301         return false;
302       }
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.
310     int i;
311     for (i = 0; i < DB.length; i++)
312       {
313         DB[i] = (byte) (DB[i] ^ dbMask[i]);
314       }
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)
318       {
319         debug("dbMask (decode): " + Util.toString(dbMask));
320         debug("DB (decode): " + Util.toString(DB));
321       }
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
327     // advised
328     for (i = 0; i < (emLen - hLen - sLen - 2); i++)
329       {
330         if (DB[i] != 0)
331           {
332             if (DEBUG && debuglevel > 8)
333               {
334                 debug("DB[" + String.valueOf(i) + "] != 0x00");
335               }
336             return false;
337           }
338       }
339     if (DB[i] != 0x01)
340       { // i == emLen -hLen -sLen -2
341         if (DEBUG && debuglevel > 8)
342           {
343             debug("DB's byte at position (emLen -hLen -sLen -2); i.e. "
344                   + String.valueOf(i) + " is not 0x01");
345           }
346         return false;
347       }
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
353     //     zero octets.
354     // 13. Let H0 = Hash(M0), an octet string of length hLen.
355     byte[] H0;
356     synchronized (hash)
357       {
358         for (i = 0; i < 8; i++)
359           {
360             hash.update((byte) 0x00);
361           }
362         hash.update(mHash, 0, hLen);
363         hash.update(salt, 0, sLen);
364         H0 = hash.digest();
365       }
366     // 14. If H = H0, output 'consistent.' Otherwise, output 'inconsistent.'
367     return Arrays.equals(H, H0);
368   }
369
370   // helper methods ----------------------------------------------------------
371
372   /**
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>
384    *
385    * @param Z a seed.
386    * @param l the desired output length in octets.
387    * @return the mask.
388    * @exception IllegalArgumentException if the desired output length is too
389    * long.
390    */
391   private byte[] MGF(byte[] Z, int l)
392   {
393     // 1. If l > (2**32).hLen, output 'mask too long' and stop.
394     if (l < 1 || (l & 0xFFFFFFFFL) > ((hLen & 0xFFFFFFFFL) << 32L))
395       {
396         throw new IllegalArgumentException("mask too long");
397       }
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();
404     hashZ.digest();
405     hashZ.update(Z, 0, Z.length);
406     IMessageDigest hashZC = null;
407     byte[] t;
408     int sofar = 0;
409     int length;
410     for (int i = 0; i < limit; i++)
411       {
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);
421         t = hashZC.digest();
422         length = l - sofar;
423         length = (length > hLen ? hLen : length);
424         System.arraycopy(t, 0, result, sofar, length);
425         sofar += length;
426       }
427     // 4. Output the leading l octets of T as the octet string mask.
428     return result;
429   }
430 }