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 * <i>KDF</i>s (Key Derivation Functions) are used to stretch user-supplied key 54 * material to specific size(s) required by high level cryptographic primitives. 55 * 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. 60 * <p> 61 * <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 Integer} with a value between <code>0</code> and 64 * <code>255</code>). Using the same key, but different indices, generates 65 * different pseudorandom outputs. 66 * <p> 67 * This implementation generalises the definition of the 68 * <code>UmacGenerator</code> algorithm to allow for other than the AES 69 * symetric key block cipher algorithm (initialisation parameter 70 * <code>gnu.crypto.prng.umac.cipher.name</code> taken to be an instance of 71 * {@link 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 75 * {@link Integer}) is missing or undefined in the initialisation 76 * <code>Map</code>, then the cipher's <em>default</em> block size is used. 77 * <p> 78 * <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. 82 * <p> 83 * References: 84 * <ol> 85 * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt"> 86 * UMAC</a>: Message Authentication Code using Universal Hashing.<br> 87 * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li> 88 * </ol> 89 */ 90 public class UMacGenerator 91 extends BasePRNG 92 implements Cloneable 93 { 94 /** 95 * Property name of the KDF <code>index</code> value to use in this 96 * instance. The value is taken to be an {@link Integer} less than 97 * <code>256</code>. 98 */ 99 public static final String INDEX = "gnu.crypto.prng.umac.index"; 100 /** The name of the underlying symmetric key block cipher algorithm. */ 101 public static final String CIPHER = "gnu.crypto.prng.umac.cipher.name"; 102 /** The generator's underlying block cipher. */ 103 private IBlockCipher cipher; 104 105 /** Trivial 0-arguments constructor. */ UMacGenerator()106 public UMacGenerator() 107 { 108 super(Registry.UMAC_PRNG); 109 } 110 setup(Map attributes)111 public void setup(Map attributes) 112 { 113 boolean newCipher = true; 114 String cipherName = (String) attributes.get(CIPHER); 115 if (cipherName == null) 116 if (cipher == null) // happy birthday 117 cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER); 118 else // we already have one. use it as is 119 newCipher = false; 120 else 121 cipher = CipherFactory.getInstance(cipherName); 122 // find out what block size we should use it in 123 int cipherBlockSize = 0; 124 Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE); 125 if (bs != null) 126 cipherBlockSize = bs.intValue(); 127 else 128 { 129 if (newCipher) // assume we'll use its default block size 130 cipherBlockSize = cipher.defaultBlockSize(); 131 // else use as is 132 } 133 // get the key material 134 byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL); 135 if (key == null) 136 throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); 137 138 int keyLength = key.length; 139 // ensure that keyLength is valid for the chosen underlying cipher 140 boolean ok = false; 141 for (Iterator it = cipher.keySizes(); it.hasNext();) 142 { 143 ok = (keyLength == ((Integer) it.next()).intValue()); 144 if (ok) 145 break; 146 } 147 if (! ok) 148 throw new IllegalArgumentException("key length"); 149 // ensure that remaining params make sense 150 int index = -1; 151 Integer i = (Integer) attributes.get(INDEX); 152 if (i != null) 153 { 154 index = i.intValue(); 155 if (index < 0 || index > 255) 156 throw new IllegalArgumentException(INDEX); 157 } 158 // now initialise the underlying cipher 159 Map map = new HashMap(); 160 if (cipherBlockSize != 0) // only needed if new or changed 161 map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize)); 162 map.put(IBlockCipher.KEY_MATERIAL, key); 163 try 164 { 165 cipher.init(map); 166 } 167 catch (InvalidKeyException x) 168 { 169 throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); 170 } 171 buffer = new byte[cipher.currentBlockSize()]; 172 buffer[cipher.currentBlockSize() - 1] = (byte) index; 173 try 174 { 175 fillBlock(); 176 } 177 catch (LimitReachedException impossible) 178 { 179 } 180 } 181 fillBlock()182 public void fillBlock() throws LimitReachedException 183 { 184 cipher.encryptBlock(buffer, 0, buffer, 0); 185 } 186 } 187