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
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2014-05-23 07:49:53 +0400
committerDavid Hook <dgh@cryptoworkshop.com>2014-05-23 07:49:53 +0400
commite60d4ef8c6627c6b4a9c0bfccba206ab5ed9d9d5 (patch)
tree695168623f430239c2da79feb7be6b8c722d9daa
parentcb6e7cb081d1db8a3a18bd773f2d81b9b5989c22 (diff)
added EncodableDigest with constructors supporting the same.
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java17
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java23
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java39
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java45
-rw-r--r--core/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java46
-rw-r--r--core/src/test/java/org/bouncycastle/crypto/test/DigestTest.java2
-rw-r--r--core/src/test/java/org/bouncycastle/crypto/test/SHA1DigestTest.java47
-rw-r--r--core/src/test/java/org/bouncycastle/crypto/test/SHA224DigestTest.java39
-rw-r--r--core/src/test/java/org/bouncycastle/crypto/test/SHA256DigestTest.java40
9 files changed, 291 insertions, 7 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java
new file mode 100644
index 00000000..d79fece8
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.crypto.digests;
+
+/**
+ * Encodable digests allow you to download an encoded copy of their internal state. This is useful for the situation where
+ * you need to generate a signature on an external device and it allows for "sign with last round", so a copy of the
+ * internal state of the digest, plus the last few blocks of the message are all that needs to be sent, rather than the
+ * entire message.
+ */
+public interface EncodableDigest
+{
+ /**
+ * Return an encoded byte array for the digest's internal state
+ *
+ * @return an encoding of the digests internal state.
+ */
+ byte[] getEncodedState();
+}
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
index 15f3ebbd..29692bad 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
@@ -2,6 +2,7 @@ package org.bouncycastle.crypto.digests;
import org.bouncycastle.crypto.ExtendedDigest;
import org.bouncycastle.util.Memoable;
+import org.bouncycastle.util.Pack;
/**
* base implementation of MD4 family style digest as outlined in
@@ -11,8 +12,9 @@ public abstract class GeneralDigest
implements ExtendedDigest, Memoable
{
private static final int BYTE_LENGTH = 64;
- private byte[] xBuf;
- private int xBufOff;
+
+ private final byte[] xBuf = new byte[4];
+ private int xBufOff;
private long byteCount;
@@ -21,7 +23,6 @@ public abstract class GeneralDigest
*/
protected GeneralDigest()
{
- xBuf = new byte[4];
xBufOff = 0;
}
@@ -32,11 +33,16 @@ public abstract class GeneralDigest
*/
protected GeneralDigest(GeneralDigest t)
{
- xBuf = new byte[t.xBuf.length];
-
copyIn(t);
}
+ protected GeneralDigest(byte[] encodedState)
+ {
+ System.arraycopy(encodedState, 0, xBuf, 0, xBuf.length);
+ xBufOff = Pack.bigEndianToInt(encodedState, 4);
+ byteCount = Pack.bigEndianToLong(encodedState, 8);
+ }
+
protected void copyIn(GeneralDigest t)
{
System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
@@ -129,6 +135,13 @@ public abstract class GeneralDigest
}
}
+ protected void populateState(byte[] state)
+ {
+ System.arraycopy(xBuf, 0, state, 0, xBufOff);
+ Pack.intToBigEndian(xBufOff, state, 4);
+ Pack.longToBigEndian(byteCount, state, 8);
+ }
+
public int getByteLength()
{
return BYTE_LENGTH;
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java b/core/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
index ff2f5ca2..450dda46 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
@@ -11,6 +11,7 @@ import org.bouncycastle.util.Pack;
*/
public class SHA1Digest
extends GeneralDigest
+ implements EncodableDigest
{
private static final int DIGEST_LENGTH = 20;
@@ -38,6 +39,23 @@ public class SHA1Digest
copyIn(t);
}
+ public SHA1Digest(byte[] encodedState)
+ {
+ super(encodedState);
+
+ H1 = Pack.bigEndianToInt(encodedState, 16);
+ H2 = Pack.bigEndianToInt(encodedState, 20);
+ H3 = Pack.bigEndianToInt(encodedState, 24);
+ H4 = Pack.bigEndianToInt(encodedState, 28);
+ H5 = Pack.bigEndianToInt(encodedState, 32);
+
+ xOff = Pack.bigEndianToInt(encodedState, 36);
+ for (int i = 0; i != xOff; i++)
+ {
+ X[i] = Pack.bigEndianToInt(encodedState, 40 + (i * 4));
+ }
+ }
+
private void copyIn(SHA1Digest t)
{
H1 = t.H1;
@@ -302,6 +320,27 @@ public class SHA1Digest
super.copyIn(d);
copyIn(d);
}
+
+ public byte[] getEncodedState()
+ {
+ byte[] state = new byte[40 + xOff * 4];
+
+ super.populateState(state);
+
+ Pack.intToBigEndian(H1, state, 16);
+ Pack.intToBigEndian(H2, state, 20);
+ Pack.intToBigEndian(H3, state, 24);
+ Pack.intToBigEndian(H4, state, 28);
+ Pack.intToBigEndian(H5, state, 32);
+ Pack.intToBigEndian(xOff, state, 36);
+
+ for (int i = 0; i != xOff; i++)
+ {
+ Pack.intToBigEndian(X[i], state, 40 + (i * 4));
+ }
+
+ return state;
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java b/core/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
index 16550149..4f2b2842 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
@@ -18,6 +18,7 @@ import org.bouncycastle.util.Pack;
*/
public class SHA224Digest
extends GeneralDigest
+ implements EncodableDigest
{
private static final int DIGEST_LENGTH = 28;
@@ -62,6 +63,26 @@ public class SHA224Digest
xOff = t.xOff;
}
+ public SHA224Digest(byte[] encodedState)
+ {
+ super(encodedState);
+
+ H1 = Pack.bigEndianToInt(encodedState, 16);
+ H2 = Pack.bigEndianToInt(encodedState, 20);
+ H3 = Pack.bigEndianToInt(encodedState, 24);
+ H4 = Pack.bigEndianToInt(encodedState, 28);
+ H5 = Pack.bigEndianToInt(encodedState, 32);
+ H6 = Pack.bigEndianToInt(encodedState, 36);
+ H7 = Pack.bigEndianToInt(encodedState, 40);
+ H8 = Pack.bigEndianToInt(encodedState, 44);
+
+ xOff = Pack.bigEndianToInt(encodedState, 48);
+ for (int i = 0; i != xOff; i++)
+ {
+ X[i] = Pack.bigEndianToInt(encodedState, 52 + (i * 4));
+ }
+ }
+
public String getAlgorithmName()
{
return "SHA-224";
@@ -307,5 +328,29 @@ public class SHA224Digest
doCopy(d);
}
+
+ public byte[] getEncodedState()
+ {
+ byte[] state = new byte[52 + xOff * 4];
+
+ super.populateState(state);
+
+ Pack.intToBigEndian(H1, state, 16);
+ Pack.intToBigEndian(H2, state, 20);
+ Pack.intToBigEndian(H3, state, 24);
+ Pack.intToBigEndian(H4, state, 28);
+ Pack.intToBigEndian(H5, state, 32);
+ Pack.intToBigEndian(H6, state, 36);
+ Pack.intToBigEndian(H7, state, 40);
+ Pack.intToBigEndian(H8, state, 44);
+ Pack.intToBigEndian(xOff, state, 48);
+
+ for (int i = 0; i != xOff; i++)
+ {
+ Pack.intToBigEndian(X[i], state, 52 + (i * 4));
+ }
+
+ return state;
+ }
}
diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java b/core/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
index e3dd4c37..600d2343 100644
--- a/core/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
+++ b/core/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
@@ -18,6 +18,7 @@ import org.bouncycastle.util.Pack;
*/
public class SHA256Digest
extends GeneralDigest
+ implements EncodableDigest
{
private static final int DIGEST_LENGTH = 32;
@@ -62,6 +63,27 @@ public class SHA256Digest
xOff = t.xOff;
}
+ public SHA256Digest(byte[] encodedState)
+ {
+ super(encodedState);
+
+ H1 = Pack.bigEndianToInt(encodedState, 16);
+ H2 = Pack.bigEndianToInt(encodedState, 20);
+ H3 = Pack.bigEndianToInt(encodedState, 24);
+ H4 = Pack.bigEndianToInt(encodedState, 28);
+ H5 = Pack.bigEndianToInt(encodedState, 32);
+ H6 = Pack.bigEndianToInt(encodedState, 36);
+ H7 = Pack.bigEndianToInt(encodedState, 40);
+ H8 = Pack.bigEndianToInt(encodedState, 44);
+
+ xOff = Pack.bigEndianToInt(encodedState, 48);
+ for (int i = 0; i != xOff; i++)
+ {
+ X[i] = Pack.bigEndianToInt(encodedState, 52 + (i * 4));
+ }
+ }
+
+
public String getAlgorithmName()
{
return "SHA-256";
@@ -310,5 +332,29 @@ public class SHA256Digest
copyIn(d);
}
+
+ public byte[] getEncodedState()
+ {
+ byte[] state = new byte[52 + xOff * 4];
+
+ super.populateState(state);
+
+ Pack.intToBigEndian(H1, state, 16);
+ Pack.intToBigEndian(H2, state, 20);
+ Pack.intToBigEndian(H3, state, 24);
+ Pack.intToBigEndian(H4, state, 28);
+ Pack.intToBigEndian(H5, state, 32);
+ Pack.intToBigEndian(H6, state, 36);
+ Pack.intToBigEndian(H7, state, 40);
+ Pack.intToBigEndian(H8, state, 44);
+ Pack.intToBigEndian(xOff, state, 48);
+
+ for (int i = 0; i != xOff; i++)
+ {
+ Pack.intToBigEndian(X[i], state, 52 + (i * 4));
+ }
+
+ return state;
+ }
}
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/DigestTest.java b/core/src/test/java/org/bouncycastle/crypto/test/DigestTest.java
index 746a308d..be115325 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/DigestTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/DigestTest.java
@@ -107,7 +107,7 @@ public abstract class DigestTest
}
}
- private byte[] toByteArray(String input)
+ protected byte[] toByteArray(String input)
{
byte[] bytes = new byte[input.length()];
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SHA1DigestTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SHA1DigestTest.java
index 9bcba664..2b002c43 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/SHA1DigestTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/SHA1DigestTest.java
@@ -2,6 +2,7 @@ package org.bouncycastle.crypto.test;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.util.encoders.Hex;
/**
* standard vector test for SHA-1 from "Handbook of Applied Cryptography", page 345.
@@ -34,7 +35,51 @@ public class SHA1DigestTest
{
return new SHA1Digest((SHA1Digest)digest);
}
-
+
+ public void performTest()
+ {
+ super.performTest();
+
+ // test state encoding;
+
+ byte[] lastV = toByteArray(messages[messages.length - 1]);
+ byte[] lastDigest = Hex.decode(digests[digests.length - 1]);
+
+ SHA1Digest digest = new SHA1Digest();
+ byte[] resBuf = new byte[digest.getDigestSize()];
+
+ digest.update(lastV, 0, lastV.length/2);
+
+ // copy the Digest
+ SHA1Digest copy1 = new SHA1Digest(digest.getEncodedState());
+ SHA1Digest copy2 = new SHA1Digest(copy1.getEncodedState());
+
+ digest.update(lastV, lastV.length / 2, lastV.length - lastV.length / 2);
+
+ digest.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing state vector test", digests[digests.length - 1], new String(Hex.encode(resBuf)));
+ }
+
+ copy1.update(lastV, lastV.length/2, lastV.length - lastV.length/2);
+ copy1.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing state copy1 vector test", digests[digests.length - 1], new String(Hex.encode(resBuf)));
+ }
+
+ copy2.update(lastV, lastV.length / 2, lastV.length - lastV.length / 2);
+ copy2.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing state copy2 vector test", digests[digests.length - 1], new String(Hex.encode(resBuf)));
+ }
+ }
+
public static void main(
String[] args)
{
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SHA224DigestTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SHA224DigestTest.java
index c352bad0..1f3f6b05 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/SHA224DigestTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/SHA224DigestTest.java
@@ -2,6 +2,7 @@ package org.bouncycastle.crypto.test;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.util.encoders.Hex;
/**
* standard vector test for SHA-224 from RFC 3874 - only the last three are in
@@ -39,6 +40,44 @@ public class SHA224DigestTest
super.performTest();
millionATest(million_a_digest);
+
+ // test state encoding;
+ byte[] lastV = toByteArray(messages[messages.length - 1]);
+ byte[] lastDigest = Hex.decode(digests[digests.length - 1]);
+
+ SHA224Digest digest = new SHA224Digest();
+ byte[] resBuf = new byte[digest.getDigestSize()];
+
+ digest.update(lastV, 0, lastV.length/2);
+
+ // copy the Digest
+ SHA224Digest copy1 = new SHA224Digest(digest.getEncodedState());
+ SHA224Digest copy2 = new SHA224Digest(copy1.getEncodedState());
+
+ digest.update(lastV, lastV.length / 2, lastV.length - lastV.length / 2);
+
+ digest.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing state vector test", digests[digests.length - 1], new String(Hex.encode(resBuf)));
+ }
+
+ copy1.update(lastV, lastV.length/2, lastV.length - lastV.length/2);
+ copy1.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing state copy1 vector test", digests[digests.length - 1], new String(Hex.encode(resBuf)));
+ }
+
+ copy2.update(lastV, lastV.length / 2, lastV.length - lastV.length / 2);
+ copy2.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing state copy2 vector test", digests[digests.length - 1], new String(Hex.encode(resBuf)));
+ }
}
protected Digest cloneDigest(Digest digest)
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SHA256DigestTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SHA256DigestTest.java
index a2f87292..15293968 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/SHA256DigestTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/SHA256DigestTest.java
@@ -2,6 +2,7 @@ package org.bouncycastle.crypto.test;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.util.encoders.Hex;
/**
* standard vector test for SHA-256 from FIPS Draft 180-2.
@@ -40,6 +41,45 @@ public class SHA256DigestTest
super.performTest();
millionATest(million_a_digest);
+
+ // test state encoding;
+
+ byte[] lastV = toByteArray(messages[messages.length - 1]);
+ byte[] lastDigest = Hex.decode(digests[digests.length - 1]);
+
+ SHA256Digest digest = new SHA256Digest();
+ byte[] resBuf = new byte[digest.getDigestSize()];
+
+ digest.update(lastV, 0, lastV.length/2);
+
+ // copy the Digest
+ SHA256Digest copy1 = new SHA256Digest(digest.getEncodedState());
+ SHA256Digest copy2 = new SHA256Digest(copy1.getEncodedState());
+
+ digest.update(lastV, lastV.length / 2, lastV.length - lastV.length / 2);
+
+ digest.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing state vector test", digests[digests.length - 1], new String(Hex.encode(resBuf)));
+ }
+
+ copy1.update(lastV, lastV.length/2, lastV.length - lastV.length/2);
+ copy1.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing state copy1 vector test", digests[digests.length - 1], new String(Hex.encode(resBuf)));
+ }
+
+ copy2.update(lastV, lastV.length / 2, lastV.length - lastV.length / 2);
+ copy2.doFinal(resBuf, 0);
+
+ if (!areEqual(lastDigest, resBuf))
+ {
+ fail("failing state copy2 vector test", digests[digests.length - 1], new String(Hex.encode(resBuf)));
+ }
}
protected Digest cloneDigest(Digest digest)