Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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 }