SHA-1 的实现产生与“java.security”实现不同的散列
Implementation of SHA-1 yields different hashes than the `java.security` implementation
我正在尝试在 Java 11 中实现 SHA-1 算法,在测试散列算法时,我得到的散列值与使用 java.security
实现的 SHA-1 散列值不同。
可以找到我试图遵循的伪代码 on Wikipedia。
public static byte[] hash(byte[] message) {
int h0 = 0x67452301;
int h1 = 0xEFCDAB89;
int h2 = 0x98BADCFE;
int h3 = 0x10325476;
int h4 = 0xC3D2E1F0;
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.writeBytes(message);
out.write(0x00000080);
while (out.size() % 64 != 56) out.write(0x00000000);
out.writeBytes(ByteBuffer.allocate(8).putLong(message.length).array());
byte[] data = out.toByteArray();
for (int j = 0; j < data.length / 64; ++j) {
int[] w = new int[80];
for (int i = 0; i < 16; ++i) {
w[i] = ByteBuffer.wrap(data, j * 64 + i * 4, 4).getInt();
}
for (int i = 16; i < 80; ++i) {
w[i] = leftrotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
}
int a = h0;
int b = h1;
int c = h2;
int d = h3;
int e = h4;
for (int i = 0; i < 80; ++i) {
final int f, k;
if (i < 20) {
f = (b & c) | ((~b) & d);
k = 0x5A827999;
} else if (i < 40) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (i < 60) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
int t = leftrotate(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = leftrotate(b, 30);
b = a;
a = t;
}
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
}
ByteBuffer buffer = ByteBuffer.allocate(20);
buffer.putInt(h0);
buffer.putInt(h1);
buffer.putInt(h2);
buffer.putInt(h3);
buffer.putInt(h4);
return buffer.array();
}
public static int leftrotate(int x, int c) {
return (x << c) | (x >> (32 - c));
}
为了测试这一点,我尝试散列一个 n 字节的随机数组,并将该散列与
获得的散列进行比较
MessageDigest.getInstance("SHA-1").digest(message)
我得到了不同的哈希值。
我上面的实现有没有错误?错误可能来自其他地方吗?
实现有两个问题。首先,我以字节而不是位为单位写入初始消息的大小。其次,leftrotate
方法在本应使用逻辑右移时使用了算术右移。
我正在尝试在 Java 11 中实现 SHA-1 算法,在测试散列算法时,我得到的散列值与使用 java.security
实现的 SHA-1 散列值不同。
可以找到我试图遵循的伪代码 on Wikipedia。
public static byte[] hash(byte[] message) {
int h0 = 0x67452301;
int h1 = 0xEFCDAB89;
int h2 = 0x98BADCFE;
int h3 = 0x10325476;
int h4 = 0xC3D2E1F0;
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.writeBytes(message);
out.write(0x00000080);
while (out.size() % 64 != 56) out.write(0x00000000);
out.writeBytes(ByteBuffer.allocate(8).putLong(message.length).array());
byte[] data = out.toByteArray();
for (int j = 0; j < data.length / 64; ++j) {
int[] w = new int[80];
for (int i = 0; i < 16; ++i) {
w[i] = ByteBuffer.wrap(data, j * 64 + i * 4, 4).getInt();
}
for (int i = 16; i < 80; ++i) {
w[i] = leftrotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
}
int a = h0;
int b = h1;
int c = h2;
int d = h3;
int e = h4;
for (int i = 0; i < 80; ++i) {
final int f, k;
if (i < 20) {
f = (b & c) | ((~b) & d);
k = 0x5A827999;
} else if (i < 40) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (i < 60) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
int t = leftrotate(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = leftrotate(b, 30);
b = a;
a = t;
}
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
}
ByteBuffer buffer = ByteBuffer.allocate(20);
buffer.putInt(h0);
buffer.putInt(h1);
buffer.putInt(h2);
buffer.putInt(h3);
buffer.putInt(h4);
return buffer.array();
}
public static int leftrotate(int x, int c) {
return (x << c) | (x >> (32 - c));
}
为了测试这一点,我尝试散列一个 n 字节的随机数组,并将该散列与
获得的散列进行比较MessageDigest.getInstance("SHA-1").digest(message)
我得到了不同的哈希值。 我上面的实现有没有错误?错误可能来自其他地方吗?
实现有两个问题。首先,我以字节而不是位为单位写入初始消息的大小。其次,leftrotate
方法在本应使用逻辑右移时使用了算术右移。