我在 C 中实现了 SHA-3 哈希算法,它适用于非空文件,但是当我尝试获取空文件的摘要时,我得到了错误的摘要。
例如,如果散列一个只有“a”字母的文件,我得到:
be5215abf72333a73b992dafdf4ab59884b948452e0015cfaddaa0b87a0e4515
但是,当我散列空文件时,我得到
000000000000000000000000000000000000000000000000000000000000000000
我期望:
a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a
(https://en.wikipedia.org/wiki/SHA-3#Examples_of_SHA-3_variants)
谁能告诉我我的实施有什么问题?
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define index(x, y) (((x) % 5) + 5 * ((y) % 5))
#define KECCAK_ROUNDS 24
#define Plen 200
typedef unsigned int uint;
const uint64_t round_constants[KECCAK_ROUNDS] =
{
0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000,
0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
};
/* --------------------------------------------------------------------------- */
static uint64_t
rol(uint64_t a, uint offset)
{
if (offset == 0) {
return a;
}
return (a << offset) | (a >> (64 - offset));
}
static void
theta(uint64_t *A)
{
uint64_t C[5], D[5];
for (uint x = 0; x < 5; ++x) {
C[x] = 0;
for (uint y = 0; y < 5; ++y) {
C[x] ^= A[index(x, y)];
}
}
for (uint x = 0; x < 5; ++x) {
D[x] = rol(C[(x + 1) % 5], 1) ^ C[(x + 4) % 5];
}
for (uint x = 0; x < 5; ++x) {
for (uint y = 0; y < 5; ++y) {
A[index(x, y)] ^= D[x];
}
}
}
static void
rho(uint64_t *A)
{
uint newX, newY, ro[KECCAK_ROUNDS];
ro[index(0, 0)] = 0;
uint x = 1;
uint y = 0;
for (uint t = 0; t < KECCAK_ROUNDS; ++t) {
ro[index(x, y)] = ((t + 1) * (t + 2) / 2) % 64;
newX = (0 * x + 1 * y) % 5;
newY = (2 * x + 3 * y) % 5;
x = newX;
y = newY;
}
for (x = 0; x < 5; ++x) {
for (y = 0; y < 5; ++y) {
A[index(x, y)] = rol(A[index(x, y)], ro[index(x, y)]);
}
}
}
static void
pi(uint64_t *A)
{
uint64_t tempA[25];
for (uint x = 0; x < 5; ++x) {
for (uint y = 0; y < 5; ++y) {
tempA[index(x, y)] = A[index(x, y)];
}
}
for (uint x = 0; x < 5; ++x) {
for (uint y = 0; y < 5; ++y) {
A[index(0 * x + 1 * y, 2 * x + 3 * y)] = tempA[index(x, y)];
}
}
}
static void
chi(uint64_t *A)
{
uint64_t C[5];
for (uint y = 0; y < 5; ++y) {
for (uint x = 0; x < 5; ++x) {
C[x] = A[index(x, y)] ^ ((~A[index(x + 1, y)]) & A[index(x + 2, y)]);
}
for (uint x = 0; x < 5; ++x) {
A[index(x, y)] = C[x];
}
}
}
static void
iota(uint64_t *A, uint indexRound)
{
A[index(0, 0)] ^= round_constants[indexRound];
}
static void
keccakf(void *state)
{
for (uint i = 0; i < KECCAK_ROUNDS; ++i) {
theta(state);
rho(state);
pi(state);
chi(state);
iota(state, i);
}
}
static void
xorin(uint8_t *dest, const uint8_t *src, size_t len)
{
for (size_t i = 0; i < len; ++i) {
dest[i] ^= src[i];
}
}
static void
setout(uint8_t *dest, const uint8_t *src, size_t len)
{
for (size_t i = 0; i < len; ++i) {
dest[i] = src[i];
}
}
/* The sponge-based hash construction. */
static void
hash(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen, size_t rate, uint8_t delim)
{
if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
return;
}
uint8_t a[Plen] = { 0 /* 0, 0, 0, ... */ };
while (inlen >= rate) {
xorin(a, in, rate);
keccakf(a);
in += rate;
inlen -= rate;
}
a[inlen] ^= delim;
a[rate - 1] ^= 0x80;
xorin(a, in, inlen);
keccakf(a);
while (outlen >= rate) {
setout(out, a, rate);
keccakf(a);
out += rate;
outlen -= rate;
}
setout(out, a, outlen);
memset(a, '\0', Plen);
}
int
sha3_stream (FILE *stream, void *resblock, size_t databitlen)
{
size_t SHA3_BLOCK = databitlen / 8;
size_t bytesread;
uint8_t *in = malloc (databitlen);
if (!in)
return 1;
while ((bytesread = fread(in, sizeof(char), SHA3_BLOCK, stream)) != 0)
hash(resblock, SHA3_BLOCK, in, bytesread, Plen - (databitlen / 4), 0x06);
free(in);
return 0;
}
int main(int argc, char **argv)
{
/* 32 it is SHA3-256 BLOCK */
/* here used 256 bits digest lenght */
for (int i = 1; i < argc; ++i)
{
uint8_t *out = malloc(32);
FILE *fp = fopen(argv[i], "r");
sha3_stream(fp, out, 256);
for (int j = 0; j < 32; ++j)
printf("%02x", out[j]);
printf(" %s\n", argv[i]);
free(out);
}
}