Source for gnu.javax.crypto.prng.UMacGenerator

   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: }