diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-sha256.h b/extmod/modtrezorcrypto/modtrezorcrypto-sha256.h index b9e8e139a..d1ae7f475 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-sha256.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-sha256.h @@ -61,7 +61,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorCrypto_Sha256_digest_obj, mod_TrezorC STATIC mp_obj_t mod_TrezorCrypto_Sha256___del__(mp_obj_t self) { mp_obj_Sha256_t *o = MP_OBJ_TO_PTR(self); mbedtls_sha256_free(&(o->ctx)); - printf("yay!\n"); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorCrypto_Sha256___del___obj, mod_TrezorCrypto_Sha256___del__); diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-sha3-256.h b/extmod/modtrezorcrypto/modtrezorcrypto-sha3-256.h new file mode 100644 index 000000000..0c06f67b3 --- /dev/null +++ b/extmod/modtrezorcrypto/modtrezorcrypto-sha3-256.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) Pavol Rusnak, SatoshiLabs + * + * Licensed under Microsoft Reference Source License (Ms-RSL) + * see LICENSE.md file for details + */ + +#include "py/objstr.h" + +#include "sha3.h" + +#define HASH_SHA3_256_BLOCK_SIZE 64 +#define HASH_SHA3_256_DIGEST_SIZE 32 + +// class Sha3_256(object): +typedef struct _mp_obj_Sha3_256_t { + mp_obj_base_t base; + sha3_ctx ctx; +} mp_obj_Sha3_256_t; + +STATIC mp_obj_t mod_TrezorCrypto_Sha3_256_update(mp_obj_t self, mp_obj_t data); + +// def Sha3_256.__init__(self, data: bytes = None) +STATIC mp_obj_t mod_TrezorCrypto_Sha3_256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_Sha3_256_t *o = m_new_obj(mp_obj_Sha3_256_t); + o->base.type = type; + rhash_sha3_256_init(&(o->ctx)); + // constructor called with bytes/str as first parameter + if (n_args == 1) { + mod_TrezorCrypto_Sha3_256_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +// def Sha3_256.update(self, data: bytes) -> None +STATIC mp_obj_t mod_TrezorCrypto_Sha3_256_update(mp_obj_t self, mp_obj_t data) { + mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self); + mp_buffer_info_t databuf; + mp_get_buffer_raise(data, &databuf, MP_BUFFER_READ); + rhash_sha3_update(&(o->ctx), databuf.buf, databuf.len); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorCrypto_Sha3_256_update_obj, mod_TrezorCrypto_Sha3_256_update); + +// def Sha3_256.digest(self) -> bytes +STATIC mp_obj_t mod_TrezorCrypto_Sha3_256_digest(mp_obj_t self) { + mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self); + vstr_t vstr; + vstr_init_len(&vstr, HASH_SHA3_256_DIGEST_SIZE); + sha3_ctx ctx; + memcpy(&ctx, &(o->ctx), sizeof(sha3_ctx)); + rhash_sha3_final(&ctx, (uint8_t *)vstr.buf); + memset(&ctx, 0, sizeof(sha3_ctx)); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorCrypto_Sha3_256_digest_obj, mod_TrezorCrypto_Sha3_256_digest); + +// def Sha3_256.__del__(self) -> None +STATIC mp_obj_t mod_TrezorCrypto_Sha3_256___del__(mp_obj_t self) { + mp_obj_Sha3_256_t *o = MP_OBJ_TO_PTR(self); + memset(&(o->ctx), 0, sizeof(sha3_ctx)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorCrypto_Sha3_256___del___obj, mod_TrezorCrypto_Sha3_256___del__); + +// Sha3_256 stuff + +STATIC const mp_rom_map_elem_t mod_TrezorCrypto_Sha3_256_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_TrezorCrypto_Sha3_256_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_TrezorCrypto_Sha3_256_digest_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_TrezorCrypto_Sha3_256___del___obj) }, + { MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(HASH_SHA3_256_BLOCK_SIZE) }, + { MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(HASH_SHA3_256_DIGEST_SIZE) }, +}; +STATIC MP_DEFINE_CONST_DICT(mod_TrezorCrypto_Sha3_256_locals_dict, mod_TrezorCrypto_Sha3_256_locals_dict_table); + +STATIC const mp_obj_type_t mod_TrezorCrypto_Sha3_256_type = { + { &mp_type_type }, + .name = MP_QSTR_Sha3_256, + .make_new = mod_TrezorCrypto_Sha3_256_make_new, + .locals_dict = (void*)&mod_TrezorCrypto_Sha3_256_locals_dict, +}; diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-sha3-512.h b/extmod/modtrezorcrypto/modtrezorcrypto-sha3-512.h new file mode 100644 index 000000000..ed5261ce7 --- /dev/null +++ b/extmod/modtrezorcrypto/modtrezorcrypto-sha3-512.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) Pavol Rusnak, SatoshiLabs + * + * Licensed under Microsoft Reference Source License (Ms-RSL) + * see LICENSE.md file for details + */ + +#include "py/objstr.h" + +#include "sha3.h" + +#define HASH_SHA3_512_BLOCK_SIZE 128 +#define HASH_SHA3_512_DIGEST_SIZE 64 + +// class Sha3_512(object): +typedef struct _mp_obj_Sha3_512_t { + mp_obj_base_t base; + sha3_ctx ctx; +} mp_obj_Sha3_512_t; + +STATIC mp_obj_t mod_TrezorCrypto_Sha3_512_update(mp_obj_t self, mp_obj_t data); + +// def Sha3_512.__init__(self, data: bytes = None) +STATIC mp_obj_t mod_TrezorCrypto_Sha3_512_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + mp_obj_Sha3_512_t *o = m_new_obj(mp_obj_Sha3_512_t); + o->base.type = type; + rhash_sha3_512_init(&(o->ctx)); + // constructor called with bytes/str as first parameter + if (n_args == 1) { + mod_TrezorCrypto_Sha3_512_update(MP_OBJ_FROM_PTR(o), args[0]); + } + return MP_OBJ_FROM_PTR(o); +} + +// def Sha3_512.update(self, data: bytes) -> None +STATIC mp_obj_t mod_TrezorCrypto_Sha3_512_update(mp_obj_t self, mp_obj_t data) { + mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self); + mp_buffer_info_t databuf; + mp_get_buffer_raise(data, &databuf, MP_BUFFER_READ); + rhash_sha3_update(&(o->ctx), databuf.buf, databuf.len); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorCrypto_Sha3_512_update_obj, mod_TrezorCrypto_Sha3_512_update); + +// def Sha3_512.digest(self) -> bytes +STATIC mp_obj_t mod_TrezorCrypto_Sha3_512_digest(mp_obj_t self) { + mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self); + vstr_t vstr; + vstr_init_len(&vstr, HASH_SHA3_512_DIGEST_SIZE); + sha3_ctx ctx; + memcpy(&ctx, &(o->ctx), sizeof(sha3_ctx)); + rhash_sha3_final(&ctx, (uint8_t *)vstr.buf); + memset(&ctx, 0, sizeof(sha3_ctx)); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorCrypto_Sha3_512_digest_obj, mod_TrezorCrypto_Sha3_512_digest); + +// def Sha3_512.__del__(self) -> None +STATIC mp_obj_t mod_TrezorCrypto_Sha3_512___del__(mp_obj_t self) { + mp_obj_Sha3_512_t *o = MP_OBJ_TO_PTR(self); + memset(&(o->ctx), 0, sizeof(sha3_ctx)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorCrypto_Sha3_512___del___obj, mod_TrezorCrypto_Sha3_512___del__); + +// Sha3_512 stuff + +STATIC const mp_rom_map_elem_t mod_TrezorCrypto_Sha3_512_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mod_TrezorCrypto_Sha3_512_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&mod_TrezorCrypto_Sha3_512_digest_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_TrezorCrypto_Sha3_512___del___obj) }, + { MP_ROM_QSTR(MP_QSTR_block_size), MP_OBJ_NEW_SMALL_INT(HASH_SHA3_512_BLOCK_SIZE) }, + { MP_ROM_QSTR(MP_QSTR_digest_size), MP_OBJ_NEW_SMALL_INT(HASH_SHA3_512_DIGEST_SIZE) }, +}; +STATIC MP_DEFINE_CONST_DICT(mod_TrezorCrypto_Sha3_512_locals_dict, mod_TrezorCrypto_Sha3_512_locals_dict_table); + +STATIC const mp_obj_type_t mod_TrezorCrypto_Sha3_512_type = { + { &mp_type_type }, + .name = MP_QSTR_Sha3_512, + .make_new = mod_TrezorCrypto_Sha3_512_make_new, + .locals_dict = (void*)&mod_TrezorCrypto_Sha3_512_locals_dict, +}; diff --git a/extmod/modtrezorcrypto/modtrezorcrypto.c b/extmod/modtrezorcrypto/modtrezorcrypto.c index 520f2c71c..713cffd0c 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto.c +++ b/extmod/modtrezorcrypto/modtrezorcrypto.c @@ -19,6 +19,8 @@ #include "modtrezorcrypto-ripemd160.h" #include "modtrezorcrypto-sha256.h" #include "modtrezorcrypto-sha512.h" +#include "modtrezorcrypto-sha3-256.h" +#include "modtrezorcrypto-sha3-512.h" // module stuff @@ -27,6 +29,8 @@ STATIC const mp_rom_map_elem_t mp_module_TrezorCrypto_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Ripemd160), MP_ROM_PTR(&mod_TrezorCrypto_Ripemd160_type) }, { MP_ROM_QSTR(MP_QSTR_Sha256), MP_ROM_PTR(&mod_TrezorCrypto_Sha256_type) }, { MP_ROM_QSTR(MP_QSTR_Sha512), MP_ROM_PTR(&mod_TrezorCrypto_Sha512_type) }, + { MP_ROM_QSTR(MP_QSTR_Sha3_256), MP_ROM_PTR(&mod_TrezorCrypto_Sha3_256_type) }, + { MP_ROM_QSTR(MP_QSTR_Sha3_512), MP_ROM_PTR(&mod_TrezorCrypto_Sha3_512_type) }, { MP_ROM_QSTR(MP_QSTR_pbkdf2_hmac), MP_ROM_PTR(&mod_TrezorCrypto_pbkdf2_hmac_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_TrezorCrypto_globals, mp_module_TrezorCrypto_globals_table); diff --git a/extmod/modtrezorcrypto/sha3.c b/extmod/modtrezorcrypto/sha3.c new file mode 100644 index 000000000..9dbcacc80 --- /dev/null +++ b/extmod/modtrezorcrypto/sha3.c @@ -0,0 +1,361 @@ +/* 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 + * + * 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 +#include +#include "sha3.h" + +#define I64(x) x##LL +#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) +#define le2me_64(x) (x) +#define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0))) +# define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) + +/* 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 */ diff --git a/extmod/modtrezorcrypto/sha3.h b/extmod/modtrezorcrypto/sha3.h new file mode 100644 index 000000000..f23fa196d --- /dev/null +++ b/extmod/modtrezorcrypto/sha3.h @@ -0,0 +1,73 @@ +/* sha3.h - 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 + * + * 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! + */ + +#ifndef RHASH_SHA3_H +#define RHASH_SHA3_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define sha3_224_hash_size 28 +#define sha3_256_hash_size 32 +#define sha3_384_hash_size 48 +#define sha3_512_hash_size 64 +#define sha3_max_permutation_size 25 +#define sha3_max_rate_in_qwords 24 + +/** + * SHA3 Algorithm context. + */ +typedef struct sha3_ctx +{ + /* 1600 bits algorithm hashing state */ + uint64_t hash[sha3_max_permutation_size]; + /* 1536-bit buffer for leftovers */ + uint64_t message[sha3_max_rate_in_qwords]; + /* count of bytes in the message[] buffer */ + unsigned rest; + /* size of a message block processed at once */ + unsigned block_size; +} sha3_ctx; + +/* methods for calculating the hash function */ + +void rhash_sha3_224_init(sha3_ctx *ctx); +void rhash_sha3_256_init(sha3_ctx *ctx); +void rhash_sha3_384_init(sha3_ctx *ctx); +void rhash_sha3_512_init(sha3_ctx *ctx); +void rhash_sha3_update(sha3_ctx *ctx, const unsigned char* msg, size_t size); +void rhash_sha3_final(sha3_ctx *ctx, unsigned char* result); + +#ifdef USE_KECCAK +#define rhash_keccak_224_init rhash_sha3_224_init +#define rhash_keccak_256_init rhash_sha3_256_init +#define rhash_keccak_384_init rhash_sha3_384_init +#define rhash_keccak_512_init rhash_sha3_512_init +#define rhash_keccak_update rhash_sha3_update +void rhash_keccak_final(sha3_ctx *ctx, unsigned char* result); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* RHASH_SHA3_H */ diff --git a/src/tests/test_crypto_sha3_256.py b/src/tests/test_crypto_sha3_256.py new file mode 100644 index 000000000..3b8e672f7 --- /dev/null +++ b/src/tests/test_crypto_sha3_256.py @@ -0,0 +1,56 @@ +import sys +sys.path.append('..') +sys.path.append('../lib') +import unittest +import trezor.utils + +from trezor.crypto import hashlib + +class TestCryptoSha3_256(unittest.TestCase): + + # vectors from http://www.di-mgt.com.au/sha_testvectors.html + + def test_digest(self): + self.assertEqual(hashlib.sha3_256(b'').digest(), trezor.utils.unhexlify('a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a')) + self.assertEqual(hashlib.sha3_256(b'abc').digest(), trezor.utils.unhexlify('3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532')) + self.assertEqual(hashlib.sha3_256(b'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq').digest(), trezor.utils.unhexlify('41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376')) + self.assertEqual(hashlib.sha3_256(b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu').digest(), trezor.utils.unhexlify('916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18')) + + def test_update(self): + x = hashlib.sha3_256() + self.assertEqual(x.digest(), trezor.utils.unhexlify('a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a')) + + x = hashlib.sha3_256() + x.update(b'abc') + self.assertEqual(x.digest(), trezor.utils.unhexlify('3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532')) + + x = hashlib.sha3_256() + x.update(b'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq') + self.assertEqual(x.digest(), trezor.utils.unhexlify('41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376')) + + x = hashlib.sha3_256() + x.update(b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu') + self.assertEqual(x.digest(), trezor.utils.unhexlify('916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18')) + + x = hashlib.sha3_256() + for i in range(1000000): + x.update(b'a') + self.assertEqual(x.digest(), trezor.utils.unhexlify('5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1')) + + ''' + x = hashlib.sha3_256() + for i in range(16777216): + x.update(b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno') + self.assertEqual(x.digest(), trezor.utils.unhexlify('ecbbc42cbf296603acb2c6bc0410ef4378bafb24b710357f12df607758b33e2b')) + ''' + + def test_digest_multi(self): + x = hashlib.sha3_256() + d0 = x.digest() + d1 = x.digest() + d2 = x.digest() + self.assertEqual(d0, d1) + self.assertEqual(d0, d2) + +if __name__ == '__main__': + unittest.main() diff --git a/src/tests/test_crypto_sha3_512.py b/src/tests/test_crypto_sha3_512.py new file mode 100644 index 000000000..3f24f5cbe --- /dev/null +++ b/src/tests/test_crypto_sha3_512.py @@ -0,0 +1,56 @@ +import sys +sys.path.append('..') +sys.path.append('../lib') +import unittest +import trezor.utils + +from trezor.crypto import hashlib + +class TestCryptoSha3_512(unittest.TestCase): + + # vectors from http://www.di-mgt.com.au/sha_testvectors.html + + def test_digest(self): + self.assertEqual(hashlib.sha3_512(b'').digest(), trezor.utils.unhexlify('a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26')) + self.assertEqual(hashlib.sha3_512(b'abc').digest(), trezor.utils.unhexlify('b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0')) + self.assertEqual(hashlib.sha3_512(b'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq').digest(), trezor.utils.unhexlify('04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e')) + self.assertEqual(hashlib.sha3_512(b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu').digest(), trezor.utils.unhexlify('afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185')) + + def test_update(self): + x = hashlib.sha3_512() + self.assertEqual(x.digest(), trezor.utils.unhexlify('a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26')) + + x = hashlib.sha3_512() + x.update(b'abc') + self.assertEqual(x.digest(), trezor.utils.unhexlify('b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0')) + + x = hashlib.sha3_512() + x.update(b'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq') + self.assertEqual(x.digest(), trezor.utils.unhexlify('04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e')) + + x = hashlib.sha3_512() + x.update(b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu') + self.assertEqual(x.digest(), trezor.utils.unhexlify('afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185')) + + x = hashlib.sha3_512() + for i in range(1000000): + x.update(b'a') + self.assertEqual(x.digest(), trezor.utils.unhexlify('3c3a876da14034ab60627c077bb98f7e120a2a5370212dffb3385a18d4f38859ed311d0a9d5141ce9cc5c66ee689b266a8aa18ace8282a0e0db596c90b0a7b87')) + + ''' + x = hashlib.sha3_512() + for i in range(16777216): + x.update(b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno') + self.assertEqual(x.digest(), trezor.utils.unhexlify('235ffd53504ef836a1342b488f483b396eabbfe642cf78ee0d31feec788b23d0d18d5c339550dd5958a500d4b95363da1b5fa18affc1bab2292dc63b7d85097c')) + ''' + + def test_digest_multi(self): + x = hashlib.sha3_512() + d0 = x.digest() + d1 = x.digest() + d2 = x.digest() + self.assertEqual(d0, d1) + self.assertEqual(d0, d2) + +if __name__ == '__main__': + unittest.main() diff --git a/src/trezor/crypto/hashlib.py b/src/trezor/crypto/hashlib.py index 9a86d7519..c7b26cb49 100644 --- a/src/trezor/crypto/hashlib.py +++ b/src/trezor/crypto/hashlib.py @@ -1,4 +1,6 @@ from TrezorCrypto import Ripemd160 as ripemd160 from TrezorCrypto import Sha256 as sha256 from TrezorCrypto import Sha512 as sha512 +from TrezorCrypto import Sha3_256 as sha3_256 +from TrezorCrypto import Sha3_512 as sha3_512 from TrezorCrypto import pbkdf2_hmac diff --git a/vendor/micropython b/vendor/micropython index ef0505fb5..f0ffa8c04 160000 --- a/vendor/micropython +++ b/vendor/micropython @@ -1 +1 @@ -Subproject commit ef0505fb5c70bf89a6d42d712bc54815e6024b36 +Subproject commit f0ffa8c044759ba10bd092b3ad0e1434fa1b6654