Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2014-05-16 09:49:13 +0400
committerDavid Hook <dgh@cryptoworkshop.com>2014-05-16 09:49:13 +0400
commit8b2aeaea94a1f9c3450b5bd8841c37ac8e78efd5 (patch)
tree75a8543081a363ff93aba5cfae9538f9a85d8e42 /core/src
parent13f8d8f5309cdb26317e9578a54ccdcd635fe706 (diff)
further work on SkippingCipher, added StreamCipher interface to SICBlockCipher.
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/SkippingCipher.java19
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java21
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java144
-rw-r--r--core/src/test/java/org/bouncycastle/crypto/test/AESTest.java108
-rw-r--r--core/src/test/java/org/bouncycastle/crypto/test/Salsa20Test.java9
5 files changed, 270 insertions, 31 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/SkippingCipher.java b/core/src/main/java/org/bouncycastle/crypto/SkippingCipher.java
index bf2595fd..477be0c0 100644
--- a/core/src/main/java/org/bouncycastle/crypto/SkippingCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/SkippingCipher.java
@@ -6,12 +6,19 @@ package org.bouncycastle.crypto;
public interface SkippingCipher
{
/**
- * Skip numberOfBlocks forwards, or backwards. If the cipher is a stream cipher a block
- * size of 1 is assumed.
+ * Skip numberOfBytes forwards, or backwards.
*
- * @param numberOfBlocks the number of blocks to skip (positive forward, negative backwards).
- * @return the number of blocks actually skipped.
- * @throws java.lang.IllegalArgumentException if numberOfBlocks is an invalid value.
+ * @param numberOfBytes the number of bytes to skip (positive forward, negative backwards).
+ * @return the number of bytes actually skipped.
+ * @throws java.lang.IllegalArgumentException if numberOfBytes is an invalid value.
*/
- long skip(long numberOfBlocks);
+ long skip(long numberOfBytes);
+
+ /**
+ * Reset the cipher and then skip forward to a given position.
+ *
+ * @param position the number of bytes in to set the cipher state to.
+ * @return the byte position moved to.
+ */
+ long seekTo(long position);
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java
index b4e89900..a2837dd8 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java
@@ -216,15 +216,15 @@ public class Salsa20Engine
}
}
- public long skip(long numberOfBlocks)
+ public long skip(long numberOfBytes)
{
- if (numberOfBlocks >= 0)
+ if (numberOfBytes >= 0)
{
- for (long i = 0; i < numberOfBlocks; i++)
+ for (long i = 0; i < numberOfBytes; i++)
{
if (index == 0)
{
- if (numberOfBlocks - i < 64)
+ if (numberOfBytes - i < 64)
{
generateKeyStream(keyStream);
}
@@ -237,14 +237,14 @@ public class Salsa20Engine
}
else
{
- for (long i = 0; i > numberOfBlocks; i--)
+ for (long i = 0; i > numberOfBytes; i--)
{
index = (index - 1) & 63;
if (index == 0)
{
retreatCounter();
- if (i - numberOfBlocks < 63)
+ if (i - numberOfBytes < 63)
{
if (isCounterAtZero())
{
@@ -261,7 +261,14 @@ public class Salsa20Engine
}
}
- return numberOfBlocks;
+ return numberOfBytes;
+ }
+
+ public long seekTo(long position)
+ {
+ reset();
+
+ return skip(position);
}
public void reset()
diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
index da8c4ae1..5da541ee 100644
--- a/core/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
+++ b/core/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
@@ -3,6 +3,8 @@ package org.bouncycastle.crypto.modes;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.SkippingCipher;
+import org.bouncycastle.crypto.StreamCipher;
import org.bouncycastle.crypto.params.ParametersWithIV;
/**
@@ -10,7 +12,7 @@ import org.bouncycastle.crypto.params.ParametersWithIV;
* block cipher. This mode is also known as CTR mode.
*/
public class SICBlockCipher
- implements BlockCipher
+ implements BlockCipher, StreamCipher, SkippingCipher
{
private final BlockCipher cipher;
private final int blockSize;
@@ -18,7 +20,7 @@ public class SICBlockCipher
private byte[] IV;
private byte[] counter;
private byte[] counterOut;
-
+ private int byteCount;
/**
* Basic constructor.
@@ -32,6 +34,7 @@ public class SICBlockCipher
this.IV = new byte[blockSize];
this.counter = new byte[blockSize];
this.counterOut = new byte[blockSize];
+ this.byteCount = 0;
}
@@ -53,17 +56,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
{
@@ -76,6 +79,34 @@ public class SICBlockCipher
return cipher.getAlgorithmName() + "/SIC";
}
+ public byte returnByte(byte in)
+ {
+ return processByte(in);
+ }
+
+ public void processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException
+ {
+ if (outOff + len > out.length)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ if (inOff + len > in.length)
+ {
+ throw new DataLengthException("input buffer too small for len");
+ }
+
+ int inStart = inOff;
+ int inEnd = inOff + len;
+ int outStart = outOff;
+
+ while (inStart < inEnd)
+ {
+ out[outStart++] = processByte(in[inStart++]);
+ }
+ }
+
public int getBlockSize()
{
return cipher.getBlockSize();
@@ -85,29 +116,106 @@ public class SICBlockCipher
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;
+ }
+
+ private byte processByte(byte in)
+ throws DataLengthException, IllegalStateException
+ {
+ if (byteCount == 0)
{
- out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]);
+ cipher.processBlock(counter, 0, counterOut, 0);
}
+ 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()
+ {
+ // increment counter by 1.
+ for (int i = counter.length - 1; i >= 0 && --counter[i] == Integer.MIN_VALUE; i--)
+ {
+ ; // do nothing - pre-increment and test for 0 in counter does the job.
+ }
}
+ 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();
+
+ skip(position);
+
+ return 0;
}
}
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/AESTest.java b/core/src/test/java/org/bouncycastle/crypto/test/AESTest.java
index 8c9637f7..791e47b9 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/AESTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/AESTest.java
@@ -1,7 +1,10 @@
package org.bouncycastle.crypto.test;
+import java.security.SecureRandom;
+
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
@@ -243,6 +246,109 @@ public class AESTest
}
}
+ private boolean areEqual(byte[] a, int aOff, byte[] b, int bOff)
+ {
+ for (int i = bOff; i != b.length; i++)
+ {
+ if (a[aOff + i - bOff] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void skipTest()
+ {
+ SecureRandom rand = new SecureRandom();
+ byte[] plain = new byte[5000];
+ byte[] cipher = new byte[5000];
+
+ rand.nextBytes(plain);
+
+ CipherParameters params = new ParametersWithIV(new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), Hex.decode("00000000000000000000000000000000"));
+ SICBlockCipher engine = new SICBlockCipher(new AESEngine());
+
+ engine.init(true, params);
+
+ engine.processBytes(plain, 0, plain.length, cipher, 0);
+
+ byte[] fragment = new byte[20];
+
+ engine.init(true, params);
+
+ engine.skip(10);
+
+ engine.processBytes(plain, 10, fragment.length, fragment, 0);
+
+ if (!areEqual(cipher, 10, fragment, 0))
+ {
+ fail("skip forward 10 failed");
+ }
+
+ engine.skip(1000);
+
+ engine.processBytes(plain, 1010 + fragment.length, fragment.length, fragment, 0);
+
+ if (!areEqual(cipher, 1010 + fragment.length, fragment, 0))
+ {
+ fail("skip forward 1000 failed");
+ }
+
+ engine.skip(-10);
+
+ engine.processBytes(plain, 1010 + 2 * fragment.length - 10, fragment.length, fragment, 0);
+
+ if (!areEqual(cipher, 1010 + 2 * fragment.length - 10, fragment, 0))
+ {
+ fail("skip back 10 failed");
+ }
+
+ engine.skip(-1000);
+
+ engine.processBytes(plain, 60, fragment.length, fragment, 0);
+
+ if (!areEqual(cipher, 60, fragment, 0))
+ {
+ fail("skip back 1000 failed");
+ }
+
+ engine.seekTo(1010);
+
+ engine.processBytes(plain, 1010, fragment.length, fragment, 0);
+
+ if (!areEqual(cipher, 1010, fragment, 0))
+ {
+ fail("seek to 1010 failed");
+ }
+
+ engine.reset();
+
+ for (int i = 0; i != 1000; i++)
+ {
+ engine.skip(i);
+
+ engine.processBytes(plain, i, fragment.length, fragment, 0);
+
+ if (!areEqual(cipher, i, fragment, 0))
+ {
+ fail("skip forward i failed: " + i);
+ }
+
+ engine.skip(-fragment.length);
+
+ engine.processBytes(plain, i, fragment.length, fragment, 0);
+
+ if (!areEqual(cipher, i, fragment, 0))
+ {
+ fail("skip back i failed: " + i);
+ }
+
+ engine.reset();
+ }
+ }
+
public void performTest()
throws Exception
{
@@ -285,6 +391,8 @@ public class AESTest
testNullSIC();
testNullOFB();
testNullCFB();
+
+ skipTest();
}
public static void main(
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Salsa20Test.java b/core/src/test/java/org/bouncycastle/crypto/test/Salsa20Test.java
index 8e1de2c9..e36b679e 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Salsa20Test.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Salsa20Test.java
@@ -333,6 +333,15 @@ public class Salsa20Test
fail("skip back 1000 failed");
}
+ engine.seekTo(1010);
+
+ engine.processBytes(plain, 1010, fragment.length, fragment, 0);
+
+ if (!areEqual(cipher, 1010, fragment, 0))
+ {
+ fail("seek to 1010 failed");
+ }
+
engine.reset();
for (int i = 0; i != 1000; i++)