|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.provider; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.Objects; |
|
|
|
import static sun.security.provider.ByteArrayAccess.*; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final class SHA extends DigestBase { |
|
|
|
// Buffer of int's and count of characters accumulated |
|
// 64 bytes are included in each hash block so the low order |
|
// bits of count are used to know how to pack the bytes into ints |
|
|
|
private int[] W; |
|
|
|
|
|
private int[] state; |
|
|
|
|
|
|
|
*/ |
|
public SHA() { |
|
super("SHA-1", 20, 64); |
|
state = new int[5]; |
|
W = new int[80]; |
|
resetHashes(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public Object clone() throws CloneNotSupportedException { |
|
SHA copy = (SHA) super.clone(); |
|
copy.state = copy.state.clone(); |
|
copy.W = new int[80]; |
|
return copy; |
|
} |
|
|
|
|
|
|
|
*/ |
|
void implReset() { |
|
|
|
resetHashes(); |
|
|
|
Arrays.fill(W, 0); |
|
} |
|
|
|
private void resetHashes() { |
|
state[0] = 0x67452301; |
|
state[1] = 0xefcdab89; |
|
state[2] = 0x98badcfe; |
|
state[3] = 0x10325476; |
|
state[4] = 0xc3d2e1f0; |
|
} |
|
|
|
|
|
|
|
*/ |
|
void implDigest(byte[] out, int ofs) { |
|
long bitsProcessed = bytesProcessed << 3; |
|
|
|
int index = (int)bytesProcessed & 0x3f; |
|
int padLen = (index < 56) ? (56 - index) : (120 - index); |
|
engineUpdate(padding, 0, padLen); |
|
|
|
i2bBig4((int)(bitsProcessed >>> 32), buffer, 56); |
|
i2bBig4((int)bitsProcessed, buffer, 60); |
|
implCompress(buffer, 0); |
|
|
|
i2bBig(state, 0, out, ofs, 20); |
|
} |
|
|
|
|
|
private final static int round1_kt = 0x5a827999; |
|
private final static int round2_kt = 0x6ed9eba1; |
|
private final static int round3_kt = 0x8f1bbcdc; |
|
private final static int round4_kt = 0xca62c1d6; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
void implCompress(byte[] buf, int ofs) { |
|
implCompressCheck(buf, ofs); |
|
implCompress0(buf, ofs); |
|
} |
|
|
|
private void implCompressCheck(byte[] buf, int ofs) { |
|
Objects.requireNonNull(buf); |
|
|
|
// The checks performed by the method 'b2iBig64' |
|
// are sufficient for the case when the method |
|
// 'implCompressImpl' is replaced with a compiler |
|
|
|
b2iBig64(buf, ofs, W); |
|
} |
|
|
|
// The method 'implCompressImpl seems not to use its parameters. |
|
// The method can, however, be replaced with a compiler intrinsic |
|
// that operates directly on the array 'buf' (starting from |
|
// offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs' |
|
|
|
private void implCompress0(byte[] buf, int ofs) { |
|
// The first 16 ints have the byte stream, compute the rest of |
|
|
|
for (int t = 16; t <= 79; t++) { |
|
int temp = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]; |
|
W[t] = (temp << 1) | (temp >>> 31); |
|
} |
|
|
|
int a = state[0]; |
|
int b = state[1]; |
|
int c = state[2]; |
|
int d = state[3]; |
|
int e = state[4]; |
|
|
|
|
|
for (int i = 0; i < 20; i++) { |
|
int temp = ((a<<5) | (a>>>(32-5))) + |
|
((b&c)|((~b)&d))+ e + W[i] + round1_kt; |
|
e = d; |
|
d = c; |
|
c = ((b<<30) | (b>>>(32-30))); |
|
b = a; |
|
a = temp; |
|
} |
|
|
|
|
|
for (int i = 20; i < 40; i++) { |
|
int temp = ((a<<5) | (a>>>(32-5))) + |
|
(b ^ c ^ d) + e + W[i] + round2_kt; |
|
e = d; |
|
d = c; |
|
c = ((b<<30) | (b>>>(32-30))); |
|
b = a; |
|
a = temp; |
|
} |
|
|
|
|
|
for (int i = 40; i < 60; i++) { |
|
int temp = ((a<<5) | (a>>>(32-5))) + |
|
((b&c)|(b&d)|(c&d)) + e + W[i] + round3_kt; |
|
e = d; |
|
d = c; |
|
c = ((b<<30) | (b>>>(32-30))); |
|
b = a; |
|
a = temp; |
|
} |
|
|
|
|
|
for (int i = 60; i < 80; i++) { |
|
int temp = ((a<<5) | (a>>>(32-5))) + |
|
(b ^ c ^ d) + e + W[i] + round4_kt; |
|
e = d; |
|
d = c; |
|
c = ((b<<30) | (b>>>(32-30))); |
|
b = a; |
|
a = temp; |
|
} |
|
state[0] += a; |
|
state[1] += b; |
|
state[2] += c; |
|
state[3] += d; |
|
state[4] += e; |
|
} |
|
|
|
} |