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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [javax/] [crypto/] [mac/] [TMMH16.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* TMMH16.java --
2
   Copyright (C) 2001, 2002, 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.javax.crypto.mac;
40
 
41
import gnu.java.security.Registry;
42
import gnu.java.security.prng.IRandom;
43
import gnu.java.security.prng.LimitReachedException;
44
 
45
import java.security.InvalidKeyException;
46
import java.util.Map;
47
 
48
/**
49
 * <i>TMMH</i> is a <i>universal</i> hash function suitable for message
50
 * authentication in the Wegman-Carter paradigm, as in the Stream Cipher
51
 * Security Transform. It is simple, quick, and especially appropriate for
52
 * Digital Signal Processors and other processors with a fast multiply
53
 * operation, though a straightforward implementation requires storage equal in
54
 * length to the largest message to be hashed.
55
 * <p>
56
 * <i>TMMH</i> is a simple hash function which maps a key and a message to a
57
 * hash value. There are two versions of TMMH: TMMH/16 and TMMH/32. <i>TMMH</i>
58
 * can be used as a message authentication code, as described in Section 5 (see
59
 * References).
60
 * <p>
61
 * The key, message, and hash value are all octet strings, and the lengths of
62
 * these quantities are denoted as <code>KEY_LENGTH</code>,
63
 * <code>MESSAGE_LENGTH</code>, and <code>TAG_LENGTH</code>, respectively.
64
 * The values of <code>KEY_LENGTH</code> and <code>TAG_LENGTH</code>
65
 * <bold>MUST</bold> be fixed for any particular fixed value of the key, and
66
 * must obey the alignment restrictions described below.
67
 * <p>
68
 * The parameter <code>MAX_HASH_LENGTH</code>, which denotes the maximum
69
 * value which <code>MESSAGE_LENGTH</code> may take, is equal to
70
 * <code>KEY_LENGTH - TAG_LENGTH</code>.
71
 * <p>
72
 * References:
73
 * <ol>
74
 * <li><a
75
 * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-tmmh-01.txt"> The
76
 * Truncated Multi-Modular Hash Function (TMMH)</a>, David A. McGrew.</li>
77
 * </ol>
78
 */
79
public class TMMH16
80
    extends BaseMac
81
    implements Cloneable
82
{
83
  public static final String TAG_LENGTH = "gnu.crypto.mac.tmmh.tag.length";
84
  public static final String KEYSTREAM = "gnu.crypto.mac.tmmh.keystream";
85
  public static final String PREFIX = "gnu.crypto.mac.tmmh.prefix";
86
  private static final int P = (1 << 16) + 1; // the TMMH/16 prime
87
  /** caches the result of the correctness test, once executed. */
88
  private static Boolean valid;
89
  private int tagWords = 0; // the tagLength expressed in words
90
  private IRandom keystream = null; // the keystream generator
91
  private byte[] prefix; // mask to use when operating as an authentication f.
92
  private long keyWords; // key words counter
93
  private long msgLength; // in bytes
94
  private long msgWords; // should be = msgLength * WORD_LENGTH
95
  private int[] context; // the tmmh running context; length == TAG_WORDS
96
  private int[] K0; // the first TAG_WORDS words of the keystream
97
  private int[] Ki; // the sliding TAG_WORDS words of the keystream
98
  private int Mi; // current message word being constructed
99
 
100
  /** Trivial 0-arguments constructor. */
101
  public TMMH16()
102
  {
103
    super(Registry.TMMH16);
104
  }
105
 
106
  public int macSize()
107
  {
108
    return tagWords * 2;
109
  }
110
 
111
  public void init(Map attributes) throws InvalidKeyException,
112
      IllegalStateException
113
  {
114
    int wantTagLength = 0;
115
    Integer tagLength = (Integer) attributes.get(TAG_LENGTH); // get tag length
116
    if (tagLength == null)
117
      {
118
        if (tagWords == 0) // was never set
119
          throw new IllegalArgumentException(TAG_LENGTH);
120
        // else re-use
121
      }
122
    else // check if positive and is divisible by WORD_LENGTH
123
      {
124
        wantTagLength = tagLength.intValue();
125
        if (wantTagLength < 2 || (wantTagLength % 2 != 0))
126
          throw new IllegalArgumentException(TAG_LENGTH);
127
        else if (wantTagLength > (512 / 8)) // 512-bits is our maximum
128
          throw new IllegalArgumentException(TAG_LENGTH);
129
 
130
        tagWords = wantTagLength / 2; // init local vars
131
        K0 = new int[tagWords];
132
        Ki = new int[tagWords];
133
        context = new int[tagWords];
134
      }
135
 
136
    prefix = (byte[]) attributes.get(PREFIX);
137
    if (prefix == null) // default to all-zeroes
138
      prefix = new byte[tagWords * 2];
139
    else // ensure it's as long as it should
140
      {
141
        if (prefix.length != tagWords * 2)
142
          throw new IllegalArgumentException(PREFIX);
143
      }
144
 
145
    IRandom prng = (IRandom) attributes.get(KEYSTREAM); // get keystream
146
    if (prng == null)
147
      {
148
        if (keystream == null)
149
          throw new IllegalArgumentException(KEYSTREAM);
150
        // else reuse
151
      }
152
    else
153
      keystream = prng;
154
 
155
    reset(); // reset context variables
156
    for (int i = 0; i < tagWords; i++) // init starting key words
157
      Ki[i] = K0[i] = getNextKeyWord(keystream);
158
  }
159
 
160
  // The words of the key are denoted as K[1], K[2], ..., K[KEY_WORDS], and the
161
  // words of the message (after zero padding, if needed) are denoted as M[1],
162
  // M[2], ..., M[MSG_WORDS], where MSG_WORDS is the smallest number such that
163
  // 2 * MSG_WORDS is at least MESSAGE_LENGTH, and KEY_WORDS is KEY_LENGTH / 2.
164
  //
165
  // If MESSAGE_LENGTH is greater than MAX_HASH_LENGTH, then the value of
166
  // TMMH/16 is undefined. Implementations MUST indicate an error if asked to
167
  // hash a message with such a length. Otherwise, the hash value is defined
168
  // to be the length TAG_WORDS sequence of words in which the j-th word in the
169
  // sequence is defined as
170
  //
171
  // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2]
172
  // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16
173
  //
174
  // where j ranges from 1 to TAG_WORDS.
175
  public void update(byte b)
176
  {
177
    this.update(b, keystream);
178
  }
179
 
180
  public void update(byte[] b, int offset, int len)
181
  {
182
    for (int i = 0; i < len; i++)
183
      this.update(b[offset + i], keystream);
184
  }
185
 
186
  // For TMMH/16, KEY_LENGTH and TAG_LENGTH MUST be a multiple of two. The key,
187
  // message, and hash value are treated as a sequence of unsigned sixteen bit
188
  // integers in network byte order. (In this section, we call such an integer
189
  // a word.) If MESSAGE_LENGTH is odd, then a zero byte is appended to the
190
  // message to align it on a word boundary, though this process does not
191
  // change the value of MESSAGE_LENGTH.
192
  //
193
  // ... Otherwise, the hash value is defined to be the length TAG_WORDS
194
  // sequence of words in which the j-th word in the sequence is defined as
195
  //
196
  // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2]
197
  // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16
198
  //
199
  // where j ranges from 1 to TAG_WORDS.
200
  //
201
  // Here, TAG_WORDS is equal to TAG_LENGTH / 2, and p is equal to 2^16 + 1.
202
  // The symbol * denotes multiplication and the symbol +32 denotes addition
203
  // modulo 2^32.
204
  public byte[] digest()
205
  {
206
    return this.digest(keystream);
207
  }
208
 
209
  public void reset()
210
  {
211
    msgLength = msgWords = keyWords = 0L;
212
    Mi = 0;
213
    for (int i = 0; i < tagWords; i++)
214
      context[i] = 0;
215
  }
216
 
217
  public boolean selfTest()
218
  {
219
    if (valid == null)
220
      {
221
        // TODO: compute and test equality with one known vector
222
        valid = Boolean.TRUE;
223
      }
224
    return valid.booleanValue();
225
  }
226
 
227
  public Object clone() throws CloneNotSupportedException
228
  {
229
    TMMH16 result = (TMMH16) super.clone();
230
    if (this.keystream != null)
231
      result.keystream = (IRandom) this.keystream.clone();
232
    if (this.prefix != null)
233
      result.prefix = (byte[]) this.prefix.clone();
234
    if (this.context != null)
235
      result.context = (int[]) this.context.clone();
236
    if (this.K0 != null)
237
      result.K0 = (int[]) this.K0.clone();
238
    if (this.Ki != null)
239
      result.Ki = (int[]) this.Ki.clone();
240
    return result;
241
  }
242
 
243
  /**
244
   * Similar to the same method with one argument, but uses the designated
245
   * random number generator to compute needed keying material.
246
   *
247
   * @param b the byte to process.
248
   * @param prng the source of randomness to use.
249
   */
250
  public void update(byte b, IRandom prng)
251
  {
252
    Mi <<= 8; // update message buffer
253
    Mi |= b & 0xFF;
254
    msgLength++; // update message length (bytes)
255
    if (msgLength % 2 == 0) // got a full word
256
      {
257
        msgWords++; // update message words counter
258
        System.arraycopy(Ki, 1, Ki, 0, tagWords - 1); // 1. shift Ki up by 1
259
        Ki[tagWords - 1] = getNextKeyWord(prng); // 2. fill last box of Ki
260
        long t; // temp var to allow working in modulo 2^32
261
        for (int i = 0; i < tagWords; i++) // 3. update context
262
          {
263
            t = context[i] & 0xFFFFFFFFL;
264
            t += Ki[i] * Mi;
265
            context[i] = (int) t;
266
          }
267
        Mi = 0; // reset message buffer
268
      }
269
  }
270
 
271
  /**
272
   * Similar to the same method with three arguments, but uses the designated
273
   * random number generator to compute needed keying material.
274
   *
275
   * @param b the byte array to process.
276
   * @param offset the starting offset in <code>b</code> to start considering
277
   *          the bytes to process.
278
   * @param len the number of bytes in <code>b</code> starting from
279
   *          <code>offset</code> to process.
280
   * @param prng the source of randomness to use.
281
   */
282
  public void update(byte[] b, int offset, int len, IRandom prng)
283
  {
284
    for (int i = 0; i < len; i++)
285
      this.update(b[offset + i], prng);
286
  }
287
 
288
  /**
289
   * Similar to the same method with no arguments, but uses the designated
290
   * random number generator to compute needed keying material.
291
   *
292
   * @param prng the source of randomness to use.
293
   * @return the final result of the algorithm.
294
   */
295
  public byte[] digest(IRandom prng)
296
  {
297
    doFinalRound(prng);
298
    byte[] result = new byte[tagWords * 2];
299
    for (int i = 0, j = 0; i < tagWords; i++)
300
      {
301
        result[j] = (byte)((context[i] >>> 8) ^ prefix[j]);
302
        j++;
303
        result[j] = (byte)(context[i] ^ prefix[j]);
304
        j++;
305
      }
306
    reset();
307
    return result;
308
  }
309
 
310
  private int getNextKeyWord(IRandom prng)
311
  {
312
    int result = 0;
313
    try
314
      {
315
        result = (prng.nextByte() & 0xFF) << 8 | (prng.nextByte() & 0xFF);
316
      }
317
    catch (LimitReachedException x)
318
      {
319
        throw new RuntimeException(String.valueOf(x));
320
      }
321
    keyWords++; // update key words counter
322
    return result;
323
  }
324
 
325
  private void doFinalRound(IRandom prng)
326
  {
327
    long limit = msgLength; // formula works on real message length
328
    while (msgLength % 2 != 0)
329
      update((byte) 0x00, prng);
330
    long t;
331
    for (int i = 0; i < tagWords; i++)
332
      {
333
        t = context[i] & 0xFFFFFFFFL;
334
        t += K0[i] * limit;
335
        t %= P;
336
        context[i] = (int) t;
337
      }
338
  }
339
}

powered by: WebSVN 2.1.0

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