1package org.bouncycastle.crypto.modes; 2 3import org.bouncycastle.crypto.BlockCipher; 4import org.bouncycastle.crypto.CipherParameters; 5import org.bouncycastle.crypto.DataLengthException; 6import org.bouncycastle.crypto.params.ParametersWithIV; 7 8/** 9 * Implements the Segmented Integer Counter (SIC) mode on top of a simple 10 * block cipher. This mode is also known as CTR mode. 11 */ 12public class SICBlockCipher 13 implements BlockCipher 14{ 15 private final BlockCipher cipher; 16 private final int blockSize; 17 18 private byte[] IV; 19 private byte[] counter; 20 private byte[] counterOut; 21 22 23 /** 24 * Basic constructor. 25 * 26 * @param c the block cipher to be used. 27 */ 28 public SICBlockCipher(BlockCipher c) 29 { 30 this.cipher = c; 31 this.blockSize = cipher.getBlockSize(); 32 this.IV = new byte[blockSize]; 33 this.counter = new byte[blockSize]; 34 this.counterOut = new byte[blockSize]; 35 } 36 37 38 /** 39 * return the underlying block cipher that we are wrapping. 40 * 41 * @return the underlying block cipher that we are wrapping. 42 */ 43 public BlockCipher getUnderlyingCipher() 44 { 45 return cipher; 46 } 47 48 49 public void init( 50 boolean forEncryption, //ignored by this CTR mode 51 CipherParameters params) 52 throws IllegalArgumentException 53 { 54 if (params instanceof ParametersWithIV) 55 { 56 ParametersWithIV ivParam = (ParametersWithIV)params; 57 byte[] iv = ivParam.getIV(); 58 System.arraycopy(iv, 0, IV, 0, IV.length); 59 60 reset(); 61 62 // if null it's an IV changed only. 63 if (ivParam.getParameters() != null) 64 { 65 cipher.init(true, ivParam.getParameters()); 66 } 67 } 68 else 69 { 70 throw new IllegalArgumentException("SIC mode requires ParametersWithIV"); 71 } 72 } 73 74 public String getAlgorithmName() 75 { 76 return cipher.getAlgorithmName() + "/SIC"; 77 } 78 79 public int getBlockSize() 80 { 81 return cipher.getBlockSize(); 82 } 83 84 85 public int processBlock(byte[] in, int inOff, byte[] out, int outOff) 86 throws DataLengthException, IllegalStateException 87 { 88 cipher.processBlock(counter, 0, counterOut, 0); 89 90 // 91 // XOR the counterOut with the plaintext producing the cipher text 92 // 93 for (int i = 0; i < counterOut.length; i++) 94 { 95 out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]); 96 } 97 98 // increment counter by 1. 99 for (int i = counter.length - 1; i >= 0 && ++counter[i] == 0; i--) 100 { 101 ; // do nothing - pre-increment and test for 0 in counter does the job. 102 } 103 104 return counter.length; 105 } 106 107 108 public void reset() 109 { 110 System.arraycopy(IV, 0, counter, 0, counter.length); 111 cipher.reset(); 112 } 113} 114