UMac32.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /* UMac32.java --
  2. Copyright (C) 2001, 2002, 2003, 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 gnu.java.security.util.Util;
  36. import gnu.javax.crypto.cipher.CipherFactory;
  37. import gnu.javax.crypto.cipher.IBlockCipher;
  38. import gnu.javax.crypto.prng.UMacGenerator;
  39. import java.io.UnsupportedEncodingException;
  40. import java.math.BigInteger;
  41. import java.security.InvalidKeyException;
  42. import java.util.HashMap;
  43. import java.util.Map;
  44. /**
  45. * The implementation of the <i>UMAC</i> (Universal Message Authentication
  46. * Code).
  47. * <p>
  48. * The <i>UMAC</i> algorithms described are <i>parameterized</i>. This means
  49. * that various low-level choices, like the endian convention and the underlying
  50. * cryptographic primitive, have not been fixed. One must choose values for
  51. * these parameters before the authentication tag generated by <i>UMAC</i> (for
  52. * a given message, key, and nonce) becomes fully-defined. In this document we
  53. * provide two collections of parameter settings, and have named the sets
  54. * <i>UMAC16</i> and <i>UMAC32</i>. The parameter sets have been chosen based
  55. * on experimentation and provide good performance on a wide variety of
  56. * processors. <i>UMAC16</i> is designed to excel on processors which provide
  57. * small-scale SIMD parallelism of the type found in Intel's MMX and Motorola's
  58. * AltiVec instruction sets, while <i>UMAC32</i> is designed to do well on
  59. * processors with good 32- and 64- bit support. <i>UMAC32</i> may take
  60. * advantage of SIMD parallelism in future processors.
  61. * <p>
  62. * <i>UMAC</i> has been designed to allow implementations which accommodate
  63. * <i>on-line</i> authentication. This means that pieces of the message may be
  64. * presented to <i>UMAC</i> at different times (but in correct order) and an
  65. * on-line implementation will be able to process the message correctly without
  66. * the need to buffer more than a few dozen bytes of the message. For
  67. * simplicity, the algorithms in this specification are presented as if the
  68. * entire message being authenticated were available at once.
  69. * <p>
  70. * To authenticate a message, <code>Msg</code>, one first applies the
  71. * universal hash function, resulting in a string which is typically much
  72. * shorter than the original message. The pseudorandom function is applied to a
  73. * nonce, and the result is used in the manner of a Vernam cipher: the
  74. * authentication tag is the xor of the output from the hash function and the
  75. * output from the pseudorandom function. Thus, an authentication tag is
  76. * generated as
  77. * <pre>
  78. * AuthTag = f(Nonce) xor h(Msg)
  79. * </pre>
  80. * <p>
  81. * Here <code>f</code> is the pseudorandom function shared between the sender
  82. * and the receiver, and h is a universal hash function shared by the sender and
  83. * the receiver. In <i>UMAC</i>, a shared key is used to key the pseudorandom
  84. * function <code>f</code>, and then <code>f</code> is used for both tag
  85. * generation and internally to generate all of the bits needed by the universal
  86. * hash function.
  87. * <p>
  88. * The universal hash function that we use is called <code>UHASH</code>. It
  89. * combines several software-optimized algorithms into a multi-layered
  90. * structure. The algorithm is moderately complex. Some of this complexity comes
  91. * from extensive speed optimizations.
  92. * <p>
  93. * For the pseudorandom function we use the block cipher of the <i>Advanced
  94. * Encryption Standard</i> (AES).
  95. * <p>
  96. * The UMAC32 parameters, considered in this implementation are:
  97. * <pre>
  98. * UMAC32
  99. * ------
  100. * WORD-LEN 4
  101. * UMAC-OUTPUT-LEN 8
  102. * L1-KEY-LEN 1024
  103. * UMAC-KEY-LEN 16
  104. * ENDIAN-FAVORITE BIG *
  105. * L1-OPERATIONS-SIGN UNSIGNED
  106. * </pre>
  107. * <p>
  108. * Please note that this UMAC32 differs from the one described in the paper by
  109. * the <i>ENDIAN-FAVORITE</i> value.
  110. * <p>
  111. * References:
  112. * <ol>
  113. * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
  114. * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
  115. * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
  116. * </ol>
  117. */
  118. public class UMac32
  119. extends BaseMac
  120. {
  121. /**
  122. * Property name of the user-supplied <i>Nonce</i>. The value associated to
  123. * this property name is taken to be a byte array.
  124. */
  125. public static final String NONCE_MATERIAL = "gnu.crypto.umac.nonce.material";
  126. /** Known test vector. */
  127. // private static final String TV1 = "3E5A0E09198B0F94";
  128. // private static final String TV1 = "5FD764A6D3A9FD9D";
  129. // private static final String TV1 = "48658DE1D9A70304";
  130. private static final String TV1 = "455ED214A6909F20";
  131. private static final BigInteger MAX_NONCE_ITERATIONS = BigInteger.ONE.shiftLeft(16 * 8);
  132. // UMAC32 parameters
  133. static final int OUTPUT_LEN = 8;
  134. static final int L1_KEY_LEN = 1024;
  135. static final int KEY_LEN = 16;
  136. /** caches the result of the correctness test, once executed. */
  137. private static Boolean valid;
  138. private byte[] nonce;
  139. private UHash32 uhash32;
  140. private BigInteger nonceReuseCount;
  141. /** The authentication key for this instance. */
  142. private transient byte[] K;
  143. /** Trivial 0-arguments constructor. */
  144. public UMac32()
  145. {
  146. super("umac32");
  147. }
  148. /**
  149. * Private constructor for cloning purposes.
  150. *
  151. * @param that the instance to clone.
  152. */
  153. private UMac32(UMac32 that)
  154. {
  155. this();
  156. if (that.K != null)
  157. this.K = (byte[]) that.K.clone();
  158. if (that.nonce != null)
  159. this.nonce = (byte[]) that.nonce.clone();
  160. if (that.uhash32 != null)
  161. this.uhash32 = (UHash32) that.uhash32.clone();
  162. this.nonceReuseCount = that.nonceReuseCount;
  163. }
  164. public Object clone()
  165. {
  166. return new UMac32(this);
  167. }
  168. public int macSize()
  169. {
  170. return OUTPUT_LEN;
  171. }
  172. /**
  173. * Initialising a <i>UMAC</i> instance consists of defining values for the
  174. * following parameters:
  175. * <ol>
  176. * <li>Key Material: as the value of the attribute entry keyed by
  177. * {@link #MAC_KEY_MATERIAL}. The value is taken to be a byte array
  178. * containing the user-specified key material. The length of this array,
  179. * if/when defined SHOULD be exactly equal to {@link #KEY_LEN}.</li>
  180. * <li>Nonce Material: as the value of the attribute entry keyed by
  181. * {@link #NONCE_MATERIAL}. The value is taken to be a byte array containing
  182. * the user-specified nonce material. The length of this array, if/when
  183. * defined SHOULD be (a) greater than zero, and (b) less or equal to 16 (the
  184. * size of the AES block).</li>
  185. * </ol>
  186. * <p>
  187. * For convenience, this implementation accepts that not both parameters be
  188. * always specified.
  189. * <ul>
  190. * <li>If the <i>Key Material</i> is specified, but the <i>Nonce Material</i>
  191. * is not, then this implementation, re-uses the previously set <i>Nonce
  192. * Material</i> after (a) converting the bytes to an unsigned integer, (b)
  193. * incrementing the number by one, and (c) converting it back to 16 bytes.</li>
  194. * <li>If the <i>Nonce Material</i> is specified, but the <i>Key Material</i>
  195. * is not, then this implementation re-uses the previously set <i>Key Material</i>.
  196. * </li>
  197. * </ul>
  198. * <p>
  199. * This method throws an exception if no <i>Key Material</i> is specified in
  200. * the input map, and there is no previously set/defined <i>Key Material</i>
  201. * (from an earlier invocation of this method). If a <i>Key Material</i> can
  202. * be used, but no <i>Nonce Material</i> is defined or previously
  203. * set/defined, then a default value of all-zeroes shall be used.
  204. *
  205. * @param attributes one or both of required parameters.
  206. * @throws InvalidKeyException the key material specified is not of the
  207. * correct length.
  208. */
  209. public void init(Map attributes) throws InvalidKeyException,
  210. IllegalStateException
  211. {
  212. byte[] key = (byte[]) attributes.get(MAC_KEY_MATERIAL);
  213. byte[] n = (byte[]) attributes.get(NONCE_MATERIAL);
  214. boolean newKey = (key != null);
  215. boolean newNonce = (n != null);
  216. if (newKey)
  217. {
  218. if (key.length != KEY_LEN)
  219. throw new InvalidKeyException("Key length: "
  220. + String.valueOf(key.length));
  221. K = key;
  222. }
  223. else
  224. {
  225. if (K == null)
  226. throw new InvalidKeyException("Null Key");
  227. }
  228. if (newNonce)
  229. {
  230. if (n.length < 1 || n.length > 16)
  231. throw new IllegalArgumentException("Invalid Nonce length: "
  232. + String.valueOf(n.length));
  233. if (n.length < 16) // pad with zeroes
  234. {
  235. byte[] newN = new byte[16];
  236. System.arraycopy(n, 0, newN, 0, n.length);
  237. nonce = newN;
  238. }
  239. else
  240. nonce = n;
  241. nonceReuseCount = BigInteger.ZERO;
  242. }
  243. else if (nonce == null) // use all-0 nonce if 1st time
  244. {
  245. nonce = new byte[16];
  246. nonceReuseCount = BigInteger.ZERO;
  247. }
  248. else if (! newKey) // increment nonce if still below max count
  249. {
  250. nonceReuseCount = nonceReuseCount.add(BigInteger.ONE);
  251. if (nonceReuseCount.compareTo(MAX_NONCE_ITERATIONS) >= 0)
  252. {
  253. // limit reached. we SHOULD have a key
  254. throw new InvalidKeyException("Null Key and unusable old Nonce");
  255. }
  256. BigInteger N = new BigInteger(1, nonce);
  257. N = N.add(BigInteger.ONE).mod(MAX_NONCE_ITERATIONS);
  258. n = N.toByteArray();
  259. if (n.length == 16)
  260. nonce = n;
  261. else if (n.length < 16)
  262. {
  263. nonce = new byte[16];
  264. System.arraycopy(n, 0, nonce, 16 - n.length, n.length);
  265. }
  266. else
  267. {
  268. nonce = new byte[16];
  269. System.arraycopy(n, n.length - 16, nonce, 0, 16);
  270. }
  271. }
  272. else // do nothing, re-use old nonce value
  273. nonceReuseCount = BigInteger.ZERO;
  274. if (uhash32 == null)
  275. uhash32 = new UHash32();
  276. Map map = new HashMap();
  277. map.put(MAC_KEY_MATERIAL, K);
  278. uhash32.init(map);
  279. }
  280. public void update(byte b)
  281. {
  282. uhash32.update(b);
  283. }
  284. public void update(byte[] b, int offset, int len)
  285. {
  286. uhash32.update(b, offset, len);
  287. }
  288. public byte[] digest()
  289. {
  290. byte[] result = uhash32.digest();
  291. byte[] pad = pdf(); // pdf(K, nonce);
  292. for (int i = 0; i < OUTPUT_LEN; i++)
  293. result[i] = (byte)(result[i] ^ pad[i]);
  294. return result;
  295. }
  296. public void reset()
  297. {
  298. if (uhash32 != null)
  299. uhash32.reset();
  300. }
  301. public boolean selfTest()
  302. {
  303. if (valid == null)
  304. {
  305. byte[] key;
  306. try
  307. {
  308. key = "abcdefghijklmnop".getBytes("ASCII");
  309. }
  310. catch (UnsupportedEncodingException x)
  311. {
  312. throw new RuntimeException("ASCII not supported");
  313. }
  314. byte[] nonce = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
  315. UMac32 mac = new UMac32();
  316. Map attributes = new HashMap();
  317. attributes.put(MAC_KEY_MATERIAL, key);
  318. attributes.put(NONCE_MATERIAL, nonce);
  319. try
  320. {
  321. mac.init(attributes);
  322. }
  323. catch (InvalidKeyException x)
  324. {
  325. x.printStackTrace(System.err);
  326. return false;
  327. }
  328. byte[] data = new byte[128];
  329. data[0] = (byte) 0x80;
  330. mac.update(data, 0, 128);
  331. byte[] result = mac.digest();
  332. valid = Boolean.valueOf(TV1.equals(Util.toString(result)));
  333. }
  334. return valid.booleanValue();
  335. }
  336. /**
  337. * @return byte array of length 8 (or OUTPUT_LEN) bytes.
  338. */
  339. private byte[] pdf()
  340. {
  341. // Make Nonce 16 bytes by prepending zeroes. done (see init())
  342. // one AES invocation is enough for more than one PDF invocation
  343. // number of index bits needed = 1
  344. // Extract index bits and zero low bits of Nonce
  345. BigInteger Nonce = new BigInteger(1, nonce);
  346. int nlowbitsnum = Nonce.testBit(0) ? 1 : 0;
  347. Nonce = Nonce.clearBit(0);
  348. // Generate subkey, AES and extract indexed substring
  349. IRandom kdf = new UMacGenerator();
  350. Map map = new HashMap();
  351. map.put(IBlockCipher.KEY_MATERIAL, K);
  352. map.put(UMacGenerator.INDEX, Integer.valueOf(128));
  353. kdf.init(map);
  354. byte[] Kp = new byte[KEY_LEN];
  355. try
  356. {
  357. kdf.nextBytes(Kp, 0, KEY_LEN);
  358. }
  359. catch (IllegalStateException x)
  360. {
  361. x.printStackTrace(System.err);
  362. throw new RuntimeException(String.valueOf(x));
  363. }
  364. catch (LimitReachedException x)
  365. {
  366. x.printStackTrace(System.err);
  367. throw new RuntimeException(String.valueOf(x));
  368. }
  369. IBlockCipher aes = CipherFactory.getInstance(Registry.AES_CIPHER);
  370. map.put(IBlockCipher.KEY_MATERIAL, Kp);
  371. try
  372. {
  373. aes.init(map);
  374. }
  375. catch (InvalidKeyException x)
  376. {
  377. x.printStackTrace(System.err);
  378. throw new RuntimeException(String.valueOf(x));
  379. }
  380. catch (IllegalStateException x)
  381. {
  382. x.printStackTrace(System.err);
  383. throw new RuntimeException(String.valueOf(x));
  384. }
  385. byte[] T = new byte[16];
  386. aes.encryptBlock(nonce, 0, T, 0);
  387. byte[] result = new byte[OUTPUT_LEN];
  388. System.arraycopy(T, nlowbitsnum, result, 0, OUTPUT_LEN);
  389. return result;
  390. }
  391. }