UMacGenerator.java 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /* UMacGenerator.java --
  2. Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
  3. This file is a part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or (at
  7. your option) any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  15. USA
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package gnu.javax.crypto.prng;
  32. import gnu.java.security.Registry;
  33. import gnu.java.security.prng.BasePRNG;
  34. import gnu.java.security.prng.LimitReachedException;
  35. import gnu.javax.crypto.cipher.CipherFactory;
  36. import gnu.javax.crypto.cipher.IBlockCipher;
  37. import java.util.HashMap;
  38. import java.util.Iterator;
  39. import java.util.Map;
  40. import java.security.InvalidKeyException;
  41. /**
  42. * <i>KDF</i>s (Key Derivation Functions) are used to stretch user-supplied key
  43. * material to specific size(s) required by high level cryptographic primitives.
  44. * Described in the <A
  45. * HREF="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">UMAC</A>
  46. * paper, this function basically operates an underlying <em>symmetric key block
  47. * cipher</em> instance in output feedback mode (OFB), as a <b>strong</b>
  48. * pseudo-random number generator.
  49. * <p>
  50. * <code>UMacGenerator</code> requires an <em>index</em> parameter
  51. * (initialisation parameter <code>gnu.crypto.prng.umac.kdf.index</code> taken
  52. * to be an instance of {@link Integer} with a value between <code>0</code> and
  53. * <code>255</code>). Using the same key, but different indices, generates
  54. * different pseudorandom outputs.
  55. * <p>
  56. * This implementation generalises the definition of the
  57. * <code>UmacGenerator</code> algorithm to allow for other than the AES
  58. * symetric key block cipher algorithm (initialisation parameter
  59. * <code>gnu.crypto.prng.umac.cipher.name</code> taken to be an instance of
  60. * {@link String}). If such a parameter is not defined/included in the
  61. * initialisation <code>Map</code>, then the "Rijndael" algorithm is used.
  62. * Furthermore, if the initialisation parameter
  63. * <code>gnu.crypto.cipher.block.size</code> (taken to be a instance of
  64. * {@link Integer}) is missing or undefined in the initialisation
  65. * <code>Map</code>, then the cipher's <em>default</em> block size is used.
  66. * <p>
  67. * <b>NOTE</b>: Rijndael is used as the default symmetric key block cipher
  68. * algorithm because, with its default block and key sizes, it is the AES. Yet
  69. * being Rijndael, the algorithm offers more versatile block and key sizes which
  70. * may prove to be useful for generating "longer" key streams.
  71. * <p>
  72. * References:
  73. * <ol>
  74. * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
  75. * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
  76. * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
  77. * </ol>
  78. */
  79. public class UMacGenerator
  80. extends BasePRNG
  81. implements Cloneable
  82. {
  83. /**
  84. * Property name of the KDF <code>index</code> value to use in this
  85. * instance. The value is taken to be an {@link Integer} less than
  86. * <code>256</code>.
  87. */
  88. public static final String INDEX = "gnu.crypto.prng.umac.index";
  89. /** The name of the underlying symmetric key block cipher algorithm. */
  90. public static final String CIPHER = "gnu.crypto.prng.umac.cipher.name";
  91. /** The generator's underlying block cipher. */
  92. private IBlockCipher cipher;
  93. /** Trivial 0-arguments constructor. */
  94. public UMacGenerator()
  95. {
  96. super(Registry.UMAC_PRNG);
  97. }
  98. public void setup(Map attributes)
  99. {
  100. boolean newCipher = true;
  101. String cipherName = (String) attributes.get(CIPHER);
  102. if (cipherName == null)
  103. if (cipher == null) // happy birthday
  104. cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER);
  105. else // we already have one. use it as is
  106. newCipher = false;
  107. else
  108. cipher = CipherFactory.getInstance(cipherName);
  109. // find out what block size we should use it in
  110. int cipherBlockSize = 0;
  111. Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE);
  112. if (bs != null)
  113. cipherBlockSize = bs.intValue();
  114. else
  115. {
  116. if (newCipher) // assume we'll use its default block size
  117. cipherBlockSize = cipher.defaultBlockSize();
  118. // else use as is
  119. }
  120. // get the key material
  121. byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL);
  122. if (key == null)
  123. throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL);
  124. int keyLength = key.length;
  125. // ensure that keyLength is valid for the chosen underlying cipher
  126. boolean ok = false;
  127. for (Iterator it = cipher.keySizes(); it.hasNext();)
  128. {
  129. ok = (keyLength == ((Integer) it.next()).intValue());
  130. if (ok)
  131. break;
  132. }
  133. if (! ok)
  134. throw new IllegalArgumentException("key length");
  135. // ensure that remaining params make sense
  136. int index = -1;
  137. Integer i = (Integer) attributes.get(INDEX);
  138. if (i != null)
  139. {
  140. index = i.intValue();
  141. if (index < 0 || index > 255)
  142. throw new IllegalArgumentException(INDEX);
  143. }
  144. // now initialise the underlying cipher
  145. Map map = new HashMap();
  146. if (cipherBlockSize != 0) // only needed if new or changed
  147. map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize));
  148. map.put(IBlockCipher.KEY_MATERIAL, key);
  149. try
  150. {
  151. cipher.init(map);
  152. }
  153. catch (InvalidKeyException x)
  154. {
  155. throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL);
  156. }
  157. buffer = new byte[cipher.currentBlockSize()];
  158. buffer[cipher.currentBlockSize() - 1] = (byte) index;
  159. try
  160. {
  161. fillBlock();
  162. }
  163. catch (LimitReachedException impossible)
  164. {
  165. }
  166. }
  167. public void fillBlock() throws LimitReachedException
  168. {
  169. cipher.encryptBlock(buffer, 0, buffer, 0);
  170. }
  171. }