|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.provider; |
|
|
|
import static sun.security.provider.ByteArrayAccess.*; |
|
import java.nio.*; |
|
import java.util.*; |
|
import java.security.*; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
abstract class SHA3 extends DigestBase { |
|
|
|
private static final int WIDTH = 200; |
|
private static final int DM = 5; |
|
|
|
private static final int NR = 24; |
|
|
|
|
|
private static final long[] RC_CONSTANTS = { |
|
0x01L, 0x8082L, 0x800000000000808aL, |
|
0x8000000080008000L, 0x808bL, 0x80000001L, |
|
0x8000000080008081L, 0x8000000000008009L, 0x8aL, |
|
0x88L, 0x80008009L, 0x8000000aL, |
|
0x8000808bL, 0x800000000000008bL, 0x8000000000008089L, |
|
0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L, |
|
0x800aL, 0x800000008000000aL, 0x8000000080008081L, |
|
0x8000000000008080L, 0x80000001L, 0x8000000080008008L, |
|
}; |
|
|
|
private byte[] state = new byte[WIDTH]; |
|
private final long[] lanes = new long[DM*DM]; |
|
|
|
|
|
|
|
*/ |
|
SHA3(String name, int digestLength) { |
|
super(name, digestLength, (WIDTH - (2 * digestLength))); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void implCompress(byte[] b, int ofs) { |
|
for (int i = 0; i < buffer.length; i++) { |
|
state[i] ^= b[ofs++]; |
|
} |
|
keccak(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void implDigest(byte[] out, int ofs) { |
|
int numOfPadding = |
|
setPaddingBytes(buffer, (int)(bytesProcessed % buffer.length)); |
|
if (numOfPadding < 1) { |
|
throw new ProviderException("Incorrect pad size: " + numOfPadding); |
|
} |
|
for (int i = 0; i < buffer.length; i++) { |
|
state[i] ^= buffer[i]; |
|
} |
|
keccak(); |
|
System.arraycopy(state, 0, out, ofs, engineGetDigestLength()); |
|
} |
|
|
|
|
|
|
|
*/ |
|
void implReset() { |
|
Arrays.fill(state, (byte)0); |
|
Arrays.fill(lanes, 0L); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static int setPaddingBytes(byte[] in, int len) { |
|
if (len != in.length) { |
|
|
|
Arrays.fill(in, len, in.length, (byte)0); |
|
// directly store the padding bytes into the input |
|
|
|
in[len] |= (byte) 0x06; |
|
in[in.length - 1] |= (byte) 0x80; |
|
} |
|
return (in.length - len); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private static void bytes2Lanes(byte[] s, long[] m) { |
|
int sOfs = 0; |
|
|
|
for (int y = 0; y < DM; y++, sOfs += 40) { |
|
b2lLittle(s, sOfs, m, DM*y, 40); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private static void lanes2Bytes(long[] m, byte[] s) { |
|
int sOfs = 0; |
|
|
|
for (int y = 0; y < DM; y++, sOfs += 40) { |
|
l2bLittle(m, DM*y, s, sOfs, 40); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static long[] smTheta(long[] a) { |
|
long c0 = a[0]^a[5]^a[10]^a[15]^a[20]; |
|
long c1 = a[1]^a[6]^a[11]^a[16]^a[21]; |
|
long c2 = a[2]^a[7]^a[12]^a[17]^a[22]; |
|
long c3 = a[3]^a[8]^a[13]^a[18]^a[23]; |
|
long c4 = a[4]^a[9]^a[14]^a[19]^a[24]; |
|
long d0 = c4 ^ Long.rotateLeft(c1, 1); |
|
long d1 = c0 ^ Long.rotateLeft(c2, 1); |
|
long d2 = c1 ^ Long.rotateLeft(c3, 1); |
|
long d3 = c2 ^ Long.rotateLeft(c4, 1); |
|
long d4 = c3 ^ Long.rotateLeft(c0, 1); |
|
for (int y = 0; y < a.length; y += DM) { |
|
a[y] ^= d0; |
|
a[y+1] ^= d1; |
|
a[y+2] ^= d2; |
|
a[y+3] ^= d3; |
|
a[y+4] ^= d4; |
|
} |
|
return a; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static long[] smPiRho(long[] a) { |
|
long tmp = Long.rotateLeft(a[10], 3); |
|
a[10] = Long.rotateLeft(a[1], 1); |
|
a[1] = Long.rotateLeft(a[6], 44); |
|
a[6] = Long.rotateLeft(a[9], 20); |
|
a[9] = Long.rotateLeft(a[22], 61); |
|
a[22] = Long.rotateLeft(a[14], 39); |
|
a[14] = Long.rotateLeft(a[20], 18); |
|
a[20] = Long.rotateLeft(a[2], 62); |
|
a[2] = Long.rotateLeft(a[12], 43); |
|
a[12] = Long.rotateLeft(a[13], 25); |
|
a[13] = Long.rotateLeft(a[19], 8); |
|
a[19] = Long.rotateLeft(a[23], 56); |
|
a[23] = Long.rotateLeft(a[15], 41); |
|
a[15] = Long.rotateLeft(a[4], 27); |
|
a[4] = Long.rotateLeft(a[24], 14); |
|
a[24] = Long.rotateLeft(a[21], 2); |
|
a[21] = Long.rotateLeft(a[8], 55); |
|
a[8] = Long.rotateLeft(a[16], 45); |
|
a[16] = Long.rotateLeft(a[5], 36); |
|
a[5] = Long.rotateLeft(a[3], 28); |
|
a[3] = Long.rotateLeft(a[18], 21); |
|
a[18] = Long.rotateLeft(a[17], 15); |
|
a[17] = Long.rotateLeft(a[11], 10); |
|
a[11] = Long.rotateLeft(a[7], 6); |
|
a[7] = tmp; |
|
return a; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static long[] smChi(long[] a) { |
|
for (int y = 0; y < a.length; y+=DM) { |
|
long ay0 = a[y]; |
|
long ay1 = a[y+1]; |
|
long ay2 = a[y+2]; |
|
long ay3 = a[y+3]; |
|
long ay4 = a[y+4]; |
|
a[y] = ay0 ^ ((~ay1) & ay2); |
|
a[y+1] = ay1 ^ ((~ay2) & ay3); |
|
a[y+2] = ay2 ^ ((~ay3) & ay4); |
|
a[y+3] = ay3 ^ ((~ay4) & ay0); |
|
a[y+4] = ay4 ^ ((~ay0) & ay1); |
|
} |
|
return a; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static long[] smIota(long[] a, int rndIndex) { |
|
a[0] ^= RC_CONSTANTS[rndIndex]; |
|
return a; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private void keccak() { |
|
|
|
bytes2Lanes(state, lanes); |
|
|
|
for (int ir = 0; ir < NR; ir++) { |
|
smIota(smChi(smPiRho(smTheta(lanes))), ir); |
|
} |
|
|
|
lanes2Bytes(lanes, state); |
|
} |
|
|
|
public Object clone() throws CloneNotSupportedException { |
|
SHA3 copy = (SHA3) super.clone(); |
|
copy.state = copy.state.clone(); |
|
return copy; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static final class SHA224 extends SHA3 { |
|
public SHA224() { |
|
super("SHA3-224", 28); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static final class SHA256 extends SHA3 { |
|
public SHA256() { |
|
super("SHA3-256", 32); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static final class SHA384 extends SHA3 { |
|
public SHA384() { |
|
super("SHA3-384", 48); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static final class SHA512 extends SHA3 { |
|
public SHA512() { |
|
super("SHA3-512", 64); |
|
} |
|
} |
|
} |