Skip to content

Commit 160db88

Browse files
committed
added SavableDigest support to CSHAKE, SHAKE
minor changes to support in SHA3 to accomodate.
1 parent 0d55ad5 commit 160db88

File tree

6 files changed

+231
-65
lines changed

6 files changed

+231
-65
lines changed

core/src/main/java/org/bouncycastle/crypto/digests/CSHAKEDigest.java

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.bouncycastle.crypto.CryptoServicePurpose;
44
import org.bouncycastle.util.Arrays;
5+
import org.bouncycastle.util.Memoable;
56

67
/**
78
* Customizable SHAKE function.
@@ -10,7 +11,8 @@ public class CSHAKEDigest
1011
extends SHAKEDigest
1112
{
1213
private static final byte[] padding = new byte[100];
13-
private final byte[] diff;
14+
15+
private byte[] diff;
1416

1517
/**
1618
* Base constructor.
@@ -54,6 +56,29 @@ public CSHAKEDigest(CSHAKEDigest source)
5456
this.diff = Arrays.clone(source.diff);
5557
}
5658

59+
public CSHAKEDigest(byte[] encodedState)
60+
{
61+
super(encodedState);
62+
63+
int sha3StateLength = state.length * 8 + dataQueue.length + 12 + 2;
64+
if (encodedState.length != sha3StateLength)
65+
{
66+
this.diff = new byte[encodedState.length - sha3StateLength];
67+
System.arraycopy(encodedState, sha3StateLength, diff, 0, diff.length);
68+
}
69+
else
70+
{
71+
this.diff = null;
72+
}
73+
}
74+
75+
private void copyIn(CSHAKEDigest source)
76+
{
77+
super.copyIn(source);
78+
79+
this.diff = Arrays.clone(source.diff);
80+
}
81+
5782
// bytepad in SP 800-185
5883
private void diffPadAndAbsorb()
5984
{
@@ -120,4 +145,36 @@ public void reset()
120145
diffPadAndAbsorb();
121146
}
122147
}
148+
149+
public byte[] getEncodedState()
150+
{
151+
int sha3StateLength = state.length * 8 + dataQueue.length + 12 + 2;
152+
byte[] encState;
153+
154+
if (diff == null)
155+
{
156+
encState = new byte[sha3StateLength];
157+
super.getEncodedState(encState);
158+
}
159+
else
160+
{
161+
encState = new byte[sha3StateLength + diff.length];
162+
super.getEncodedState(encState);
163+
System.arraycopy(diff, 0, encState, sha3StateLength, diff.length);
164+
}
165+
166+
return encState;
167+
}
168+
169+
public Memoable copy()
170+
{
171+
return new CSHAKEDigest(this);
172+
}
173+
174+
public void reset(Memoable other)
175+
{
176+
CSHAKEDigest d = (CSHAKEDigest)other;
177+
178+
copyIn(d);
179+
}
123180
}

core/src/main/java/org/bouncycastle/crypto/digests/KeccakDigest.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,47 @@ public KeccakDigest(KeccakDigest source)
6666
CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
6767
}
6868

69+
protected KeccakDigest(byte[] encodedState)
70+
{
71+
purpose = getCryptoServicePurpose(encodedState[0]);
72+
73+
int encOff = 1;
74+
Pack.bigEndianToLong(encodedState, encOff, state, 0, state.length);
75+
encOff += state.length * 8;
76+
System.arraycopy(encodedState, encOff, dataQueue, 0, dataQueue.length);
77+
encOff += dataQueue.length;
78+
rate = Pack.bigEndianToInt(encodedState, encOff);
79+
encOff += 4;
80+
bitsInQueue = Pack.bigEndianToInt(encodedState, encOff);
81+
encOff += 4;
82+
fixedOutputLength = Pack.bigEndianToInt(encodedState, encOff);
83+
encOff += 4;
84+
squeezing = encodedState[encOff] != 0;
85+
}
86+
87+
private static CryptoServicePurpose getCryptoServicePurpose(byte b)
88+
{
89+
CryptoServicePurpose[] values = CryptoServicePurpose.values();
90+
return values[b];
91+
}
92+
93+
protected void copyIn(KeccakDigest source)
94+
{
95+
if (this.purpose != source.purpose)
96+
{
97+
throw new IllegalArgumentException("attempt to copy digest of different purpose");
98+
}
99+
100+
System.arraycopy(source.state, 0, this.state, 0, source.state.length);
101+
System.arraycopy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.length);
102+
this.rate = source.rate;
103+
this.bitsInQueue = source.bitsInQueue;
104+
this.fixedOutputLength = source.fixedOutputLength;
105+
this.squeezing = source.squeezing;
106+
107+
CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
108+
}
109+
69110
public String getAlgorithmName()
70111
{
71112
return "Keccak-" + fixedOutputLength;
@@ -440,4 +481,29 @@ protected CryptoServiceProperties cryptoServiceProperties()
440481
{
441482
return Utils.getDefaultProperties(this, getDigestSize() * 8, purpose);
442483
}
484+
485+
protected byte[] getEncodedState(byte[] encState)
486+
{
487+
encState[0] = (byte)purpose.ordinal();
488+
489+
int sOff = 1;
490+
for (int i = 0; i != state.length; i++)
491+
{
492+
Pack.longToBigEndian(state[i], encState, sOff);
493+
sOff += 8;
494+
}
495+
496+
System.arraycopy(dataQueue, 0, encState, sOff, dataQueue.length);
497+
498+
sOff += dataQueue.length;
499+
Pack.intToBigEndian(rate, encState, sOff);
500+
sOff += 4;
501+
Pack.intToBigEndian(bitsInQueue, encState, sOff);
502+
sOff += 4;
503+
Pack.intToBigEndian(fixedOutputLength, encState, sOff);
504+
sOff += 4;
505+
encState[sOff] = squeezing ? (byte)1 : (byte)0;
506+
507+
return encState;
508+
}
443509
}

core/src/main/java/org/bouncycastle/crypto/digests/SHA3Digest.java

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package org.bouncycastle.crypto.digests;
22

33
import org.bouncycastle.crypto.CryptoServicePurpose;
4-
import org.bouncycastle.crypto.CryptoServicesRegistrar;
54
import org.bouncycastle.crypto.SavableDigest;
65
import org.bouncycastle.util.Memoable;
7-
import org.bouncycastle.util.Pack;
86

97
/**
108
* implementation of SHA-3 based on following KeccakNISTInterface.c from https://keccak.noekeon.org/
@@ -51,49 +49,14 @@ public SHA3Digest(int bitLength, CryptoServicePurpose purpose)
5149

5250
public SHA3Digest(byte[] encodedState)
5351
{
54-
super(getCryptoServicePurpose(encodedState[encodedState.length - 1]));
55-
56-
Pack.bigEndianToLong(encodedState, 0, state, 0, state.length);
57-
int encOff = state.length * 8;
58-
System.arraycopy(encodedState, encOff, dataQueue, 0, dataQueue.length);
59-
encOff += dataQueue.length;
60-
rate = Pack.bigEndianToInt(encodedState, encOff);
61-
encOff += 4;
62-
bitsInQueue = Pack.bigEndianToInt(encodedState, encOff);
63-
encOff += 4;
64-
fixedOutputLength = Pack.bigEndianToInt(encodedState, encOff);
65-
encOff += 4;
66-
squeezing = encodedState[encOff] != 0;
67-
}
68-
69-
private static CryptoServicePurpose getCryptoServicePurpose(byte b)
70-
{
71-
CryptoServicePurpose[] values = CryptoServicePurpose.values();
72-
return values[b];
52+
super(encodedState);
7353
}
7454

7555
public SHA3Digest(SHA3Digest source)
7656
{
7757
super(source);
7858
}
7959

80-
private void copyIn(SHA3Digest source)
81-
{
82-
if (this.purpose != source.purpose)
83-
{
84-
throw new IllegalArgumentException("attempt to copy digest of different purpose");
85-
}
86-
87-
System.arraycopy(source.state, 0, this.state, 0, source.state.length);
88-
System.arraycopy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.length);
89-
this.rate = source.rate;
90-
this.bitsInQueue = source.bitsInQueue;
91-
this.fixedOutputLength = source.fixedOutputLength;
92-
this.squeezing = source.squeezing;
93-
94-
CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
95-
}
96-
9760
public String getAlgorithmName()
9861
{
9962
return "SHA3-" + fixedOutputLength;
@@ -133,24 +96,8 @@ public byte[] getEncodedState()
13396
{
13497
byte[] encState = new byte[state.length * 8 + dataQueue.length + 12 + 2];
13598

136-
for (int i = 0; i != state.length; i++)
137-
{
138-
Pack.longToBigEndian(state[i], encState, i * 8);
139-
}
140-
141-
int sOff = state.length * 8;
142-
System.arraycopy(dataQueue, 0, encState, sOff, dataQueue.length);
143-
144-
sOff += dataQueue.length;
145-
Pack.intToBigEndian(rate, encState, sOff);
146-
sOff += 4;
147-
Pack.intToBigEndian(bitsInQueue, encState, sOff);
148-
sOff += 4;
149-
Pack.intToBigEndian(fixedOutputLength, encState, sOff);
150-
sOff += 4;
151-
encState[sOff++] = squeezing ? (byte)1 : (byte)0;
152-
encState[sOff] = (byte)purpose.ordinal();
153-
99+
super.getEncodedState(encState);
100+
154101
return encState;
155102
}
156103

core/src/main/java/org/bouncycastle/crypto/digests/SHAKEDigest.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import org.bouncycastle.crypto.CryptoServiceProperties;
44
import org.bouncycastle.crypto.CryptoServicePurpose;
5+
import org.bouncycastle.crypto.SavableDigest;
56
import org.bouncycastle.crypto.Xof;
7+
import org.bouncycastle.util.Memoable;
68

79

810
/**
@@ -12,7 +14,7 @@
1214
*/
1315
public class SHAKEDigest
1416
extends KeccakDigest
15-
implements Xof
17+
implements Xof, SavableDigest
1618
{
1719
private static int checkBitLength(int bitStrength)
1820
{
@@ -67,6 +69,11 @@ public SHAKEDigest(SHAKEDigest source)
6769
super(source);
6870
}
6971

72+
public SHAKEDigest(byte[] encodedState)
73+
{
74+
super(encodedState);
75+
}
76+
7077
public String getAlgorithmName()
7178
{
7279
return "SHAKE" + fixedOutputLength;
@@ -147,4 +154,25 @@ protected CryptoServiceProperties cryptoServiceProperties()
147154
{
148155
return Utils.getDefaultProperties(this, purpose);
149156
}
157+
158+
public byte[] getEncodedState()
159+
{
160+
byte[] encState = new byte[state.length * 8 + dataQueue.length + 12 + 2];
161+
162+
super.getEncodedState(encState);
163+
164+
return encState;
165+
}
166+
167+
public Memoable copy()
168+
{
169+
return new SHAKEDigest(this);
170+
}
171+
172+
public void reset(Memoable other)
173+
{
174+
SHAKEDigest d = (SHAKEDigest)other;
175+
176+
copyIn(d);
177+
}
150178
}

core/src/test/java/org/bouncycastle/crypto/test/CSHAKETest.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,60 @@
11
package org.bouncycastle.crypto.test;
22

3+
import org.bouncycastle.crypto.Digest;
34
import org.bouncycastle.crypto.digests.CSHAKEDigest;
45
import org.bouncycastle.crypto.digests.SHAKEDigest;
56
import org.bouncycastle.util.Arrays;
67
import org.bouncycastle.util.Strings;
78
import org.bouncycastle.util.encoders.Hex;
8-
import org.bouncycastle.util.test.SimpleTest;
99

1010
/**
1111
* CSHAKE test vectors from:
1212
*
1313
* https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf
1414
*/
1515
public class CSHAKETest
16-
extends SimpleTest
16+
extends DigestTest
1717
{
18+
private static String[] messages =
19+
{
20+
"",
21+
"a",
22+
"abc",
23+
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
24+
};
25+
26+
private static String[] digests =
27+
{
28+
"28a0e58d342a45ef1522d69cd41748beee29c188364df18c84ed4ab8bed0cc85",
29+
"cb0a67f6ff4a3b64497a757a85bda4a275cf11970ff226abd2bf2bbcba5890ea",
30+
"346c136daea11c436d8d9e668e08888bd4e341dae05da4cb8773f74402c5bdbc",
31+
"64602dc88c880bdfb6d0c9163a72b2e3653ab6114e4f4e25d7aaf5b8d441e36f"
32+
};
33+
34+
public CSHAKETest()
35+
{
36+
super(new CSHAKEDigest(128, new byte[1], new byte[1]), messages, digests);
37+
}
38+
1839
public String getName()
1940
{
2041
return "CSHAKE";
2142
}
2243

44+
protected Digest cloneDigest(Digest digest)
45+
{
46+
return new CSHAKEDigest((CSHAKEDigest)digest);
47+
}
48+
49+
protected Digest cloneDigest(byte[] encodedState)
50+
{
51+
return new CSHAKEDigest(encodedState);
52+
}
53+
2354
public void performTest()
24-
throws Exception
2555
{
56+
super.performTest();
57+
2658
CSHAKEDigest cshake = new CSHAKEDigest(128, new byte[0], Strings.toByteArray("Email Signature"));
2759

2860
cshake.update(Hex.decode("00010203"), 0, 4);

0 commit comments

Comments
 (0)