Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / gnu / javax / crypto / mac / UMac32.java
blob01388885699323d82572b7201e6ce8a3168fb84a
1 /* UMac32.java --
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
19 USA
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.
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.javax.crypto.mac;
41 import gnu.java.security.Registry;
42 import gnu.java.security.prng.IRandom;
43 import gnu.java.security.prng.LimitReachedException;
44 import gnu.java.security.util.Util;
45 import gnu.javax.crypto.cipher.CipherFactory;
46 import gnu.javax.crypto.cipher.IBlockCipher;
47 import gnu.javax.crypto.prng.UMacGenerator;
49 import java.io.UnsupportedEncodingException;
50 import java.math.BigInteger;
51 import java.security.InvalidKeyException;
52 import java.util.HashMap;
53 import java.util.Map;
55 /**
56 * <p>The implementation of the <i>UMAC</i> (Universal Message Authentication
57 * Code).</p>
59 * <p>The <i>UMAC</i> algorithms described are <i>parameterized</i>. This means
60 * that various low-level choices, like the endian convention and the underlying
61 * cryptographic primitive, have not been fixed. One must choose values for
62 * these parameters before the authentication tag generated by <i>UMAC</i> (for
63 * a given message, key, and nonce) becomes fully-defined. In this document
64 * we provide two collections of parameter settings, and have named the sets
65 * <i>UMAC16</i> and <i>UMAC32</i>. The parameter sets have been chosen based on
66 * experimentation and provide good performance on a wide variety of processors.
67 * <i>UMAC16</i> is designed to excel on processors which provide small-scale
68 * SIMD parallelism of the type found in Intel's MMX and Motorola's AltiVec
69 * instruction sets, while <i>UMAC32</i> is designed to do well on processors
70 * with good 32- and 64- bit support. <i>UMAC32</i> may take advantage of SIMD
71 * parallelism in future processors.</p>
73 * <p><i>UMAC</i> has been designed to allow implementations which accommodate
74 * <i>on-line</i> authentication. This means that pieces of the message may
75 * be presented to <i>UMAC</i> at different times (but in correct order) and an
76 * on-line implementation will be able to process the message correctly without
77 * the need to buffer more than a few dozen bytes of the message. For
78 * simplicity, the algorithms in this specification are presented as if the
79 * entire message being authenticated were available at once.</p>
81 * <p>To authenticate a message, <code>Msg</code>, one first applies the
82 * universal hash function, resulting in a string which is typically much
83 * shorter than the original message. The pseudorandom function is applied to a
84 * nonce, and the result is used in the manner of a Vernam cipher: the
85 * authentication tag is the xor of the output from the hash function and the
86 * output from the pseudorandom function. Thus, an authentication tag is
87 * generated as</p>
89 * <pre>
90 * AuthTag = f(Nonce) xor h(Msg)
91 * </pre>
93 * <p>Here <code>f</code> is the pseudorandom function shared between the sender
94 * and the receiver, and h is a universal hash function shared by the sender and
95 * the receiver. In <i>UMAC</i>, a shared key is used to key the pseudorandom
96 * function <code>f</code>, and then <code>f</code> is used for both tag
97 * generation and internally to generate all of the bits needed by the universal
98 * hash function.</p>
100 * <p>The universal hash function that we use is called <code>UHASH</code>. It
101 * combines several software-optimized algorithms into a multi-layered
102 * structure. The algorithm is moderately complex. Some of this complexity comes
103 * from extensive speed optimizations.</p>
105 * <p>For the pseudorandom function we use the block cipher of the <i>Advanced
106 * Encryption Standard</i> (AES).</p>
108 * <p>The UMAC32 parameters, considered in this implementation are:</p>
109 * <pre>
110 * UMAC32
111 * ------
112 * WORD-LEN 4
113 * UMAC-OUTPUT-LEN 8
114 * L1-KEY-LEN 1024
115 * UMAC-KEY-LEN 16
116 * ENDIAN-FAVORITE BIG *
117 * L1-OPERATIONS-SIGN UNSIGNED
118 * </pre>
120 * <p>Please note that this UMAC32 differs from the one described in the paper
121 * by the <i>ENDIAN-FAVORITE</i> value.</p>
123 * <p>References:</p>
125 * <ol>
126 * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
127 * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
128 * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
129 * </ol>
131 public class UMac32 extends BaseMac
134 // Constants and variables
135 // -------------------------------------------------------------------------
138 * Property name of the user-supplied <i>Nonce</i>. The value associated to
139 * this property name is taken to be a byte array.
141 public static final String NONCE_MATERIAL = "gnu.crypto.umac.nonce.material";
143 /** Known test vector. */
144 // private static final String TV1 = "3E5A0E09198B0F94";
145 // private static final String TV1 = "5FD764A6D3A9FD9D";
146 // private static final String TV1 = "48658DE1D9A70304";
147 private static final String TV1 = "455ED214A6909F20";
149 private static final BigInteger MAX_NONCE_ITERATIONS = BigInteger.ONE.shiftLeft(16 * 8);
151 // UMAC32 parameters
152 static final int OUTPUT_LEN = 8;
154 static final int L1_KEY_LEN = 1024;
156 static final int KEY_LEN = 16;
158 /** caches the result of the correctness test, once executed. */
159 private static Boolean valid;
161 private byte[] nonce;
163 private UHash32 uhash32;
165 private BigInteger nonceReuseCount;
167 /** The authentication key for this instance. */
168 private transient byte[] K;
170 // Constructor(s)
171 // -------------------------------------------------------------------------
173 /** Trivial 0-arguments constructor. */
174 public UMac32()
176 super("umac32");
180 * <p>Private constructor for cloning purposes.</p>
182 * @param that the instance to clone.
184 private UMac32(UMac32 that)
186 this();
188 if (that.K != null)
190 this.K = (byte[]) that.K.clone();
192 if (that.nonce != null)
194 this.nonce = (byte[]) that.nonce.clone();
196 if (that.uhash32 != null)
198 this.uhash32 = (UHash32) that.uhash32.clone();
200 this.nonceReuseCount = that.nonceReuseCount;
203 // Class methods
204 // -------------------------------------------------------------------------
206 // Instance methods
207 // -------------------------------------------------------------------------
209 // java.lang.Cloneable interface implementation ----------------------------
211 public Object clone()
213 return new UMac32(this);
216 // gnu.crypto.mac.IMac interface implementation ----------------------------
218 public int macSize()
220 return OUTPUT_LEN;
224 * <p>Initialising a <i>UMAC</i> instance consists of defining values for
225 * the following parameters:</p>
227 * <ol>
228 * <li>Key Material: as the value of the attribute entry keyed by
229 * {@link #MAC_KEY_MATERIAL}. The value is taken to be a byte array
230 * containing the user-specified key material. The length of this array,
231 * if/when defined SHOULD be exactly equal to {@link #KEY_LEN}.</li>
233 * <li>Nonce Material: as the value of the attribute entry keyed by
234 * {@link #NONCE_MATERIAL}. The value is taken to be a byte array
235 * containing the user-specified nonce material. The length of this array,
236 * if/when defined SHOULD be (a) greater than zero, and (b) less or equal
237 * to 16 (the size of the AES block).</li>
238 * </ol>
240 * <p>For convenience, this implementation accepts that not both parameters
241 * be always specified.</p>
243 * <ul>
244 * <li>If the <i>Key Material</i> is specified, but the <i>Nonce Material</i>
245 * is not, then this implementation, re-uses the previously set <i>Nonce
246 * Material</i> after (a) converting the bytes to an unsigned integer,
247 * (b) incrementing the number by one, and (c) converting it back to 16
248 * bytes.</li>
250 * <li>If the <i>Nonce Material</i> is specified, but the <i>Key Material</i>
251 * is not, then this implementation re-uses the previously set <i>Key
252 * Material</i>.</li>
253 * </ul>
255 * <p>This method throws an exception if no <i>Key Material</i> is specified
256 * in the input map, and there is no previously set/defined <i>Key Material</i>
257 * (from an earlier invocation of this method). If a <i>Key Material</i> can
258 * be used, but no <i>Nonce Material</i> is defined or previously set/defined,
259 * then a default value of all-zeroes shall be used.</p>
261 * @param attributes one or both of required parameters.
262 * @throws InvalidKeyException the key material specified is not of the
263 * correct length.
265 public void init(Map attributes) throws InvalidKeyException,
266 IllegalStateException
268 byte[] key = (byte[]) attributes.get(MAC_KEY_MATERIAL);
269 byte[] n = (byte[]) attributes.get(NONCE_MATERIAL);
271 boolean newKey = (key != null);
272 boolean newNonce = (n != null);
274 if (newKey)
276 if (key.length != KEY_LEN)
278 throw new InvalidKeyException("Key length: "
279 + String.valueOf(key.length));
281 K = key;
283 else
285 if (K == null)
287 throw new InvalidKeyException("Null Key");
291 if (newNonce)
293 if (n.length < 1 || n.length > 16)
295 throw new IllegalArgumentException("Invalid Nonce length: "
296 + String.valueOf(n.length));
299 if (n.length < 16)
300 { // pad with zeroes
301 byte[] newN = new byte[16];
302 System.arraycopy(n, 0, newN, 0, n.length);
303 nonce = newN;
305 else
307 nonce = n;
310 nonceReuseCount = BigInteger.ZERO;
312 else if (nonce == null)
313 { // use all-0 nonce if 1st time
314 nonce = new byte[16];
315 nonceReuseCount = BigInteger.ZERO;
317 else if (!newKey)
318 { // increment nonce if still below max count
319 nonceReuseCount = nonceReuseCount.add(BigInteger.ONE);
320 if (nonceReuseCount.compareTo(MAX_NONCE_ITERATIONS) >= 0)
322 // limit reached. we SHOULD have a key
323 throw new InvalidKeyException("Null Key and unusable old Nonce");
325 BigInteger N = new BigInteger(1, nonce);
326 N = N.add(BigInteger.ONE).mod(MAX_NONCE_ITERATIONS);
327 n = N.toByteArray();
328 if (n.length == 16)
330 nonce = n;
332 else if (n.length < 16)
334 nonce = new byte[16];
335 System.arraycopy(n, 0, nonce, 16 - n.length, n.length);
337 else
339 nonce = new byte[16];
340 System.arraycopy(n, n.length - 16, nonce, 0, 16);
343 else
344 { // do nothing, re-use old nonce value
345 nonceReuseCount = BigInteger.ZERO;
348 if (uhash32 == null)
350 uhash32 = new UHash32();
353 Map map = new HashMap();
354 map.put(MAC_KEY_MATERIAL, K);
355 uhash32.init(map);
358 public void update(byte b)
360 uhash32.update(b);
363 public void update(byte[] b, int offset, int len)
365 uhash32.update(b, offset, len);
368 public byte[] digest()
370 byte[] result = uhash32.digest();
371 byte[] pad = pdf(); // pdf(K, nonce);
372 for (int i = 0; i < OUTPUT_LEN; i++)
374 result[i] = (byte) (result[i] ^ pad[i]);
377 return result;
380 public void reset()
382 if (uhash32 != null)
384 uhash32.reset();
388 public boolean selfTest()
390 if (valid == null)
392 byte[] key;
395 key = "abcdefghijklmnop".getBytes("ASCII");
397 catch (UnsupportedEncodingException x)
399 throw new RuntimeException("ASCII not supported");
401 byte[] nonce = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
402 UMac32 mac = new UMac32();
403 Map attributes = new HashMap();
404 attributes.put(MAC_KEY_MATERIAL, key);
405 attributes.put(NONCE_MATERIAL, nonce);
408 mac.init(attributes);
410 catch (InvalidKeyException x)
412 x.printStackTrace(System.err);
413 return false;
416 byte[] data = new byte[128];
417 data[0] = (byte) 0x80;
419 mac.update(data, 0, 128);
420 byte[] result = mac.digest();
421 // System.out.println("UMAC test vector: "+Util.toString(result));
422 valid = Boolean.valueOf(TV1.equals(Util.toString(result)));
424 return valid.booleanValue();
427 // helper methods ----------------------------------------------------------
431 * @return byte array of length 8 (or OUTPUT_LEN) bytes.
433 private byte[] pdf()
435 // Make Nonce 16 bytes by prepending zeroes. done (see init())
437 // one AES invocation is enough for more than one PDF invocation
438 // number of index bits needed = 1
440 // Extract index bits and zero low bits of Nonce
441 BigInteger Nonce = new BigInteger(1, nonce);
442 int nlowbitsnum = Nonce.testBit(0) ? 1 : 0;
443 Nonce = Nonce.clearBit(0);
445 // Generate subkey, AES and extract indexed substring
446 IRandom kdf = new UMacGenerator();
447 Map map = new HashMap();
448 map.put(IBlockCipher.KEY_MATERIAL, K);
449 // map.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(128/8));
450 map.put(UMacGenerator.INDEX, new Integer(128));
451 // map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER);
452 kdf.init(map);
453 byte[] Kp = new byte[KEY_LEN];
456 kdf.nextBytes(Kp, 0, KEY_LEN);
458 catch (IllegalStateException x)
460 x.printStackTrace(System.err);
461 throw new RuntimeException(String.valueOf(x));
463 catch (LimitReachedException x)
465 x.printStackTrace(System.err);
466 throw new RuntimeException(String.valueOf(x));
468 IBlockCipher aes = CipherFactory.getInstance(Registry.AES_CIPHER);
469 map.put(IBlockCipher.KEY_MATERIAL, Kp);
472 aes.init(map);
474 catch (InvalidKeyException x)
476 x.printStackTrace(System.err);
477 throw new RuntimeException(String.valueOf(x));
479 catch (IllegalStateException x)
481 x.printStackTrace(System.err);
482 throw new RuntimeException(String.valueOf(x));
484 byte[] T = new byte[16];
485 aes.encryptBlock(nonce, 0, T, 0);
486 byte[] result = new byte[OUTPUT_LEN];
487 System.arraycopy(T, nlowbitsnum, result, 0, OUTPUT_LEN);
489 return result;