123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- /* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak).
- * based on the
- * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011
- * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche
- *
- * Copyright: 2013 Aleksey Kravchenko <rhash.admin@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
- */
- #include <assert.h>
- #include <string.h>
- #include "byte_order.h"
- #include "sha3.h"
- /* constants */
- #define NumberOfRounds 24
- /* SHA3 (Keccak) constants for 24 rounds */
- static uint64_t keccak_round_constants[NumberOfRounds] = {
- I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000),
- I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009),
- I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A),
- I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003),
- I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A),
- I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008)
- };
- /* Initializing a sha3 context for given number of output bits */
- static void rhash_keccak_init(sha3_ctx *ctx, unsigned bits)
- {
- /* NB: The Keccak capacity parameter = bits * 2 */
- unsigned rate = 1600 - bits * 2;
- memset(ctx, 0, sizeof(sha3_ctx));
- ctx->block_size = rate / 8;
- assert(rate <= 1600 && (rate % 64) == 0);
- }
- /**
- * Initialize context before calculating hash.
- *
- * @param ctx context to initialize
- */
- void rhash_sha3_224_init(sha3_ctx *ctx)
- {
- rhash_keccak_init(ctx, 224);
- }
- /**
- * Initialize context before calculating hash.
- *
- * @param ctx context to initialize
- */
- void rhash_sha3_256_init(sha3_ctx *ctx)
- {
- rhash_keccak_init(ctx, 256);
- }
- /**
- * Initialize context before calculating hash.
- *
- * @param ctx context to initialize
- */
- void rhash_sha3_384_init(sha3_ctx *ctx)
- {
- rhash_keccak_init(ctx, 384);
- }
- /**
- * Initialize context before calculating hash.
- *
- * @param ctx context to initialize
- */
- void rhash_sha3_512_init(sha3_ctx *ctx)
- {
- rhash_keccak_init(ctx, 512);
- }
- /* Keccak theta() transformation */
- static void keccak_theta(uint64_t *A)
- {
- unsigned int x;
- uint64_t C[5], D[5];
- for (x = 0; x < 5; x++) {
- C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20];
- }
- D[0] = ROTL64(C[1], 1) ^ C[4];
- D[1] = ROTL64(C[2], 1) ^ C[0];
- D[2] = ROTL64(C[3], 1) ^ C[1];
- D[3] = ROTL64(C[4], 1) ^ C[2];
- D[4] = ROTL64(C[0], 1) ^ C[3];
- for (x = 0; x < 5; x++) {
- A[x] ^= D[x];
- A[x + 5] ^= D[x];
- A[x + 10] ^= D[x];
- A[x + 15] ^= D[x];
- A[x + 20] ^= D[x];
- }
- }
- /* Keccak pi() transformation */
- static void keccak_pi(uint64_t *A)
- {
- uint64_t A1;
- A1 = A[1];
- A[ 1] = A[ 6];
- A[ 6] = A[ 9];
- A[ 9] = A[22];
- A[22] = A[14];
- A[14] = A[20];
- A[20] = A[ 2];
- A[ 2] = A[12];
- A[12] = A[13];
- A[13] = A[19];
- A[19] = A[23];
- A[23] = A[15];
- A[15] = A[ 4];
- A[ 4] = A[24];
- A[24] = A[21];
- A[21] = A[ 8];
- A[ 8] = A[16];
- A[16] = A[ 5];
- A[ 5] = A[ 3];
- A[ 3] = A[18];
- A[18] = A[17];
- A[17] = A[11];
- A[11] = A[ 7];
- A[ 7] = A[10];
- A[10] = A1;
- /* note: A[ 0] is left as is */
- }
- /* Keccak chi() transformation */
- static void keccak_chi(uint64_t *A)
- {
- int i;
- for (i = 0; i < 25; i += 5) {
- uint64_t A0 = A[0 + i], A1 = A[1 + i];
- A[0 + i] ^= ~A1 & A[2 + i];
- A[1 + i] ^= ~A[2 + i] & A[3 + i];
- A[2 + i] ^= ~A[3 + i] & A[4 + i];
- A[3 + i] ^= ~A[4 + i] & A0;
- A[4 + i] ^= ~A0 & A1;
- }
- }
- static void rhash_sha3_permutation(uint64_t *state)
- {
- int round;
- for (round = 0; round < NumberOfRounds; round++)
- {
- keccak_theta(state);
- /* apply Keccak rho() transformation */
- state[ 1] = ROTL64(state[ 1], 1);
- state[ 2] = ROTL64(state[ 2], 62);
- state[ 3] = ROTL64(state[ 3], 28);
- state[ 4] = ROTL64(state[ 4], 27);
- state[ 5] = ROTL64(state[ 5], 36);
- state[ 6] = ROTL64(state[ 6], 44);
- state[ 7] = ROTL64(state[ 7], 6);
- state[ 8] = ROTL64(state[ 8], 55);
- state[ 9] = ROTL64(state[ 9], 20);
- state[10] = ROTL64(state[10], 3);
- state[11] = ROTL64(state[11], 10);
- state[12] = ROTL64(state[12], 43);
- state[13] = ROTL64(state[13], 25);
- state[14] = ROTL64(state[14], 39);
- state[15] = ROTL64(state[15], 41);
- state[16] = ROTL64(state[16], 45);
- state[17] = ROTL64(state[17], 15);
- state[18] = ROTL64(state[18], 21);
- state[19] = ROTL64(state[19], 8);
- state[20] = ROTL64(state[20], 18);
- state[21] = ROTL64(state[21], 2);
- state[22] = ROTL64(state[22], 61);
- state[23] = ROTL64(state[23], 56);
- state[24] = ROTL64(state[24], 14);
- keccak_pi(state);
- keccak_chi(state);
- /* apply iota(state, round) */
- *state ^= keccak_round_constants[round];
- }
- }
- /**
- * The core transformation. Process the specified block of data.
- *
- * @param hash the algorithm state
- * @param block the message block to process
- * @param block_size the size of the processed block in bytes
- */
- static void rhash_sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size)
- {
- /* expanded loop */
- hash[ 0] ^= le2me_64(block[ 0]);
- hash[ 1] ^= le2me_64(block[ 1]);
- hash[ 2] ^= le2me_64(block[ 2]);
- hash[ 3] ^= le2me_64(block[ 3]);
- hash[ 4] ^= le2me_64(block[ 4]);
- hash[ 5] ^= le2me_64(block[ 5]);
- hash[ 6] ^= le2me_64(block[ 6]);
- hash[ 7] ^= le2me_64(block[ 7]);
- hash[ 8] ^= le2me_64(block[ 8]);
- /* if not sha3-512 */
- if (block_size > 72) {
- hash[ 9] ^= le2me_64(block[ 9]);
- hash[10] ^= le2me_64(block[10]);
- hash[11] ^= le2me_64(block[11]);
- hash[12] ^= le2me_64(block[12]);
- /* if not sha3-384 */
- if (block_size > 104) {
- hash[13] ^= le2me_64(block[13]);
- hash[14] ^= le2me_64(block[14]);
- hash[15] ^= le2me_64(block[15]);
- hash[16] ^= le2me_64(block[16]);
- /* if not sha3-256 */
- if (block_size > 136) {
- hash[17] ^= le2me_64(block[17]);
- #ifdef FULL_SHA3_FAMILY_SUPPORT
- /* if not sha3-224 */
- if (block_size > 144) {
- hash[18] ^= le2me_64(block[18]);
- hash[19] ^= le2me_64(block[19]);
- hash[20] ^= le2me_64(block[20]);
- hash[21] ^= le2me_64(block[21]);
- hash[22] ^= le2me_64(block[22]);
- hash[23] ^= le2me_64(block[23]);
- hash[24] ^= le2me_64(block[24]);
- }
- #endif
- }
- }
- }
- /* make a permutation of the hash */
- rhash_sha3_permutation(hash);
- }
- #define SHA3_FINALIZED 0x80000000
- /**
- * Calculate message hash.
- * Can be called repeatedly with chunks of the message to be hashed.
- *
- * @param ctx the algorithm context containing current hashing state
- * @param msg message chunk
- * @param size length of the message chunk
- */
- void rhash_sha3_update(sha3_ctx *ctx, const unsigned char *msg, size_t size)
- {
- size_t index = (size_t)ctx->rest;
- size_t block_size = (size_t)ctx->block_size;
- if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */
- ctx->rest = (unsigned)((ctx->rest + size) % block_size);
- /* fill partial block */
- if (index) {
- size_t left = block_size - index;
- memcpy((char*)ctx->message + index, msg, (size < left ? size : left));
- if (size < left) return;
- /* process partial block */
- rhash_sha3_process_block(ctx->hash, ctx->message, block_size);
- msg += left;
- size -= left;
- }
- while (size >= block_size) {
- uint64_t* aligned_message_block;
- if (IS_ALIGNED_64(msg)) {
- /* the most common case is processing of an already aligned message
- without copying it */
- aligned_message_block = (uint64_t*)msg;
- } else {
- memcpy(ctx->message, msg, block_size);
- aligned_message_block = ctx->message;
- }
- rhash_sha3_process_block(ctx->hash, aligned_message_block, block_size);
- msg += block_size;
- size -= block_size;
- }
- if (size) {
- memcpy(ctx->message, msg, size); /* save leftovers */
- }
- }
- /**
- * Store calculated hash into the given array.
- *
- * @param ctx the algorithm context containing current hashing state
- * @param result calculated hash in binary form
- */
- void rhash_sha3_final(sha3_ctx *ctx, unsigned char* result)
- {
- size_t digest_length = 100 - ctx->block_size / 2;
- const size_t block_size = ctx->block_size;
- if (!(ctx->rest & SHA3_FINALIZED))
- {
- /* clear the rest of the data queue */
- memset((char*)ctx->message + ctx->rest, 0, block_size - ctx->rest);
- ((char*)ctx->message)[ctx->rest] |= 0x06;
- ((char*)ctx->message)[block_size - 1] |= 0x80;
- /* process final block */
- rhash_sha3_process_block(ctx->hash, ctx->message, block_size);
- ctx->rest = SHA3_FINALIZED; /* mark context as finalized */
- }
- assert(block_size > digest_length);
- if (result) me64_to_le_str(result, ctx->hash, digest_length);
- }
- #ifdef USE_KECCAK
- /**
- * Store calculated hash into the given array.
- *
- * @param ctx the algorithm context containing current hashing state
- * @param result calculated hash in binary form
- */
- void rhash_keccak_final(sha3_ctx *ctx, unsigned char* result)
- {
- size_t digest_length = 100 - ctx->block_size / 2;
- const size_t block_size = ctx->block_size;
- if (!(ctx->rest & SHA3_FINALIZED))
- {
- /* clear the rest of the data queue */
- memset((char*)ctx->message + ctx->rest, 0, block_size - ctx->rest);
- ((char*)ctx->message)[ctx->rest] |= 0x01;
- ((char*)ctx->message)[block_size - 1] |= 0x80;
- /* process final block */
- rhash_sha3_process_block(ctx->hash, ctx->message, block_size);
- ctx->rest = SHA3_FINALIZED; /* mark context as finalized */
- }
- assert(block_size > digest_length);
- if (result) me64_to_le_str(result, ctx->hash, digest_length);
- }
- #endif /* USE_KECCAK */
|