TMMH16.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /* TMMH16.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.mac;
  32. import gnu.java.security.Registry;
  33. import gnu.java.security.prng.IRandom;
  34. import gnu.java.security.prng.LimitReachedException;
  35. import java.security.InvalidKeyException;
  36. import java.util.Map;
  37. /**
  38. * <i>TMMH</i> is a <i>universal</i> hash function suitable for message
  39. * authentication in the Wegman-Carter paradigm, as in the Stream Cipher
  40. * Security Transform. It is simple, quick, and especially appropriate for
  41. * Digital Signal Processors and other processors with a fast multiply
  42. * operation, though a straightforward implementation requires storage equal in
  43. * length to the largest message to be hashed.
  44. * <p>
  45. * <i>TMMH</i> is a simple hash function which maps a key and a message to a
  46. * hash value. There are two versions of TMMH: TMMH/16 and TMMH/32. <i>TMMH</i>
  47. * can be used as a message authentication code, as described in Section 5 (see
  48. * References).
  49. * <p>
  50. * The key, message, and hash value are all octet strings, and the lengths of
  51. * these quantities are denoted as <code>KEY_LENGTH</code>,
  52. * <code>MESSAGE_LENGTH</code>, and <code>TAG_LENGTH</code>, respectively.
  53. * The values of <code>KEY_LENGTH</code> and <code>TAG_LENGTH</code>
  54. * <bold>MUST</bold> be fixed for any particular fixed value of the key, and
  55. * must obey the alignment restrictions described below.
  56. * <p>
  57. * The parameter <code>MAX_HASH_LENGTH</code>, which denotes the maximum
  58. * value which <code>MESSAGE_LENGTH</code> may take, is equal to
  59. * <code>KEY_LENGTH - TAG_LENGTH</code>.
  60. * <p>
  61. * References:
  62. * <ol>
  63. * <li><a
  64. * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-tmmh-01.txt"> The
  65. * Truncated Multi-Modular Hash Function (TMMH)</a>, David A. McGrew.</li>
  66. * </ol>
  67. */
  68. public class TMMH16
  69. extends BaseMac
  70. implements Cloneable
  71. {
  72. public static final String TAG_LENGTH = "gnu.crypto.mac.tmmh.tag.length";
  73. public static final String KEYSTREAM = "gnu.crypto.mac.tmmh.keystream";
  74. public static final String PREFIX = "gnu.crypto.mac.tmmh.prefix";
  75. private static final int P = (1 << 16) + 1; // the TMMH/16 prime
  76. /** caches the result of the correctness test, once executed. */
  77. private static Boolean valid;
  78. private int tagWords = 0; // the tagLength expressed in words
  79. private IRandom keystream = null; // the keystream generator
  80. private byte[] prefix; // mask to use when operating as an authentication f.
  81. private long keyWords; // key words counter
  82. private long msgLength; // in bytes
  83. private long msgWords; // should be = msgLength * WORD_LENGTH
  84. private int[] context; // the tmmh running context; length == TAG_WORDS
  85. private int[] K0; // the first TAG_WORDS words of the keystream
  86. private int[] Ki; // the sliding TAG_WORDS words of the keystream
  87. private int Mi; // current message word being constructed
  88. /** Trivial 0-arguments constructor. */
  89. public TMMH16()
  90. {
  91. super(Registry.TMMH16);
  92. }
  93. public int macSize()
  94. {
  95. return tagWords * 2;
  96. }
  97. public void init(Map attributes) throws InvalidKeyException,
  98. IllegalStateException
  99. {
  100. int wantTagLength = 0;
  101. Integer tagLength = (Integer) attributes.get(TAG_LENGTH); // get tag length
  102. if (tagLength == null)
  103. {
  104. if (tagWords == 0) // was never set
  105. throw new IllegalArgumentException(TAG_LENGTH);
  106. // else re-use
  107. }
  108. else // check if positive and is divisible by WORD_LENGTH
  109. {
  110. wantTagLength = tagLength.intValue();
  111. if (wantTagLength < 2 || (wantTagLength % 2 != 0))
  112. throw new IllegalArgumentException(TAG_LENGTH);
  113. else if (wantTagLength > (512 / 8)) // 512-bits is our maximum
  114. throw new IllegalArgumentException(TAG_LENGTH);
  115. tagWords = wantTagLength / 2; // init local vars
  116. K0 = new int[tagWords];
  117. Ki = new int[tagWords];
  118. context = new int[tagWords];
  119. }
  120. prefix = (byte[]) attributes.get(PREFIX);
  121. if (prefix == null) // default to all-zeroes
  122. prefix = new byte[tagWords * 2];
  123. else // ensure it's as long as it should
  124. {
  125. if (prefix.length != tagWords * 2)
  126. throw new IllegalArgumentException(PREFIX);
  127. }
  128. IRandom prng = (IRandom) attributes.get(KEYSTREAM); // get keystream
  129. if (prng == null)
  130. {
  131. if (keystream == null)
  132. throw new IllegalArgumentException(KEYSTREAM);
  133. // else reuse
  134. }
  135. else
  136. keystream = prng;
  137. reset(); // reset context variables
  138. for (int i = 0; i < tagWords; i++) // init starting key words
  139. Ki[i] = K0[i] = getNextKeyWord(keystream);
  140. }
  141. // The words of the key are denoted as K[1], K[2], ..., K[KEY_WORDS], and the
  142. // words of the message (after zero padding, if needed) are denoted as M[1],
  143. // M[2], ..., M[MSG_WORDS], where MSG_WORDS is the smallest number such that
  144. // 2 * MSG_WORDS is at least MESSAGE_LENGTH, and KEY_WORDS is KEY_LENGTH / 2.
  145. //
  146. // If MESSAGE_LENGTH is greater than MAX_HASH_LENGTH, then the value of
  147. // TMMH/16 is undefined. Implementations MUST indicate an error if asked to
  148. // hash a message with such a length. Otherwise, the hash value is defined
  149. // to be the length TAG_WORDS sequence of words in which the j-th word in the
  150. // sequence is defined as
  151. //
  152. // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2]
  153. // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16
  154. //
  155. // where j ranges from 1 to TAG_WORDS.
  156. public void update(byte b)
  157. {
  158. this.update(b, keystream);
  159. }
  160. public void update(byte[] b, int offset, int len)
  161. {
  162. for (int i = 0; i < len; i++)
  163. this.update(b[offset + i], keystream);
  164. }
  165. // For TMMH/16, KEY_LENGTH and TAG_LENGTH MUST be a multiple of two. The key,
  166. // message, and hash value are treated as a sequence of unsigned sixteen bit
  167. // integers in network byte order. (In this section, we call such an integer
  168. // a word.) If MESSAGE_LENGTH is odd, then a zero byte is appended to the
  169. // message to align it on a word boundary, though this process does not
  170. // change the value of MESSAGE_LENGTH.
  171. //
  172. // ... Otherwise, the hash value is defined to be the length TAG_WORDS
  173. // sequence of words in which the j-th word in the sequence is defined as
  174. //
  175. // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2]
  176. // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16
  177. //
  178. // where j ranges from 1 to TAG_WORDS.
  179. //
  180. // Here, TAG_WORDS is equal to TAG_LENGTH / 2, and p is equal to 2^16 + 1.
  181. // The symbol * denotes multiplication and the symbol +32 denotes addition
  182. // modulo 2^32.
  183. public byte[] digest()
  184. {
  185. return this.digest(keystream);
  186. }
  187. public void reset()
  188. {
  189. msgLength = msgWords = keyWords = 0L;
  190. Mi = 0;
  191. for (int i = 0; i < tagWords; i++)
  192. context[i] = 0;
  193. }
  194. public boolean selfTest()
  195. {
  196. if (valid == null)
  197. {
  198. // TODO: compute and test equality with one known vector
  199. valid = Boolean.TRUE;
  200. }
  201. return valid.booleanValue();
  202. }
  203. public Object clone() throws CloneNotSupportedException
  204. {
  205. TMMH16 result = (TMMH16) super.clone();
  206. if (this.keystream != null)
  207. result.keystream = (IRandom) this.keystream.clone();
  208. if (this.prefix != null)
  209. result.prefix = (byte[]) this.prefix.clone();
  210. if (this.context != null)
  211. result.context = (int[]) this.context.clone();
  212. if (this.K0 != null)
  213. result.K0 = (int[]) this.K0.clone();
  214. if (this.Ki != null)
  215. result.Ki = (int[]) this.Ki.clone();
  216. return result;
  217. }
  218. /**
  219. * Similar to the same method with one argument, but uses the designated
  220. * random number generator to compute needed keying material.
  221. *
  222. * @param b the byte to process.
  223. * @param prng the source of randomness to use.
  224. */
  225. public void update(byte b, IRandom prng)
  226. {
  227. Mi <<= 8; // update message buffer
  228. Mi |= b & 0xFF;
  229. msgLength++; // update message length (bytes)
  230. if (msgLength % 2 == 0) // got a full word
  231. {
  232. msgWords++; // update message words counter
  233. System.arraycopy(Ki, 1, Ki, 0, tagWords - 1); // 1. shift Ki up by 1
  234. Ki[tagWords - 1] = getNextKeyWord(prng); // 2. fill last box of Ki
  235. long t; // temp var to allow working in modulo 2^32
  236. for (int i = 0; i < tagWords; i++) // 3. update context
  237. {
  238. t = context[i] & 0xFFFFFFFFL;
  239. t += Ki[i] * Mi;
  240. context[i] = (int) t;
  241. }
  242. Mi = 0; // reset message buffer
  243. }
  244. }
  245. /**
  246. * Similar to the same method with three arguments, but uses the designated
  247. * random number generator to compute needed keying material.
  248. *
  249. * @param b the byte array to process.
  250. * @param offset the starting offset in <code>b</code> to start considering
  251. * the bytes to process.
  252. * @param len the number of bytes in <code>b</code> starting from
  253. * <code>offset</code> to process.
  254. * @param prng the source of randomness to use.
  255. */
  256. public void update(byte[] b, int offset, int len, IRandom prng)
  257. {
  258. for (int i = 0; i < len; i++)
  259. this.update(b[offset + i], prng);
  260. }
  261. /**
  262. * Similar to the same method with no arguments, but uses the designated
  263. * random number generator to compute needed keying material.
  264. *
  265. * @param prng the source of randomness to use.
  266. * @return the final result of the algorithm.
  267. */
  268. public byte[] digest(IRandom prng)
  269. {
  270. doFinalRound(prng);
  271. byte[] result = new byte[tagWords * 2];
  272. for (int i = 0, j = 0; i < tagWords; i++)
  273. {
  274. result[j] = (byte)((context[i] >>> 8) ^ prefix[j]);
  275. j++;
  276. result[j] = (byte)(context[i] ^ prefix[j]);
  277. j++;
  278. }
  279. reset();
  280. return result;
  281. }
  282. private int getNextKeyWord(IRandom prng)
  283. {
  284. int result = 0;
  285. try
  286. {
  287. result = (prng.nextByte() & 0xFF) << 8 | (prng.nextByte() & 0xFF);
  288. }
  289. catch (LimitReachedException x)
  290. {
  291. throw new RuntimeException(String.valueOf(x));
  292. }
  293. keyWords++; // update key words counter
  294. return result;
  295. }
  296. private void doFinalRound(IRandom prng)
  297. {
  298. long limit = msgLength; // formula works on real message length
  299. while (msgLength % 2 != 0)
  300. update((byte) 0x00, prng);
  301. long t;
  302. for (int i = 0; i < tagWords; i++)
  303. {
  304. t = context[i] & 0xFFFFFFFFL;
  305. t += K0[i] * limit;
  306. t %= P;
  307. context[i] = (int) t;
  308. }
  309. }
  310. }