From 25097ed0d328e4130f89b2f49b1e9f6578b0e95d Mon Sep 17 00:00:00 2001 From: Minyong Li <ml10g20@soton.ac.uk> Date: Mon, 23 Aug 2021 22:42:14 +0100 Subject: [PATCH] util/chacha20.c: add software impl for debugging --- util/chacha20.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 util/chacha20.c diff --git a/util/chacha20.c b/util/chacha20.c new file mode 100644 index 0000000..4796612 --- /dev/null +++ b/util/chacha20.c @@ -0,0 +1,183 @@ +// A quick-n-dirty software implementation of ChaCha20 block function mainly +// used for displaying, comparing and debugging the internal states. +// +// SPDX-FileCopyrightText: 2021 Minyong Li <ml10g20@soton.ac.uk> +// SPDX-License-Identifier: GPL-3.0-or-later + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#define DEBUG + +typedef uint32_t word_t; + +#define WORD_WORDS 1 +#define WORD_BYTES sizeof(word_t) +#define WORD_BITS (WORD_BYTES * 8) + +#define CONSTANTS_WORDS 4 +#define KEY_WORDS 8 +#define COUNTER_WORDS 1 +#define NONCE_WORDS 3 +#define STATE_WORDS 16 + +#define CONSTANTS_BYTES (CONSTANTS_WORDS * 4) +#define KEY_BYTES (KEY_WORDS * 4) +#define COUNTER_BYTES (COUNTER_WORDS * 4) +#define NONCE_BYTES (NONCE_WORDS * 4) +#define STATE_BYTES (STATE_WORDS * 4) + +#define CONSTANTS_BITS (CONSTANTS_BYTES * 8) +#define KEY_BITS (KEY_BYTES * 8) +#define COUNTER_BITS (COUNTER_BYTES * 8) +#define NONCE_BITS (NONCE_BYTES * 8) +#define STATE_BITS (STATE_BYTES * 8) + +#ifdef DEBUG +#define dbg(fmt, ...) fprintf(stderr, ">> %s: " fmt "\n", __func__, __VA_ARGS__) +#define eprintln_state(state) { \ + char *str = state_to_string(state); \ + fputs(str, stderr); \ + putchar('\n'); \ + free(str); \ +} +#else +#define dbg(fmt, ...) +#define eprintln_state(state) +#endif + +char *state_to_string(word_t *state) { + size_t str_size = snprintf(NULL, 0, + "%x %x %x %x\n%x %x %x %x\n%x %x %x %x\n%x %x %x %x", + state[0], state[1], state[2], state[3], + state[4], state[5], state[6], state[7], + state[8], state[9], state[10], state[11], + state[12], state[13], state[14], state[15]); + + char *str = malloc(str_size + 1); + if (!str) + return NULL; + + snprintf(str, str_size + 1, + "%x %x %x %x\n%x %x %x %x\n%x %x %x %x\n%x %x %x %x", + state[0], state[1], state[2], state[3], + state[4], state[5], state[6], state[7], + state[8], state[9], state[10], state[11], + state[12], state[13], state[14], state[15]); + + return str; +} + +word_t left_rotate(const word_t x, const int n) { + return (x << n) | (x >> (WORD_BITS - n)); +} + +void quarter_round(word_t *a, word_t *b, word_t *c, word_t *d) { + *a += *b; + *d ^= *a; + *d = left_rotate(*d, 16); + *c += *d; + *b ^= *c; + *b = left_rotate(*b, 12); + *a += *b; + *d ^= *a; + *d = left_rotate(*d, 8); + *c += *d; + *b ^= *c; + *b = left_rotate(*b, 7); +} + +void inner_block(word_t *state) { + quarter_round(&state[0], &state[4], &state[8], &state[12]); + quarter_round(&state[1], &state[5], &state[9], &state[13]); + quarter_round(&state[2], &state[6], &state[10], &state[14]); + quarter_round(&state[3], &state[7], &state[11], &state[15]); + + dbg("%s", "columnar round result"); + eprintln_state(state); + + quarter_round(&state[0], &state[5], &state[10], &state[15]); + quarter_round(&state[1], &state[6], &state[11], &state[12]); + quarter_round(&state[2], &state[7], &state[8], &state[13]); + quarter_round(&state[3], &state[4], &state[9], &state[14]); + + dbg("%s", "diagonal round result"); + eprintln_state(state); +} + +word_t *state_add(word_t *state_a, word_t *state_b) { + word_t *state_y = malloc(STATE_BYTES); + if (!state_y) + return NULL; + + for (size_t i = 0; i < STATE_WORDS; i++) { + state_y[i] = state_a[i] + state_b[i]; + } + + return state_y; +} + +word_t *chacha20_block(const unsigned char *key, const unsigned char *counter, const unsigned char *nonce) { + static const word_t constants[] = { + 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 + }; + + word_t *state = malloc(STATE_BYTES); + if (!state) + return NULL; + + dbg("%s", "initializing block"); + + memcpy(state, constants, CONSTANTS_BYTES); + memcpy(state + CONSTANTS_WORDS, key, KEY_BYTES); + memcpy(state + CONSTANTS_WORDS + KEY_WORDS, counter, COUNTER_BYTES); + memcpy(state + CONSTANTS_WORDS + KEY_WORDS + COUNTER_WORDS, nonce, NONCE_BYTES); + + dbg("%s", "initialized block"); + eprintln_state(state); + + word_t *initial_state = malloc(STATE_BYTES); + if (!initial_state) { + free(state); + return NULL; + } + + memcpy(initial_state, state, STATE_BYTES); + + dbg("%s", "initial state copied"); + + for (size_t i = 0; i < 10; i++) { + dbg("%s %zu", "inner block iteration", i); + inner_block(state); + } + + dbg("%s", "adding final state"); + + word_t *final_state = state_add(state, initial_state); + + dbg("%s", "final state produced"); + eprintln_state(final_state); + + free(initial_state); + free(state); + + return final_state; +} + +int main(void) { + static const unsigned char key[KEY_BYTES] = {0}; + static const unsigned char counter[COUNTER_BYTES] = {0}; + static const unsigned char nonce[NONCE_BYTES] = {0}; + + word_t *block = chacha20_block(key, counter, nonce); + + char *str = state_to_string(block); + printf("The final state: %s\n", str); + + free(str); + free(block); + + return 0; +} -- GitLab