Frames | No Frames |
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. */ 106: public UMacGenerator() 107: { 108: super(Registry.UMAC_PRNG); 109: } 110: 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: 182: public void fillBlock() throws LimitReachedException 183: { 184: cipher.encryptBlock(buffer, 0, buffer, 0); 185: } 186: }