Source code: gnu/javax/crypto/prng/UMacGenerator.java
1 /* UMacGenerator.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.prng;
40
41 import gnu.java.security.Registry;
42 import gnu.java.security.prng.BasePRNG;
43 import gnu.java.security.prng.LimitReachedException;
44 import gnu.javax.crypto.cipher.CipherFactory;
45 import gnu.javax.crypto.cipher.IBlockCipher;
46
47 import java.util.HashMap;
48 import java.util.Iterator;
49 import java.util.Map;
50 import java.security.InvalidKeyException;
51
52 /**
53 * <p><i>KDF</i>s (Key Derivation Functions) are used to stretch user-supplied
54 * key material to specific size(s) required by high level cryptographic
55 * primitives. Described in the <A
56 * HREF="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">UMAC</A>
57 * paper, this function basically operates an underlying <em>symmetric key block
58 * cipher</em> instance in output feedback mode (OFB), as a <b>strong</b>
59 * pseudo-random number generator.</p>
60 *
61 * <p><code>UMacGenerator</code> requires an <em>index</em> parameter
62 * (initialisation parameter <code>gnu.crypto.prng.umac.kdf.index</code> taken
63 * to be an instance of {@link java.lang.Integer} with a value between
64 * <code>0</code> and <code>255</code>). Using the same key, but different
65 * indices, generates different pseudorandom outputs.</p>
66 *
67 * <p>This implementation generalises the definition of the
68 * <code>UmacGenerator</code> algorithm to allow for other than the AES symetric
69 * key block cipher algorithm (initialisation parameter
70 * <code>gnu.crypto.prng.umac.cipher.name</code> taken to be an instance of
71 * {@link java.lang.String}). If such a parameter is not defined/included in the
72 * initialisation <code>Map</code>, then the "Rijndael" algorithm is used.
73 * Furthermore, if the initialisation parameter
74 * <code>gnu.crypto.cipher.block.size</code> (taken to be a instance of {@link
75 * java.lang.Integer}) is missing or undefined in the initialisation <code>Map
76 * </code>, then the cipher's <em>default</em> block size is used.</p>
77 *
78 * <p><b>NOTE</b>: Rijndael is used as the default symmetric key block cipher
79 * algorithm because, with its default block and key sizes, it is the AES. Yet
80 * being Rijndael, the algorithm offers more versatile block and key sizes which
81 * may prove to be useful for generating "longer" key streams.</p>
82 *
83 * <p>References:</p>
84 *
85 * <ol>
86 * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
87 * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
88 * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
89 * </ol>
90 */
91 public class UMacGenerator extends BasePRNG implements Cloneable
92 {
93
94 // Constants and variables
95 // -------------------------------------------------------------------------
96
97 /**
98 * <p>Property name of the KDF <code>index</code> value to use in this
99 * instance. The value is taken to be an {@link Integer} less than
100 * <code>256</code>.</p>
101 */
102 public static final String INDEX = "gnu.crypto.prng.umac.index";
103
104 /** The name of the underlying symmetric key block cipher algorithm. */
105 public static final String CIPHER = "gnu.crypto.prng.umac.cipher.name";
106
107 /** The generator's underlying block cipher. */
108 private IBlockCipher cipher;
109
110 // Constructor(s)
111 // -------------------------------------------------------------------------
112
113 /** Trivial 0-arguments constructor. */
114 public UMacGenerator()
115 {
116 super(Registry.UMAC_PRNG);
117 }
118
119 // Class methods
120 // -------------------------------------------------------------------------
121
122 // Instance methods
123 // -------------------------------------------------------------------------
124
125 // Implementation of abstract methods in BasePRNG --------------------------
126
127 public void setup(Map attributes)
128 {
129 boolean newCipher = true;
130 String cipherName = (String) attributes.get(CIPHER);
131 if (cipherName == null)
132 {
133 if (cipher == null)
134 { // happy birthday
135 cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER);
136 }
137 else
138 { // we already have one. use it as is
139 newCipher = false;
140 }
141 }
142 else
143 {
144 cipher = CipherFactory.getInstance(cipherName);
145 }
146
147 // find out what block size we should use it in
148 int cipherBlockSize = 0;
149 Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE);
150 if (bs != null)
151 {
152 cipherBlockSize = bs.intValue();
153 }
154 else
155 {
156 if (newCipher)
157 { // assume we'll use its default block size
158 cipherBlockSize = cipher.defaultBlockSize();
159 } // else use as is
160 }
161
162 // get the key material
163 byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL);
164 if (key == null)
165 {
166 throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL);
167 }
168
169 int keyLength = key.length;
170 // ensure that keyLength is valid for the chosen underlying cipher
171 boolean ok = false;
172 for (Iterator it = cipher.keySizes(); it.hasNext();)
173 {
174 ok = (keyLength == ((Integer) it.next()).intValue());
175 if (ok)
176 {
177 break;
178 }
179 }
180 if (!ok)
181 {
182 throw new IllegalArgumentException("key length");
183 }
184
185 // ensure that remaining params make sense
186 int index = -1;
187 Integer i = (Integer) attributes.get(INDEX);
188 if (i != null)
189 {
190 index = i.intValue();
191 if (index < 0 || index > 255)
192 {
193 throw new IllegalArgumentException(INDEX);
194 }
195 }
196
197 // now initialise the underlying cipher
198 Map map = new HashMap();
199 if (cipherBlockSize != 0)
200 { // only needed if new or changed
201 map.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(cipherBlockSize));
202 }
203 map.put(IBlockCipher.KEY_MATERIAL, key);
204 try
205 {
206 cipher.init(map);
207 }
208 catch (InvalidKeyException x)
209 {
210 throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL);
211 }
212
213 buffer = new byte[cipher.currentBlockSize()];
214 buffer[cipher.currentBlockSize() - 1] = (byte) index;
215 try
216 {
217 fillBlock();
218 }
219 catch (LimitReachedException impossible)
220 {
221 }
222 }
223
224 public void fillBlock() throws LimitReachedException
225 {
226 cipher.encryptBlock(buffer, 0, buffer, 0);
227 }
228 }