| package org.bouncycastle.crypto.modes; |
| |
| import org.bouncycastle.crypto.BlockCipher; |
| import org.bouncycastle.crypto.CipherParameters; |
| import org.bouncycastle.crypto.DataLengthException; |
| import org.bouncycastle.crypto.params.ParametersWithIV; |
| |
| /** |
| * Implements the Segmented Integer Counter (SIC) mode on top of a simple |
| * block cipher. This mode is also known as CTR mode. |
| */ |
| public class SICBlockCipher |
| implements BlockCipher |
| { |
| private final BlockCipher cipher; |
| private final int blockSize; |
| |
| private byte[] IV; |
| private byte[] counter; |
| private byte[] counterOut; |
| |
| |
| /** |
| * Basic constructor. |
| * |
| * @param c the block cipher to be used. |
| */ |
| public SICBlockCipher(BlockCipher c) |
| { |
| this.cipher = c; |
| this.blockSize = cipher.getBlockSize(); |
| this.IV = new byte[blockSize]; |
| this.counter = new byte[blockSize]; |
| this.counterOut = new byte[blockSize]; |
| } |
| |
| |
| /** |
| * return the underlying block cipher that we are wrapping. |
| * |
| * @return the underlying block cipher that we are wrapping. |
| */ |
| public BlockCipher getUnderlyingCipher() |
| { |
| return cipher; |
| } |
| |
| |
| public void init( |
| boolean forEncryption, //ignored by this CTR mode |
| CipherParameters params) |
| throws IllegalArgumentException |
| { |
| if (params instanceof ParametersWithIV) |
| { |
| ParametersWithIV ivParam = (ParametersWithIV)params; |
| byte[] iv = ivParam.getIV(); |
| System.arraycopy(iv, 0, IV, 0, IV.length); |
| |
| reset(); |
| |
| // if null it's an IV changed only. |
| if (ivParam.getParameters() != null) |
| { |
| cipher.init(true, ivParam.getParameters()); |
| } |
| } |
| else |
| { |
| throw new IllegalArgumentException("SIC mode requires ParametersWithIV"); |
| } |
| } |
| |
| public String getAlgorithmName() |
| { |
| return cipher.getAlgorithmName() + "/SIC"; |
| } |
| |
| public int getBlockSize() |
| { |
| return cipher.getBlockSize(); |
| } |
| |
| |
| public int processBlock(byte[] in, int inOff, byte[] out, int outOff) |
| throws DataLengthException, IllegalStateException |
| { |
| cipher.processBlock(counter, 0, counterOut, 0); |
| |
| // |
| // XOR the counterOut with the plaintext producing the cipher text |
| // |
| for (int i = 0; i < counterOut.length; i++) |
| { |
| out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]); |
| } |
| |
| // increment counter by 1. |
| for (int i = counter.length - 1; i >= 0 && ++counter[i] == 0; i--) |
| { |
| ; // do nothing - pre-increment and test for 0 in counter does the job. |
| } |
| |
| return counter.length; |
| } |
| |
| |
| public void reset() |
| { |
| System.arraycopy(IV, 0, counter, 0, counter.length); |
| cipher.reset(); |
| } |
| } |