OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [javax/] [crypto/] [prng/] [ICMGenerator.java] - Blame information for rev 775

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* ICMGenerator.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.math.BigInteger;
48
import java.security.InvalidKeyException;
49
import java.util.HashMap;
50
import java.util.Map;
51
 
52
/**
53
 * Counter Mode is a way to define a pseudorandom keystream generator using a
54
 * block cipher. The keystream can be used for additive encryption, key
55
 * derivation, or any other application requiring pseudorandom data.
56
 * <p>
57
 * In ICM, the keystream is logically broken into segments. Each segment is
58
 * identified with a segment index, and the segments have equal lengths. This
59
 * segmentation makes ICM especially appropriate for securing packet-based
60
 * protocols.
61
 * <p>
62
 * This implementation adheres to the definition of the ICM keystream generation
63
 * function that allows for any symetric key block cipher algorithm
64
 * (initialisation parameter <code>gnu.crypto.prng.icm.cipher.name</code>
65
 * taken to be an instance of {@link java.lang.String}) to be used. If such a
66
 * parameter is not defined/included in the initialisation <code>Map</code>,
67
 * then the "Rijndael" algorithm is used. Furthermore, if the initialisation
68
 * parameter <code>gnu.crypto.cipher.block.size</code> (taken to be a instance
69
 * of {@link java.lang.Integer}) is missing or undefined in the initialisation
70
 * <code>Map</code>, then the cipher's <em>default</em> block size is used.
71
 * <p>
72
 * The practical limits and constraints of such generator are:
73
 * <ul>
74
 * <li>The number of blocks in any segment <b>MUST NOT</b> exceed <code>
75
 *    256 ** BLOCK_INDEX_LENGTH</code>.
76
 * The number of segments <b>MUST NOT</b> exceed
77
 * <code>256 ** SEGMENT_INDEX_LENGTH</code>. These restrictions ensure the
78
 * uniqueness of each block cipher input.</li>
79
 * <li>Each segment contains <code>SEGMENT_LENGTH</code> octets; this value
80
 * <b>MUST NOT</b> exceed the value <code>(256 ** BLOCK_INDEX_LENGTH) *
81
 *    BLOCK_LENGTH</code>.</li>
82
 * <li>The sum of <code>SEGMENT_INDEX_LENGTH</code> and
83
 * <code>BLOCK_INDEX_LENGTH</code> <b>MUST NOT</b> exceed <code>BLOCK_LENGTH
84
 *    / 2</code>.
85
 * This requirement protects the ICM keystream generator from potentially
86
 * failing to be pseudorandom.</li>
87
 * </ul>
88
 * <p>
89
 * <b>NOTE</b>: Rijndael is used as the default symmetric key block cipher
90
 * algorithm because, with its default block and key sizes, it is the AES. Yet
91
 * being Rijndael, the algorithm offers more versatile block and key sizes which
92
 * may prove to be useful for generating <em>longer</em> key streams.
93
 * <p>
94
 * References:
95
 * <ol>
96
 * <li><a
97
 * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-icm-00.txt">
98
 * Integer Counter Mode</a>, David A. McGrew.</li>
99
 * </ol>
100
 */
101
public class ICMGenerator
102
    extends BasePRNG
103
    implements Cloneable
104
{
105
  /** Property name of underlying block cipher for this ICM generator. */
106
  public static final String CIPHER = "gnu.crypto.prng.icm.cipher.name";
107
  /** Property name of ICM's block index length. */
108
  public static final String BLOCK_INDEX_LENGTH =
109
      "gnu.crypto.prng.icm.block.index.length";
110
  /** Property name of ICM's segment index length. */
111
  public static final String SEGMENT_INDEX_LENGTH =
112
      "gnu.crypto.prng.icm.segment.index.length";
113
  /** Property name of ICM's offset. */
114
  public static final String OFFSET = "gnu.crypto.prng.icm.offset";
115
  /** Property name of ICM's segment index. */
116
  public static final String SEGMENT_INDEX = "gnu.crypto.prng.icm.segment.index";
117
  /** The integer value 256 as a BigInteger. */
118
  private static final BigInteger TWO_FIFTY_SIX = new BigInteger("256");
119
  /** The underlying cipher implementation. */
120
  private IBlockCipher cipher;
121
  /** This keystream block index length in bytes. */
122
  private int blockNdxLength = -1;
123
  /** This keystream segment index length in bytes. */
124
  private int segmentNdxLength = -1;
125
  /** The index of the next block for a given keystream segment. */
126
  private BigInteger blockNdx = BigInteger.ZERO;
127
  /** The segment index for this keystream. */
128
  private BigInteger segmentNdx;
129
  /** The initial counter for a given keystream segment. */
130
  private BigInteger C0;
131
 
132
  /** Trivial 0-arguments constructor. */
133
  public ICMGenerator()
134
  {
135
    super(Registry.ICM_PRNG);
136
  }
137
 
138
  // Conceptually, ICM is a keystream generator that takes a secret key and a
139
  // segment index as an input and then outputs a keystream segment. The
140
  // segmentation lends itself to packet encryption, as each keystream segment
141
  // can be used to encrypt a distinct packet.
142
  //
143
  // An ICM key consists of the block cipher key and an Offset. The Offset is
144
  // an integer with BLOCK_LENGTH octets...
145
  public void setup(Map attributes)
146
  {
147
    // find out which cipher algorithm to use
148
    boolean newCipher = true;
149
    String underlyingCipher = (String) attributes.get(CIPHER);
150
    if (underlyingCipher == null)
151
      if (cipher == null) // happy birthday
152
        // ensure we have a reliable implementation of this cipher
153
        cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER);
154
      else
155
        // we already have one. use it as is
156
        newCipher = false;
157
    else // ensure we have a reliable implementation of this cipher
158
      cipher = CipherFactory.getInstance(underlyingCipher);
159
 
160
    // find out what block size we should use it in
161
    int cipherBlockSize = 0;
162
    Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE);
163
    if (bs != null)
164
      cipherBlockSize = bs.intValue();
165
    else
166
      {
167
        if (newCipher) // assume we'll use its default block size
168
          cipherBlockSize = cipher.defaultBlockSize();
169
        // else use as is
170
      }
171
    // get the key material
172
    byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL);
173
    if (key == null)
174
      throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL);
175
    // now initialise the cipher
176
    HashMap map = new HashMap();
177
    if (cipherBlockSize != 0) // only needed if new or changed
178
      map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(cipherBlockSize));
179
    map.put(IBlockCipher.KEY_MATERIAL, key);
180
    try
181
      {
182
        cipher.init(map);
183
      }
184
    catch (InvalidKeyException x)
185
      {
186
        throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL);
187
      }
188
    // at this point we have an initialised (new or otherwise) cipher
189
    // ensure that remaining params make sense
190
    cipherBlockSize = cipher.currentBlockSize();
191
    BigInteger counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize);
192
    // offset, like the underlying cipher key is not cloneable
193
    // always look for it and throw an exception if it's not there
194
    Object obj = attributes.get(OFFSET);
195
    // allow either a byte[] or a BigInteger
196
    BigInteger r;
197
    if (obj instanceof BigInteger)
198
      r = (BigInteger) obj;
199
    else // assume byte[]. should be same length as cipher block size
200
      {
201
        byte[] offset = (byte[]) obj;
202
        if (offset.length != cipherBlockSize)
203
          throw new IllegalArgumentException(OFFSET);
204
        r = new BigInteger(1, offset);
205
      }
206
    int wantBlockNdxLength = -1; // number of octets in the block index
207
    Integer i = (Integer) attributes.get(BLOCK_INDEX_LENGTH);
208
    if (i != null)
209
      {
210
        wantBlockNdxLength = i.intValue();
211
        if (wantBlockNdxLength < 1)
212
          throw new IllegalArgumentException(BLOCK_INDEX_LENGTH);
213
      }
214
    int wantSegmentNdxLength = -1; // number of octets in the segment index
215
    i = (Integer) attributes.get(SEGMENT_INDEX_LENGTH);
216
    if (i != null)
217
      {
218
        wantSegmentNdxLength = i.intValue();
219
        if (wantSegmentNdxLength < 1)
220
          throw new IllegalArgumentException(SEGMENT_INDEX_LENGTH);
221
      }
222
    // if both are undefined check if it's a reuse
223
    if ((wantBlockNdxLength == -1) && (wantSegmentNdxLength == -1))
224
      {
225
        if (blockNdxLength == -1) // new instance
226
          throw new IllegalArgumentException(BLOCK_INDEX_LENGTH + ", "
227
                                             + SEGMENT_INDEX_LENGTH);
228
        // else reuse old values
229
      }
230
    else // only one is undefined, set it to BLOCK_LENGTH/2 minus the other
231
      {
232
        int limit = cipherBlockSize / 2;
233
        if (wantBlockNdxLength == -1)
234
          wantBlockNdxLength = limit - wantSegmentNdxLength;
235
        else if (wantSegmentNdxLength == -1)
236
          wantSegmentNdxLength = limit - wantBlockNdxLength;
237
        else if ((wantSegmentNdxLength + wantBlockNdxLength) > limit)
238
          throw new IllegalArgumentException(BLOCK_INDEX_LENGTH + ", "
239
                                             + SEGMENT_INDEX_LENGTH);
240
        // save new values
241
        blockNdxLength = wantBlockNdxLength;
242
        segmentNdxLength = wantSegmentNdxLength;
243
      }
244
    // get the segment index as a BigInteger
245
    BigInteger s = (BigInteger) attributes.get(SEGMENT_INDEX);
246
    if (s == null)
247
      {
248
        if (segmentNdx == null) // segment index was never set
249
          throw new IllegalArgumentException(SEGMENT_INDEX);
250
        // reuse; check if still valid
251
        if (segmentNdx.compareTo(TWO_FIFTY_SIX.pow(segmentNdxLength)) > 0)
252
          throw new IllegalArgumentException(SEGMENT_INDEX);
253
      }
254
    else
255
      {
256
        if (s.compareTo(TWO_FIFTY_SIX.pow(segmentNdxLength)) > 0)
257
          throw new IllegalArgumentException(SEGMENT_INDEX);
258
        segmentNdx = s;
259
      }
260
    // The initial counter of the keystream segment with segment index s is
261
    // defined as follows, where r denotes the Offset:
262
    //
263
    // C[0] = (s * (256^BLOCK_INDEX_LENGTH) + r) modulo (256^BLOCK_LENGTH)
264
    C0 = segmentNdx.multiply(TWO_FIFTY_SIX.pow(blockNdxLength))
265
                   .add(r).modPow(BigInteger.ONE, counterRange);
266
    try
267
      {
268
        fillBlock();
269
      }
270
    catch (LimitReachedException impossible)
271
      {
272
        throw (InternalError)
273
          new InternalError().initCause(impossible);
274
      }
275
  }
276
 
277
  public void fillBlock() throws LimitReachedException
278
  {
279
    if (C0 == null)
280
      throw new IllegalStateException();
281
    if (blockNdx.compareTo(TWO_FIFTY_SIX.pow(blockNdxLength)) >= 0)
282
      throw new LimitReachedException();
283
    int cipherBlockSize = cipher.currentBlockSize();
284
    BigInteger counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize);
285
    // encrypt the counter for the current blockNdx
286
    // C[i] = (C[0] + i) modulo (256^BLOCK_LENGTH).
287
    BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange);
288
    buffer = Ci.toByteArray();
289
    int limit = buffer.length;
290
    if (limit < cipherBlockSize)
291
      {
292
        byte[] data = new byte[cipherBlockSize];
293
        System.arraycopy(buffer, 0, data, cipherBlockSize - limit, limit);
294
        buffer = data;
295
      }
296
    else if (limit > cipherBlockSize)
297
      {
298
        byte[] data = new byte[cipherBlockSize];
299
        System.arraycopy(buffer, limit - cipherBlockSize, data, 0,
300
                         cipherBlockSize);
301
        buffer = data;
302
      }
303
    cipher.encryptBlock(buffer, 0, buffer, 0);
304
    blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx
305
  }
306
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.