/* * SHA3-256 – portable, eigenstaendige Implementierung * * Kein #include, kein Assembler, keine externen Abhaengigkeiten. * Laeuft auf jeder Plattform mit einem C89/C99-Compiler, * sofern unsigned long long mindestens 64 Bit breit ist. * * Basiert auf FIPS 202 (Keccak / SHA-3). * Zustand: 1600 Bit (5x5 x 64-Bit-Woerter) * Rate: 1088 Bit (136 Byte) fuer SHA3-256 * Ausgabe: 256 Bit (32 Byte) * Runden: 24 (Keccak-f[1600]) */ /* ------------------------------------------------------------------ */ /* Eigene Typdefinitionen (ersetzt / ) */ /* ------------------------------------------------------------------ */ typedef unsigned char uint8; typedef unsigned long long uint64; /* mindestens 64 Bit */ typedef unsigned long usize; /* ------------------------------------------------------------------ */ /* Hilfsfunktionen */ /* ------------------------------------------------------------------ */ static void mem_zero(void *p, usize n) { uint8 *b = (uint8 *)p; while (n--) *b++ = 0; } /* 64-Bit-Rotation nach links */ #define ROL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) /* Little-Endian-Laden / -Speichern eines 64-Bit-Wortes */ static uint64 load64_le(const uint8 *p) { uint64 v = 0; int i; for (i = 0; i < 8; i++) v |= (uint64)p[i] << (8 * i); return v; } static void store64_le(uint8 *p, uint64 v) { int i; for (i = 0; i < 8; i++) p[i] = (uint8)(v >> (8 * i)); } /* ------------------------------------------------------------------ */ /* Keccak-f[1600] – 24 Runden */ /* ------------------------------------------------------------------ */ static const uint64 RC[24] = { 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808AULL, 0x8000000080008000ULL, 0x000000000000808BULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008AULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000AULL, 0x000000008000808BULL, 0x800000000000008BULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800AULL, 0x800000008000000AULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL }; static void keccak_f1600(uint64 A[25]) { int r; for (r = 0; r < 24; r++) { uint64 C[5], D[5], B[25]; int x, y; /* theta */ for (x = 0; x < 5; x++) C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20]; for (x = 0; x < 5; x++) D[x] = C[(x + 4) % 5] ^ ROL64(C[(x + 1) % 5], 1); for (x = 0; x < 5; x++) for (y = 0; y < 5; y++) A[x + 5 * y] ^= D[x]; /* rho + pi */ { static const int rot[25] = { 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14 }; for (x = 0; x < 5; x++) for (y = 0; y < 5; y++) B[y + 5 * ((2 * x + 3 * y) % 5)] = ROL64(A[x + 5 * y], rot[x + 5 * y]); } /* chi */ for (x = 0; x < 5; x++) for (y = 0; y < 5; y++) A[x + 5 * y] = B[x + 5 * y] ^ ((~B[(x + 1) % 5 + 5 * y]) & B[(x + 2) % 5 + 5 * y]); /* iota */ A[0] ^= RC[r]; } } /* ------------------------------------------------------------------ */ /* SHA3-256 (Sponge, Padding: 0x06 ... 0x80) */ /* ------------------------------------------------------------------ */ #define SHA3_256_RATE 136 /* Byte */ #define SHA3_256_HASHLEN 32 /* Byte */ /** * sha3_256 – berechnet den SHA3-256-Hash. * * @param out Ausgabepuffer, mindestens 32 Byte. * @param in Zeiger auf die Eingabedaten. * @param inlen Laenge der Eingabedaten in Byte. */ CALLCONV void sha3_256(uint8 *out, const uint8 *in, usize inlen) { uint64 A[25]; uint8 block[SHA3_256_RATE]; usize i; int j; mem_zero(A, sizeof(A)); /* Absorb: volle Bloecke */ while (inlen >= SHA3_256_RATE) { for (j = 0; j < SHA3_256_RATE / 8; j++) A[j] ^= load64_le(in + 8 * j); keccak_f1600(A); in += SHA3_256_RATE; inlen -= SHA3_256_RATE; } /* Letzter Block + Padding */ mem_zero(block, SHA3_256_RATE); for (i = 0; i < inlen; i++) block[i] = in[i]; block[inlen] = 0x06; /* SHA-3 Domain-Trennung */ block[SHA3_256_RATE - 1] |= 0x80; /* Pad-Ende */ for (j = 0; j < SHA3_256_RATE / 8; j++) A[j] ^= load64_le(block + 8 * j); keccak_f1600(A); /* Squeeze: 32 Byte Ausgabe */ for (j = 0; j < SHA3_256_HASHLEN / 8; j++) store64_le(out + 8 * j, A[j]); }