ICM.java 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /* ICM.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.mode;
  32. import gnu.java.security.Registry;
  33. import gnu.javax.crypto.cipher.IBlockCipher;
  34. import java.math.BigInteger;
  35. /**
  36. * An implementation of <i>David McGrew</i> Integer Counter Mode (ICM) as an
  37. * {@link IMode}.
  38. * <p>
  39. * ICM is a way to define a pseudorandom keystream generator using a block
  40. * cipher. The keystream can be used for additive encryption, key derivation, or
  41. * any other application requiring pseudorandom data. In the case of this class,
  42. * it is used as additive encryption, XOR-ing the keystream with the input text
  43. * --for both encryption and decryption.
  44. * <p>
  45. * In ICM, the keystream is logically broken into segments. Each segment is
  46. * identified with a segment index, and the segments have equal lengths. This
  47. * segmentation makes ICM especially appropriate for securing packet-based
  48. * protocols. ICM also allows a variety of configurations based, among other
  49. * things, on two parameters: the <i>block index length</i> and the <i>segment
  50. * index length</i>. A constraint on those two values exists: The sum of
  51. * <i>segment index length</i> and <i>block index length</i> <b>must not</b>
  52. * half the <i>block size</i> of the underlying cipher. This requirement
  53. * protects the ICM keystream generator from potentially failing to be
  54. * pseudorandom.
  55. * <p>
  56. * For simplicity, this implementation, fixes these two values to the following:
  57. * <ul>
  58. * <li>block index length: is half the underlying cipher block size, and</li>
  59. * <li>segment index length: is zero.</li>
  60. * </ul>
  61. * <p>
  62. * For a 128-bit block cipher, the above values imply a maximum keystream length
  63. * of 295,147,905,179,352,825,856 octets, since in ICM, each segment must not
  64. * exceed the value
  65. * <code>(256 ^ <i>block index length</i>) * <i>block length</i></code>
  66. * octets.
  67. * <p>
  68. * Finally, for this implementation of the ICM, the IV placeholder will be used
  69. * to pass the value of the <i>Offset</i> in the keystream segment.
  70. * <p>
  71. * References:
  72. * <ol>
  73. * <li><a
  74. * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-icm-00.txt">
  75. * Integer Counter Mode</a>, David A. McGrew.</li>
  76. * </ol>
  77. */
  78. public class ICM
  79. extends BaseMode
  80. implements Cloneable
  81. {
  82. /** The integer value 256 as a BigInteger. */
  83. private static final BigInteger TWO_FIFTY_SIX = new BigInteger("256");
  84. /** Maximum number of blocks per segment. */
  85. private BigInteger maxBlocksPerSegment;
  86. /** A work constant. */
  87. private BigInteger counterRange;
  88. /** The initial counter for a given keystream segment. */
  89. private BigInteger C0;
  90. /** The index of the next block for a given keystream segment. */
  91. private BigInteger blockNdx;
  92. /**
  93. * Trivial package-private constructor for use by the Factory class.
  94. *
  95. * @param underlyingCipher the underlying cipher implementation.
  96. * @param cipherBlockSize the underlying cipher block size to use.
  97. */
  98. ICM(IBlockCipher underlyingCipher, int cipherBlockSize)
  99. {
  100. super(Registry.ICM_MODE, underlyingCipher, cipherBlockSize);
  101. }
  102. /**
  103. * Private constructor for cloning purposes.
  104. *
  105. * @param that the instance to clone.
  106. */
  107. private ICM(ICM that)
  108. {
  109. this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize);
  110. }
  111. public Object clone()
  112. {
  113. return new ICM(this);
  114. }
  115. public void setup()
  116. {
  117. if (modeBlockSize != cipherBlockSize)
  118. throw new IllegalArgumentException();
  119. counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize);
  120. maxBlocksPerSegment = TWO_FIFTY_SIX.pow(cipherBlockSize / 2);
  121. BigInteger r = new BigInteger(1, iv);
  122. C0 = maxBlocksPerSegment.add(r).modPow(BigInteger.ONE, counterRange);
  123. blockNdx = BigInteger.ZERO;
  124. }
  125. public void teardown()
  126. {
  127. counterRange = null;
  128. maxBlocksPerSegment = null;
  129. C0 = null;
  130. blockNdx = null;
  131. }
  132. public void encryptBlock(byte[] in, int i, byte[] out, int o)
  133. {
  134. icm(in, i, out, o);
  135. }
  136. public void decryptBlock(byte[] in, int i, byte[] out, int o)
  137. {
  138. icm(in, i, out, o);
  139. }
  140. private void icm(byte[] in, int inOffset, byte[] out, int outOffset)
  141. {
  142. if (blockNdx.compareTo(maxBlocksPerSegment) >= 0)
  143. throw new RuntimeException("Maximum blocks for segment reached");
  144. BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange);
  145. byte[] result = Ci.toByteArray();
  146. int limit = result.length;
  147. int ndx = 0;
  148. if (limit < cipherBlockSize)
  149. {
  150. byte[] data = new byte[cipherBlockSize];
  151. System.arraycopy(result, 0, data, cipherBlockSize - limit, limit);
  152. result = data;
  153. }
  154. else if (limit > cipherBlockSize)
  155. ndx = limit - cipherBlockSize;
  156. cipher.encryptBlock(result, ndx, result, ndx);
  157. blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx
  158. for (int i = 0; i < modeBlockSize; i++) // xor result with input block
  159. out[outOffset++] = (byte)(in[inOffset++] ^ result[ndx++]);
  160. }
  161. }