Frames | No Frames |
1: /* Cascade.java -- 2: Copyright (C) 2003, 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.assembly; 40: 41: import java.math.BigInteger; 42: import java.security.InvalidKeyException; 43: import java.util.Collections; 44: import java.util.HashMap; 45: import java.util.HashSet; 46: import java.util.Iterator; 47: import java.util.LinkedList; 48: import java.util.Map; 49: import java.util.Set; 50: 51: /** 52: * A <i>Cascade</i> Cipher is the concatenation of two or more block ciphers 53: * each with independent keys. Plaintext is input to the first stage; the output 54: * of stage <code>i</code> is input to stage <code>i + 1</code>; and the 55: * output of the last stage is the <i>Cascade</i>'s ciphertext output. 56: * <p> 57: * In the simplest case, all stages in a <code>Cascade</code> have <i>k</i>-bit 58: * keys, and the stage inputs and outputs are all n-bit quantities. The stage 59: * ciphers may differ (general cascade of ciphers), or all be identical (cascade 60: * of identical ciphers). 61: * <p> 62: * The term "block ciphers" used above refers to implementations of 63: * {@link gnu.javax.crypto.mode.IMode}, including the 64: * {@link gnu.javax.crypto.mode.ECB} mode which basically exposes a 65: * symmetric-key block cipher algorithm as a <i>Mode</i> of Operations. 66: * <p> 67: * References: 68: * <ol> 69: * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of 70: * Applied Cryptography.<br> 71: * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br> 72: * Menezes, A., van Oorschot, P. and S. Vanstone.</li> 73: * </ol> 74: */ 75: public class Cascade 76: { 77: public static final String DIRECTION = "gnu.crypto.assembly.cascade.direction"; 78: 79: /** The map of Stages chained in this cascade. */ 80: protected HashMap stages; 81: 82: /** The ordered list of Stage UIDs to their attribute maps. */ 83: protected LinkedList stageKeys; 84: 85: /** The current operational direction of this instance. */ 86: protected Direction wired; 87: 88: /** The curently set block-size for this instance. */ 89: protected int blockSize; 90: 91: public Cascade() 92: { 93: super(); 94: 95: stages = new HashMap(3); 96: stageKeys = new LinkedList(); 97: wired = null; 98: blockSize = 0; 99: } 100: 101: /** 102: * Returns the Least Common Multiple of two integers. 103: * 104: * @param a the first integer. 105: * @param b the second integer. 106: * @return the LCM of <code>abs(a)</code> and <code>abs(b)</code>. 107: */ 108: private static final int lcm(int a, int b) 109: { 110: BigInteger A = BigInteger.valueOf(a * 1L); 111: BigInteger B = BigInteger.valueOf(b * 1L); 112: return A.multiply(B).divide(A.gcd(B)).abs().intValue(); 113: } 114: 115: /** 116: * Adds to the end of the current chain, a designated {@link Stage}. 117: * 118: * @param stage the {@link Stage} to append to the chain. 119: * @return a unique identifier for this stage, within this cascade. 120: * @throws IllegalStateException if the instance is already initialised. 121: * @throws IllegalArgumentException if the designated stage is already in the 122: * chain, or it has incompatible characteristics with the current 123: * elements already in the chain. 124: */ 125: public Object append(Stage stage) throws IllegalArgumentException 126: { 127: return insert(size(), stage); 128: } 129: 130: /** 131: * Adds to the begining of the current chain, a designated {@link Stage}. 132: * 133: * @param stage the {@link Stage} to prepend to the chain. 134: * @return a unique identifier for this stage, within this cascade. 135: * @throws IllegalStateException if the instance is already initialised. 136: * @throws IllegalArgumentException if the designated stage is already in the 137: * chain, or it has incompatible characteristics with the current 138: * elements already in the chain. 139: */ 140: public Object prepend(Stage stage) throws IllegalArgumentException 141: { 142: return insert(0, stage); 143: } 144: 145: /** 146: * Inserts a {@link Stage} into the current chain, at the specified index 147: * (zero-based) position. 148: * 149: * @param stage the {@link Stage} to insert into the chain. 150: * @return a unique identifier for this stage, within this cascade. 151: * @throws IllegalArgumentException if the designated stage is already in the 152: * chain, or it has incompatible characteristics with the current 153: * elements already in the chain. 154: * @throws IllegalStateException if the instance is already initialised. 155: * @throws IndexOutOfBoundsException if <code>index</code> is less than 156: * <code>0</code> or greater than the current size of this 157: * cascade. 158: */ 159: public Object insert(int index, Stage stage) throws IllegalArgumentException, 160: IndexOutOfBoundsException 161: { 162: if (stages.containsValue(stage)) 163: throw new IllegalArgumentException(); 164: if (wired != null || stage == null) 165: throw new IllegalStateException(); 166: if (index < 0 || index > size()) 167: throw new IndexOutOfBoundsException(); 168: // check that there is a non-empty set of common block-sizes 169: Set set = stage.blockSizes(); 170: if (stages.isEmpty()) 171: { 172: if (set.isEmpty()) 173: throw new IllegalArgumentException("1st stage with no block sizes"); 174: } 175: else 176: { 177: Set common = this.blockSizes(); 178: common.retainAll(set); 179: if (common.isEmpty()) 180: throw new IllegalArgumentException("no common block sizes found"); 181: } 182: Object result = new Object(); 183: stageKeys.add(index, result); 184: stages.put(result, stage); 185: return result; 186: } 187: 188: /** 189: * Returns the current number of stages in this chain. 190: * 191: * @return the current count of stages in this chain. 192: */ 193: public int size() 194: { 195: return stages.size(); 196: } 197: 198: /** 199: * Returns an {@link Iterator} over the stages contained in this instance. 200: * Each element of this iterator is a concrete implementation of a {@link 201: * Stage}. 202: * 203: * @return an {@link Iterator} over the stages contained in this instance. 204: * Each element of the returned iterator is a concrete instance of a 205: * {@link Stage}. 206: */ 207: public Iterator stages() 208: { 209: LinkedList result = new LinkedList(); 210: for (Iterator it = stageKeys.listIterator(); it.hasNext();) 211: result.addLast(stages.get(it.next())); 212: return result.listIterator(); 213: } 214: 215: /** 216: * Returns the {@link Set} of supported block sizes for this 217: * <code>Cascade</code> that are common to all of its chained stages. Each 218: * element in the returned {@link Set} is an instance of {@link Integer}. 219: * 220: * @return a {@link Set} of supported block sizes common to all the stages of 221: * the chain. 222: */ 223: public Set blockSizes() 224: { 225: HashSet result = null; 226: for (Iterator it = stages.values().iterator(); it.hasNext();) 227: { 228: Stage aStage = (Stage) it.next(); 229: if (result == null) // first time 230: result = new HashSet(aStage.blockSizes()); 231: else 232: result.retainAll(aStage.blockSizes()); 233: } 234: return result == null ? Collections.EMPTY_SET : result; 235: } 236: 237: /** 238: * Initialises the chain for operation with specific characteristics. 239: * 240: * @param attributes a set of name-value pairs that describes the desired 241: * future behaviour of this instance. 242: * @throws IllegalStateException if the chain, or any of its stages, is 243: * already initialised. 244: * @throws InvalidKeyException if the intialisation data provided with the 245: * stage is incorrect or causes an invalid key to be generated. 246: * @see Direction#FORWARD 247: * @see Direction#REVERSED 248: */ 249: public void init(Map attributes) throws InvalidKeyException 250: { 251: if (wired != null) 252: throw new IllegalStateException(); 253: Direction flow = (Direction) attributes.get(DIRECTION); 254: if (flow == null) 255: flow = Direction.FORWARD; 256: int optimalSize = 0; 257: for (Iterator it = stageKeys.listIterator(); it.hasNext();) 258: { 259: Object id = it.next(); 260: Map attr = (Map) attributes.get(id); 261: attr.put(Stage.DIRECTION, flow); 262: Stage stage = (Stage) stages.get(id); 263: stage.init(attr); 264: optimalSize = optimalSize == 0 ? stage.currentBlockSize() 265: : lcm(optimalSize, 266: stage.currentBlockSize()); 267: } 268: if (flow == Direction.REVERSED) // reverse order 269: Collections.reverse(stageKeys); 270: wired = flow; 271: blockSize = optimalSize; 272: } 273: 274: /** 275: * Returns the currently set block size for the chain. 276: * 277: * @return the current block size for the chain. 278: * @throws IllegalStateException if the instance is not initialised. 279: */ 280: public int currentBlockSize() 281: { 282: if (wired == null) 283: throw new IllegalStateException(); 284: return blockSize; 285: } 286: 287: /** 288: * Resets the chain for re-initialisation and use with other characteristics. 289: * This method always succeeds. 290: */ 291: public void reset() 292: { 293: for (Iterator it = stageKeys.listIterator(); it.hasNext();) 294: ((Stage) stages.get(it.next())).reset(); 295: if (wired == Direction.REVERSED) // reverse it back 296: Collections.reverse(stageKeys); 297: wired = null; 298: blockSize = 0; 299: } 300: 301: /** 302: * Processes exactly one block of <i>plaintext</i> (if initialised in the 303: * {@link Direction#FORWARD} state) or <i>ciphertext</i> (if initialised in 304: * the {@link Direction#REVERSED} state). 305: * 306: * @param in the plaintext. 307: * @param inOffset index of <code>in</code> from which to start considering 308: * data. 309: * @param out the ciphertext. 310: * @param outOffset index of <code>out</code> from which to store result. 311: * @throws IllegalStateException if the instance is not initialised. 312: */ 313: public void update(byte[] in, int inOffset, byte[] out, int outOffset) 314: { 315: if (wired == null) 316: throw new IllegalStateException(); 317: int stageBlockSize, j, i = stages.size(); 318: for (Iterator it = stageKeys.listIterator(); it.hasNext();) 319: { 320: Stage stage = (Stage) stages.get(it.next()); 321: stageBlockSize = stage.currentBlockSize(); 322: for (j = 0; j < blockSize; j += stageBlockSize) 323: stage.update(in, inOffset + j, out, outOffset + j); 324: i--; 325: if (i > 0) 326: System.arraycopy(out, outOffset, in, inOffset, blockSize); 327: } 328: } 329: 330: /** 331: * Conducts a simple <i>correctness</i> test that consists of basic symmetric 332: * encryption / decryption test(s) for all supported block and key sizes of 333: * underlying block cipher(s) wrapped by Mode leafs. The test also includes 334: * one (1) variable key Known Answer Test (KAT) for each block cipher. 335: * 336: * @return <code>true</code> if the implementation passes simple 337: * <i>correctness</i> tests. Returns <code>false</code> otherwise. 338: */ 339: public boolean selfTest() 340: { 341: for (Iterator it = stageKeys.listIterator(); it.hasNext();) 342: { 343: if (! ((Stage) stages.get(it.next())).selfTest()) 344: return false; 345: } 346: return true; 347: } 348: }