diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java')
-rw-r--r-- | bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java | 174 |
1 files changed, 143 insertions, 31 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java index da8c4ae..5dd47ae 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java @@ -3,14 +3,18 @@ package org.bouncycastle.crypto.modes; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.SkippingStreamCipher; +import org.bouncycastle.crypto.StreamBlockCipher; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Pack; /** * 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 + extends StreamBlockCipher + implements SkippingStreamCipher { private final BlockCipher cipher; private final int blockSize; @@ -18,7 +22,7 @@ public class SICBlockCipher private byte[] IV; private byte[] counter; private byte[] counterOut; - + private int byteCount; /** * Basic constructor. @@ -27,25 +31,16 @@ public class SICBlockCipher */ public SICBlockCipher(BlockCipher c) { + super(c); + this.cipher = c; this.blockSize = cipher.getBlockSize(); this.IV = new byte[blockSize]; this.counter = new byte[blockSize]; this.counterOut = new byte[blockSize]; + this.byteCount = 0; } - - /** - * 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) @@ -53,17 +48,17 @@ public class SICBlockCipher { if (params instanceof ParametersWithIV) { - ParametersWithIV ivParam = (ParametersWithIV)params; - byte[] iv = ivParam.getIV(); - System.arraycopy(iv, 0, IV, 0, IV.length); + 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()); + } - // if null it's an IV changed only. - if (ivParam.getParameters() != null) - { - cipher.init(true, ivParam.getParameters()); - } + reset(); } else { @@ -81,33 +76,150 @@ public class SICBlockCipher return cipher.getBlockSize(); } - public int processBlock(byte[] in, int inOff, byte[] out, int outOff) throws DataLengthException, IllegalStateException { - cipher.processBlock(counter, 0, counterOut, 0); + processBytes(in, inOff, blockSize, out, outOff); - // - // XOR the counterOut with the plaintext producing the cipher text - // - for (int i = 0; i < counterOut.length; i++) + return blockSize; + } + + protected byte calculateByte(byte in) + throws DataLengthException, IllegalStateException + { + if (byteCount == 0) { - out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]); + cipher.processBlock(counter, 0, counterOut, 0); + + return (byte)(counterOut[byteCount++] ^ in); + } + + byte rv = (byte)(counterOut[byteCount++] ^ in); + + if (byteCount == counter.length) + { + byteCount = 0; + + incrementCounter(); } + return rv; + } + + private void incrementCounter() + { // 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; + private void decrementCounter() + { + if (counter[0] == 0) + { + boolean nonZero = false; + + for (int i = counter.length - 1; i > 0; i--) + { + if (counter[i] != 0) + { + nonZero = true; + } + } + + if (!nonZero) + { + throw new IllegalStateException("attempt to reduce counter past zero."); + } + } + + // decrement counter by 1. + for (int i = counter.length - 1; i >= 0 && --counter[i] == -1; i--) + { + ; + } } + private void adjustCounter(long n) + { + if (n >= 0) + { + long numBlocks = (n + byteCount) / blockSize; + + for (long i = 0; i != numBlocks; i++) + { + incrementCounter(); + } + + byteCount = (int)((n + byteCount) - (blockSize * numBlocks)); + } + else + { + long numBlocks = (-n - byteCount) / blockSize; + + for (long i = 0; i != numBlocks; i++) + { + decrementCounter(); + } + + int gap = (int)(byteCount + n + (blockSize * numBlocks)); + + if (gap >= 0) + { + byteCount = 0; + } + else + { + decrementCounter(); + byteCount = blockSize + gap; + } + } + } public void reset() { System.arraycopy(IV, 0, counter, 0, counter.length); cipher.reset(); + this.byteCount = 0; + } + + public long skip(long numberOfBytes) + { + adjustCounter(numberOfBytes); + + cipher.processBlock(counter, 0, counterOut, 0); + + return numberOfBytes; + } + + public long seekTo(long position) + { + reset(); + + return skip(position); + } + + public long getPosition() + { + byte[] res = new byte[IV.length]; + + System.arraycopy(counter, 0, res, 0, res.length); + + for (int i = res.length - 1; i >= 1; i--) + { + int v = (res[i] - IV[i]); + + if (v < 0) + { + res[i - 1]--; + v += 256; + } + + res[i] = (byte)v; + } + + return Pack.bigEndianToLong(res, res.length - 8) * blockSize + byteCount; } } |