3434
3535import jdk .internal .vm .annotation .IntrinsicCandidate ;
3636
37+ import static java .lang .Math .min ;
38+
3739/**
3840 * This class implements the Secure Hash Algorithm SHA-3 developed by
3941 * the National Institute of Standards and Technology along with the
4648 * @since 9
4749 * @author Valerie Peng
4850 */
49- abstract class SHA3 extends DigestBase {
51+ public abstract class SHA3 extends DigestBase {
5052
5153 private static final int WIDTH = 200 ; // in bytes, e.g. 1600 bits
5254 private static final int DM = 5 ; // dimension of state matrix
@@ -65,17 +67,32 @@ abstract class SHA3 extends DigestBase {
6567 0x8000000000008080L , 0x80000001L , 0x8000000080008008L ,
6668 };
6769
70+ // The starting byte combining the 2 or 4-bit domain separator and
71+ // leading bits of the 10*1 padding, see Table 6 in B.2 of FIPS PUB 202
72+ // for examples
6873 private final byte suffix ;
74+
75+ // the state matrix flattened into an array
6976 private long [] state = new long [DM *DM ];
7077
78+ // The byte offset in the state where the next squeeze() will start.
79+ // -1 indicates that either we are in the absorbing phase (only
80+ // update() calls were made so far) in an extendable-output function (XOF)
81+ // or the class was initialized as a hash.
82+ // The first squeeze() call (after a possibly empty sequence of update()
83+ // calls) will set it to 0 at its start.
84+ // When a squeeze() call uses up all available bytes from this state
85+ // and so a new keccak() call is made, squeezeOffset is reset to 0.
86+ protected int squeezeOffset = -1 ;
87+
7188 static final VarHandle asLittleEndian
7289 = MethodHandles .byteArrayViewVarHandle (long [].class ,
7390 ByteOrder .LITTLE_ENDIAN ).withInvokeExactBehavior ();
7491
7592 /**
7693 * Creates a new SHA-3 object.
7794 */
78- SHA3 (String name , int digestLength , byte suffix , int c ) {
95+ private SHA3 (String name , int digestLength , byte suffix , int c ) {
7996 super (name , digestLength , (WIDTH - c ));
8097 this .suffix = suffix ;
8198 }
@@ -103,54 +120,141 @@ private void implCompress0(byte[] b, int ofs) {
103120 keccak ();
104121 }
105122
123+ void finishAbsorb () {
124+ int numOfPadding =
125+ setPaddingBytes (suffix , buffer , (int )(bytesProcessed % blockSize ));
126+ if (numOfPadding < 1 ) {
127+ throw new ProviderException ("Incorrect pad size: " + numOfPadding );
128+ }
129+ implCompress (buffer , 0 );
130+ }
131+
106132 /**
107133 * Return the digest. Subclasses do not need to reset() themselves,
108134 * DigestBase calls implReset() when necessary.
109135 */
110136 void implDigest (byte [] out , int ofs ) {
137+ // Moving this allocation to the block where it is used causes a little
138+ // performance drop, that is why it is here.
111139 byte [] byteState = new byte [8 ];
112- int numOfPadding =
113- setPaddingBytes (suffix , buffer , (int )(bytesProcessed % blockSize ));
114- if (numOfPadding < 1 ) {
115- throw new ProviderException ("Incorrect pad size: " + numOfPadding );
140+ if (engineGetDigestLength () == 0 ) {
141+ // This is an XOF, so the digest() call is illegal.
142+ throw new ProviderException ("Calling digest() is not allowed in an XOF" );
116143 }
117- implCompress (buffer , 0 );
118- int availableBytes = blockSize ; // i.e. buffer.length
144+
145+ finishAbsorb ();
146+
147+ int availableBytes = blockSize ;
119148 int numBytes = engineGetDigestLength ();
149+
120150 while (numBytes > availableBytes ) {
121- for (int i = 0 ; i < availableBytes / 8 ; i ++) {
151+ for (int i = 0 ; i < availableBytes / 8 ; i ++) {
122152 asLittleEndian .set (out , ofs , state [i ]);
123153 ofs += 8 ;
124154 }
125155 numBytes -= availableBytes ;
126156 keccak ();
127157 }
128- int numLongs = ( numBytes + 7 ) / 8 ;
158+ int numLongs = numBytes / 8 ;
129159
130- for (int i = 0 ; i < numLongs - 1 ; i ++) {
160+ for (int i = 0 ; i < numLongs ; i ++) {
131161 asLittleEndian .set (out , ofs , state [i ]);
132162 ofs += 8 ;
133163 }
134- if (numBytes == numLongs * 8 ) {
135- asLittleEndian .set (out , ofs , state [numLongs - 1 ]);
136- } else {
137- asLittleEndian .set (byteState , 0 , state [numLongs - 1 ]);
138- System .arraycopy (byteState , 0 ,
139- out , ofs , numBytes - (numLongs - 1 ) * 8 );
164+ if (numBytes % 8 != 0 ) {
165+ asLittleEndian .set (byteState , 0 , state [numLongs ]);
166+ System .arraycopy (byteState , 0 , out , ofs , numBytes % 8 );
140167 }
141168 }
142169
170+ void implSqueeze (byte [] output , int offset , int numBytes ) {
171+ // Moving this allocation to the block where it is used causes a little
172+ // performance drop, that is why it is here.
173+ byte [] byteState = new byte [8 ];
174+ if (engineGetDigestLength () != 0 ) {
175+ // This is not an XOF, so the squeeze() call is illegal.
176+ throw new ProviderException ("Squeezing is only allowed in XOF mode." );
177+ }
178+
179+ if (squeezeOffset == -1 ) {
180+ finishAbsorb ();
181+ squeezeOffset = 0 ;
182+ }
183+
184+ int availableBytes = blockSize - squeezeOffset ;
185+
186+ while (numBytes > availableBytes ) {
187+ int longOffset = squeezeOffset / 8 ;
188+ int bytesToCopy = 0 ;
189+
190+ if (longOffset * 8 < squeezeOffset ) {
191+ asLittleEndian .set (byteState , 0 , state [longOffset ]);
192+ longOffset ++;
193+ bytesToCopy = longOffset * 8 - squeezeOffset ;
194+ System .arraycopy (byteState , 8 - bytesToCopy ,
195+ output , offset , bytesToCopy );
196+ offset += bytesToCopy ;
197+ }
198+ for (int i = longOffset ; i < blockSize / 8 ; i ++) {
199+ asLittleEndian .set (output , offset , state [i ]);
200+ offset += 8 ;
201+ }
202+ keccak ();
203+ squeezeOffset = 0 ;
204+ numBytes -= availableBytes ;
205+ availableBytes = blockSize ;
206+ }
207+ // now numBytes <= availableBytes
208+ int longOffset = squeezeOffset / 8 ;
209+
210+ if (longOffset * 8 < squeezeOffset ) {
211+ asLittleEndian .set (byteState , 0 , state [longOffset ]);
212+ int bytesToCopy = min ((longOffset + 1 ) * 8 - squeezeOffset , numBytes );
213+ System .arraycopy (byteState , squeezeOffset - 8 * longOffset ,
214+ output , offset , bytesToCopy );
215+ longOffset ++;
216+ numBytes -= bytesToCopy ;
217+ offset += bytesToCopy ;
218+ squeezeOffset += bytesToCopy ;
219+
220+ if (numBytes == 0 ) return ;
221+ }
222+
223+ int numLongs = numBytes / 8 ;
224+
225+ for (int i = longOffset ; i < longOffset + numLongs ; i ++) {
226+ asLittleEndian .set (output , offset , state [i ]);
227+ offset += 8 ;
228+ numBytes -= 8 ;
229+ squeezeOffset += 8 ;
230+ }
231+
232+ if (numBytes > 0 ) {
233+ asLittleEndian .set (byteState , 0 , state [squeezeOffset / 8 ]);
234+ System .arraycopy (byteState , 0 , output , offset , numBytes );
235+ squeezeOffset += numBytes ;
236+ }
237+ }
238+
239+ byte [] implSqueeze (int numBytes ) {
240+ byte [] result = new byte [numBytes ];
241+ implSqueeze (result , 0 , numBytes );
242+ return result ;
243+ }
244+
143245 /**
144246 * Resets the internal state to start a new hash.
145247 */
146248 void implReset () {
147249 Arrays .fill (state , 0L );
250+ squeezeOffset = -1 ;
148251 }
149252
150253 /**
151254 * Utility function for padding the specified data based on the
152- * pad10*1 algorithm (section 5.1) and the 2-bit suffix "01" required
153- * for SHA-3 hash (section 6.1).
255+ * pad10*1 algorithm (section 5.1) and the 2-bit suffix "01" or 4-bit
256+ * suffix "1111" required for SHA-3 hash functions (section 6.1) and
257+ * extendable-output functions (section 6.1) respectively.
154258 */
155259 private static int setPaddingBytes (byte suffix , byte [] in , int len ) {
156260 if (len != in .length ) {
@@ -169,16 +273,20 @@ private static int setPaddingBytes(byte suffix, byte[] in, int len) {
169273 * rate r = 1600 and capacity c.
170274 */
171275 private void keccak () {
276+ keccak (state );
277+ }
278+
279+ public static void keccak (long [] stateArr ) {
172280 long a0 , a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 , a10 , a11 , a12 ;
173281 long a13 , a14 , a15 , a16 , a17 , a18 , a19 , a20 , a21 , a22 , a23 , a24 ;
174282 // move data into local variables
175- a0 = state [0 ]; a1 = state [1 ]; a2 = state [2 ]; a3 = state [3 ]; a4 = state [4 ];
176- a5 = state [5 ]; a6 = state [6 ]; a7 = state [7 ]; a8 = state [8 ]; a9 = state [9 ];
177- a10 = state [10 ]; a11 = state [11 ]; a12 = state [12 ]; a13 = state [13 ]; a14 = state [14 ];
178- a15 = state [15 ]; a16 = state [16 ]; a17 = state [17 ]; a18 = state [18 ]; a19 = state [19 ];
179- a20 = state [20 ]; a21 = state [21 ]; a22 = state [22 ]; a23 = state [23 ]; a24 = state [24 ];
283+ a0 = stateArr [0 ]; a1 = stateArr [1 ]; a2 = stateArr [2 ]; a3 = stateArr [3 ]; a4 = stateArr [4 ];
284+ a5 = stateArr [5 ]; a6 = stateArr [6 ]; a7 = stateArr [7 ]; a8 = stateArr [8 ]; a9 = stateArr [9 ];
285+ a10 = stateArr [10 ]; a11 = stateArr [11 ]; a12 = stateArr [12 ]; a13 = stateArr [13 ]; a14 = stateArr [14 ];
286+ a15 = stateArr [15 ]; a16 = stateArr [16 ]; a17 = stateArr [17 ]; a18 = stateArr [18 ]; a19 = stateArr [19 ];
287+ a20 = stateArr [20 ]; a21 = stateArr [21 ]; a22 = stateArr [22 ]; a23 = stateArr [23 ]; a24 = stateArr [24 ];
180288
181- // process the lanes through step mappings
289+ // process the stateArr through step mappings
182290 for (int ir = 0 ; ir < NR ; ir ++) {
183291 // Step mapping Theta as defined in section 3.2.1.
184292 long c0 = a0 ^a5 ^a10 ^a15 ^a20 ;
@@ -280,11 +388,11 @@ private void keccak() {
280388 a0 ^= RC_CONSTANTS [ir ];
281389 }
282390
283- state [0 ] = a0 ; state [1 ] = a1 ; state [2 ] = a2 ; state [3 ] = a3 ; state [4 ] = a4 ;
284- state [5 ] = a5 ; state [6 ] = a6 ; state [7 ] = a7 ; state [8 ] = a8 ; state [9 ] = a9 ;
285- state [10 ] = a10 ; state [11 ] = a11 ; state [12 ] = a12 ; state [13 ] = a13 ; state [14 ] = a14 ;
286- state [15 ] = a15 ; state [16 ] = a16 ; state [17 ] = a17 ; state [18 ] = a18 ; state [19 ] = a19 ;
287- state [20 ] = a20 ; state [21 ] = a21 ; state [22 ] = a22 ; state [23 ] = a23 ; state [24 ] = a24 ;
391+ stateArr [0 ] = a0 ; stateArr [1 ] = a1 ; stateArr [2 ] = a2 ; stateArr [3 ] = a3 ; stateArr [4 ] = a4 ;
392+ stateArr [5 ] = a5 ; stateArr [6 ] = a6 ; stateArr [7 ] = a7 ; stateArr [8 ] = a8 ; stateArr [9 ] = a9 ;
393+ stateArr [10 ] = a10 ; stateArr [11 ] = a11 ; stateArr [12 ] = a12 ; stateArr [13 ] = a13 ; stateArr [14 ] = a14 ;
394+ stateArr [15 ] = a15 ; stateArr [16 ] = a16 ; stateArr [17 ] = a17 ; stateArr [18 ] = a18 ; stateArr [19 ] = a19 ;
395+ stateArr [20 ] = a20 ; stateArr [21 ] = a21 ; stateArr [22 ] = a22 ; stateArr [23 ] = a23 ; stateArr [24 ] = a24 ;
288396 }
289397
290398 public Object clone () throws CloneNotSupportedException {
@@ -328,4 +436,85 @@ public SHA512() {
328436 super ("SHA3-512" , 64 , (byte )0x06 , 128 );
329437 }
330438 }
439+
440+ public abstract static class SHA3XOF extends SHA3 {
441+ public SHA3XOF (String name , int digestLength , byte offset , int c ) {
442+ super (name , digestLength , offset , c );
443+ }
444+ public void update (byte in ) {
445+ if (squeezeOffset != -1 ) {
446+ throw new ProviderException ("update() after squeeze() is not allowed." );
447+ }
448+ engineUpdate (in );
449+ }
450+ public void update (byte [] in , int off , int len ) {
451+ if (squeezeOffset != -1 ) {
452+ throw new ProviderException ("update() after squeeze() is not allowed." );
453+ }
454+ engineUpdate (in , off , len );
455+ }
456+
457+ public void update (byte [] in ) {
458+ if (squeezeOffset != -1 ) {
459+ throw new ProviderException ("update() after squeeze() is not allowed." );
460+ }
461+ engineUpdate (in , 0 , in .length );
462+ }
463+
464+ public byte [] digest () {
465+ return engineDigest ();
466+ }
467+
468+ public void squeeze (byte [] output , int offset , int numBytes ) {
469+ implSqueeze (output , offset , numBytes );
470+ }
471+ public byte [] squeeze (int numBytes ) {
472+ return implSqueeze (numBytes );
473+ }
474+
475+ public void reset () {
476+ engineReset ();
477+ }
478+ }
479+
480+ /*
481+ * The SHAKE128 extendable output function.
482+ */
483+ public static final class SHAKE128 extends SHA3XOF {
484+ // d is the required number of output bytes.
485+ // If this constructor is used with d > 0, the squeezing methods
486+ // will throw a ProviderException.
487+ public SHAKE128 (int d ) {
488+ super ("SHAKE128" , d , (byte ) 0x1F , 32 );
489+ }
490+
491+ // If this constructor is used to get an instance of the class, then,
492+ // after the last update, one can get the generated bytes using the
493+ // squeezing methods.
494+ // Calling digest method will throw a ProviderException.
495+ public SHAKE128 () {
496+ super ("SHAKE128" , 0 , (byte ) 0x1F , 32 );
497+ }
498+ }
499+
500+ /*
501+ * The SHAKE256 extendable output function.
502+ */
503+ public static final class SHAKE256 extends SHA3XOF {
504+ // d is the required number of output bytes.
505+ // If this constructor is used with d > 0, the squeezing methods will
506+ // throw a ProviderException.
507+ public SHAKE256 (int d ) {
508+ super ("SHAKE256" , d , (byte ) 0x1F , 64 );
509+ }
510+
511+ // If this constructor is used to get an instance of the class, then,
512+ // after the last update, one can get the generated bytes using the
513+ // squeezing methods.
514+ // Calling a digest method will throw a ProviderException.
515+ public SHAKE256 () {
516+ super ("SHAKE256" , 0 , (byte ) 0x1F , 64 );
517+ }
518+ }
519+
331520}
0 commit comments