OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [java/] [security/] [sig/] [rsa/] [EMSA_PSS.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* 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.Configuration;
42
import gnu.java.security.hash.HashFactory;
43
import gnu.java.security.hash.IMessageDigest;
44
import gnu.java.security.util.Util;
45
 
46
import java.util.Arrays;
47
import java.util.logging.Logger;
48
 
49
/**
50
 * An implementation of the EMSA-PSS encoding/decoding scheme.
51
 * <p>
52
 * EMSA-PSS coincides with EMSA4 in IEEE P1363a D5 except that EMSA-PSS acts on
53
 * octet strings and not on bit strings. In particular, the bit lengths of the
54
 * hash and the salt must be multiples of 8 in EMSA-PSS. Moreover, EMSA4 outputs
55
 * an integer of a desired bit length rather than an octet string.
56
 * <p>
57
 * EMSA-PSS is parameterized by the choice of hash function Hash and mask
58
 * generation function MGF. In this submission, MGF is based on a Hash
59
 * definition that coincides with the corresponding definitions in IEEE Std
60
 * 1363-2000, PKCS #1 v2.0, and the draft ANSI X9.44. In PKCS #1 v2.0 and the
61
 * draft ANSI X9.44, the recommended hash function is SHA-1, while IEEE Std
62
 * 1363-2000 recommends SHA-1 and RIPEMD-160.
63
 * <p>
64
 * References:
65
 * <ol>
66
 * <li><a
67
 * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
68
 * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
69
 * Primitive specification and supporting documentation.<br>
70
 * Jakob Jonsson and Burt Kaliski.</li>
71
 * </ol>
72
 */
73
public class EMSA_PSS
74
    implements Cloneable
75
{
76
  private static final Logger log = Logger.getLogger(EMSA_PSS.class.getName());
77
 
78
  /** The underlying hash function to use with this instance. */
79
  private IMessageDigest hash;
80
 
81
  /** The output size of the hash function in octets. */
82
  private int hLen;
83
 
84
  /**
85
   * Trivial private constructor to enforce use through Factory method.
86
   *
87
   * @param hash the message digest instance to use with this scheme instance.
88
   */
89
  private EMSA_PSS(IMessageDigest hash)
90
  {
91
    super();
92
 
93
    this.hash = hash;
94
    hLen = hash.hashSize();
95
  }
96
 
97
  /**
98
   * Returns an instance of this object given a designated name of a hash
99
   * function.
100
   *
101
   * @param mdName the canonical name of a hash function.
102
   * @return an instance of this object configured for use with the designated
103
   *         options.
104
   */
105
  public static EMSA_PSS getInstance(String mdName)
106
  {
107
    IMessageDigest hash = HashFactory.getInstance(mdName);
108
    return new EMSA_PSS(hash);
109
  }
110
 
111
  public Object clone()
112
  {
113
    return getInstance(hash.name());
114
  }
115
 
116
  /**
117
   * The encoding operation EMSA-PSS-Encode computes the hash of a message
118
   * <code>M</code> using a hash function and maps the result to an encoded
119
   * message <code>EM</code> of a specified length using a mask generation
120
   * function.
121
   *
122
   * @param mHash the byte sequence resulting from applying the message digest
123
   *          algorithm Hash to the message <i>M</i>.
124
   * @param emBits the maximal bit length of the integer OS2IP(EM), at least
125
   *          <code>8.hLen + 8.sLen + 9</code>.
126
   * @param salt the salt to use when encoding the output.
127
   * @return the encoded message <code>EM</code>, an octet string of length
128
   *         <code>emLen = CEILING(emBits / 8)</code>.
129
   * @exception IllegalArgumentException if an exception occurs.
130
   */
131
  public byte[] encode(byte[] mHash, int emBits, byte[] salt)
132
  {
133
    int sLen = salt.length;
134
    // 1. If the length of M is greater than the input limitation for the hash
135
    // function (2**61 - 1 octets for SHA-1) then output "message too long"
136
    // and stop.
137
    // 2. Let mHash = Hash(M), an octet string of length hLen.
138
    if (hLen != mHash.length)
139
      throw new IllegalArgumentException("wrong hash");
140
    // 3. If emBits < 8.hLen + 8.sLen + 9, output 'encoding error' and stop.
141
    if (emBits < (8 * hLen + 8 * sLen + 9))
142
      throw new IllegalArgumentException("encoding error");
143
    int emLen = (emBits + 7) / 8;
144
    // 4. Generate a random octet string salt of length sLen; if sLen = 0,
145
    // then salt is the empty string.
146
    // ...passed as argument to accomodate JCE
147
    // 5. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt;
148
    // M0 is an octet string of length 8 + hLen + sLen with eight initial zero
149
    // octets.
150
    // 6. Let H = Hash(M0), an octet string of length hLen.
151
    byte[] H;
152
    int i;
153
    synchronized (hash)
154
      {
155
        for (i = 0; i < 8; i++)
156
          hash.update((byte) 0x00);
157
 
158
        hash.update(mHash, 0, hLen);
159
        hash.update(salt, 0, sLen);
160
        H = hash.digest();
161
      }
162
    // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
163
    // zero octets. The length of PS may be 0.
164
    // 8. Let DB = PS || 01 || salt.
165
    byte[] DB = new byte[emLen - sLen - hLen - 2 + 1 + sLen];
166
    DB[emLen - sLen - hLen - 2] = 0x01;
167
    System.arraycopy(salt, 0, DB, emLen - sLen - hLen - 1, sLen);
168
    // 9. Let dbMask = MGF(H, emLen - hLen - 1).
169
    byte[] dbMask = MGF(H, emLen - hLen - 1);
170
    if (Configuration.DEBUG)
171
      {
172
        log.fine("dbMask (encode): " + Util.toString(dbMask));
173
        log.fine("DB (encode): " + Util.toString(DB));
174
      }
175
    // 10. Let maskedDB = DB XOR dbMask.
176
    for (i = 0; i < DB.length; i++)
177
      DB[i] = (byte)(DB[i] ^ dbMask[i]);
178
    // 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in
179
    // maskedDB to zero.
180
    DB[0] &= (0xFF >>> (8 * emLen - emBits));
181
    // 12. Let EM = maskedDB || H || bc, where bc is the single octet with
182
    // hexadecimal value 0xBC.
183
    byte[] result = new byte[emLen];
184
    System.arraycopy(DB, 0, result, 0, emLen - hLen - 1);
185
    System.arraycopy(H, 0, result, emLen - hLen - 1, hLen);
186
    result[emLen - 1] = (byte) 0xBC;
187
    // 13. Output EM.
188
    return result;
189
  }
190
 
191
  /**
192
   * The decoding operation EMSA-PSS-Decode recovers the message hash from an
193
   * encoded message <code>EM</code> and compares it to the hash of
194
   * <code>M</code>.
195
   *
196
   * @param mHash the byte sequence resulting from applying the message digest
197
   *          algorithm Hash to the message <i>M</i>.
198
   * @param EM the <i>encoded message</i>, an octet string of length
199
   *          <code>emLen = CEILING(emBits/8).
200
   * @param emBits the maximal bit length of the integer OS2IP(EM), at least
201
   * <code>8.hLen + 8.sLen + 9</code>.
202
   * @param sLen the length, in octets, of the expected salt.
203
   * @return <code>true</code> if the result of the verification was
204
   * <i>consistent</i> with the expected reseult; and <code>false</code> if the
205
   * result was <i>inconsistent</i>.
206
   * @exception IllegalArgumentException if an exception occurs.
207
   */
208
  public boolean decode(byte[] mHash, byte[] EM, int emBits, int sLen)
209
  {
210
    if (Configuration.DEBUG)
211
      {
212
        log.fine("mHash: " + Util.toString(mHash));
213
        log.fine("EM: " + Util.toString(EM));
214
        log.fine("emBits: " + String.valueOf(emBits));
215
        log.fine("sLen: " + String.valueOf(sLen));
216
      }
217
    if (sLen < 0)
218
      throw new IllegalArgumentException("sLen");
219
    // 1. If the length of M is greater than the input limitation for the hash
220
    // function (2**61 ? 1 octets for SHA-1) then output 'inconsistent' and
221
    // stop.
222
    // 2. Let mHash = Hash(M), an octet string of length hLen.
223
    if (hLen != mHash.length)
224
      {
225
        if (Configuration.DEBUG)
226
          log.fine("hLen != mHash.length; hLen: " + String.valueOf(hLen));
227
        throw new IllegalArgumentException("wrong hash");
228
      }
229
    // 3. If emBits < 8.hLen + 8.sLen + 9, output 'decoding error' and stop.
230
    if (emBits < (8 * hLen + 8 * sLen + 9))
231
      {
232
        if (Configuration.DEBUG)
233
          log.fine("emBits < (8hLen + 8sLen + 9); sLen: "
234
                   + String.valueOf(sLen));
235
        throw new IllegalArgumentException("decoding error");
236
      }
237
    int emLen = (emBits + 7) / 8;
238
    // 4. If the rightmost octet of EM does not have hexadecimal value bc,
239
    // output 'inconsistent' and stop.
240
    if ((EM[EM.length - 1] & 0xFF) != 0xBC)
241
      {
242
        if (Configuration.DEBUG)
243
          log.fine("EM does not end with 0xBC");
244
        return false;
245
      }
246
    // 5. Let maskedDB be the leftmost emLen ? hLen ? 1 octets of EM, and let
247
    // H be the next hLen octets.
248
    // 6. If the leftmost 8.emLen ? emBits bits of the leftmost octet in
249
    // maskedDB are not all equal to zero, output 'inconsistent' and stop.
250
    if ((EM[0] & (0xFF << (8 - (8 * emLen - emBits)))) != 0)
251
      {
252
        if (Configuration.DEBUG)
253
          log.fine("Leftmost 8emLen - emBits bits of EM are not 0s");
254
        return false;
255
      }
256
    byte[] DB = new byte[emLen - hLen - 1];
257
    byte[] H = new byte[hLen];
258
    System.arraycopy(EM, 0, DB, 0, emLen - hLen - 1);
259
    System.arraycopy(EM, emLen - hLen - 1, H, 0, hLen);
260
    // 7. Let dbMask = MGF(H, emLen ? hLen ? 1).
261
    byte[] dbMask = MGF(H, emLen - hLen - 1);
262
    // 8. Let DB = maskedDB XOR dbMask.
263
    int i;
264
    for (i = 0; i < DB.length; i++)
265
      DB[i] = (byte)(DB[i] ^ dbMask[i]);
266
    // 9. Set the leftmost 8.emLen ? emBits bits of DB to zero.
267
    DB[0] &= (0xFF >>> (8 * emLen - emBits));
268
    if (Configuration.DEBUG)
269
      {
270
        log.fine("dbMask (decode): " + Util.toString(dbMask));
271
        log.fine("DB (decode): " + Util.toString(DB));
272
      }
273
    // 10. If the emLen -hLen -sLen -2 leftmost octets of DB are not zero or
274
    // if the octet at position emLen -hLen -sLen -1 is not equal to 0x01,
275
    // output 'inconsistent' and stop.
276
    // IMPORTANT (rsn): this is an error in the specs, the index of the 0x01
277
    // byte should be emLen -hLen -sLen -2 and not -1! authors have been advised
278
    for (i = 0; i < (emLen - hLen - sLen - 2); i++)
279
      {
280
        if (DB[i] != 0)
281
          {
282
            if (Configuration.DEBUG)
283
              log.fine("DB[" + String.valueOf(i) + "] != 0x00");
284
            return false;
285
          }
286
      }
287
    if (DB[i] != 0x01)
288
      { // i == emLen -hLen -sLen -2
289
        if (Configuration.DEBUG)
290
          log.fine("DB's byte at position (emLen -hLen -sLen -2); i.e. "
291
                   + String.valueOf(i) + " is not 0x01");
292
        return false;
293
      }
294
    // 11. Let salt be the last sLen octets of DB.
295
    byte[] salt = new byte[sLen];
296
    System.arraycopy(DB, DB.length - sLen, salt, 0, sLen);
297
    // 12. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt;
298
    // M0 is an octet string of length 8 + hLen + sLen with eight initial
299
    // zero octets.
300
    // 13. Let H0 = Hash(M0), an octet string of length hLen.
301
    byte[] H0;
302
    synchronized (hash)
303
      {
304
        for (i = 0; i < 8; i++)
305
          hash.update((byte) 0x00);
306
 
307
        hash.update(mHash, 0, hLen);
308
        hash.update(salt, 0, sLen);
309
        H0 = hash.digest();
310
      }
311
    // 14. If H = H0, output 'consistent.' Otherwise, output 'inconsistent.'
312
    return Arrays.equals(H, H0);
313
  }
314
 
315
  /**
316
   * A mask generation function takes an octet string of variable length and a
317
   * desired output length as input, and outputs an octet string of the desired
318
   * length. There may be restrictions on the length of the input and output
319
   * octet strings, but such bounds are generally very large. Mask generation
320
   * functions are deterministic; the octet string output is completely
321
   * determined by the input octet string. The output of a mask generation
322
   * function should be pseudorandom, that is, it should be infeasible to
323
   * predict, given one part of the output but not the input, another part of
324
   * the output. The provable security of RSA-PSS relies on the random nature of
325
   * the output of the mask generation function, which in turn relies on the
326
   * random nature of the underlying hash function.
327
   *
328
   * @param Z a seed.
329
   * @param l the desired output length in octets.
330
   * @return the mask.
331
   * @exception IllegalArgumentException if the desired output length is too
332
   *              long.
333
   */
334
  private byte[] MGF(byte[] Z, int l)
335
  {
336
    // 1. If l > (2**32).hLen, output 'mask too long' and stop.
337
    if (l < 1 || (l & 0xFFFFFFFFL) > ((hLen & 0xFFFFFFFFL) << 32L))
338
      throw new IllegalArgumentException("mask too long");
339
    // 2. Let T be the empty octet string.
340
    byte[] result = new byte[l];
341
    // 3. For i = 0 to CEILING(l/hLen) ? 1, do
342
    int limit = ((l + hLen - 1) / hLen) - 1;
343
    IMessageDigest hashZ = null;
344
    hashZ = (IMessageDigest) hash.clone();
345
    hashZ.digest();
346
    hashZ.update(Z, 0, Z.length);
347
    IMessageDigest hashZC = null;
348
    byte[] t;
349
    int sofar = 0;
350
    int length;
351
    for (int i = 0; i < limit; i++)
352
      {
353
        // 3.1 Convert i to an octet string C of length 4 with the primitive
354
        // I2OSP: C = I2OSP(i, 4).
355
        // 3.2 Concatenate the hash of the seed Z and C to the octet string T:
356
        // T = T || Hash(Z || C)
357
        hashZC = (IMessageDigest) hashZ.clone();
358
        hashZC.update((byte)(i >>> 24));
359
        hashZC.update((byte)(i >>> 16));
360
        hashZC.update((byte)(i >>> 8));
361
        hashZC.update((byte) i);
362
        t = hashZC.digest();
363
        length = l - sofar;
364
        length = (length > hLen ? hLen : length);
365
        System.arraycopy(t, 0, result, sofar, length);
366
        sofar += length;
367
      }
368
    // 4. Output the leading l octets of T as the octet string mask.
369
    return result;
370
  }
371
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.