Path: blob/main/crypto/libecc/src/hash/ripemd160.c
34869 views
/*1* Copyright (C) 2021 - This file is part of libecc project2*3* Authors:4* Arnaud EBALARD <[email protected]>5* Ryad BENADJILA <[email protected]>6*7* This software is licensed under a dual BSD and GPL v2 license.8* See LICENSE file at the root folder of the project.9*/10#include <libecc/lib_ecc_config.h>11#ifdef WITH_HASH_RIPEMD1601213#include <libecc/hash/ripemd160.h>1415/****************************************************/16/*17* 32-bit integer manipulation macros (big endian)18*/19#ifndef GET_UINT32_LE20#define GET_UINT32_LE(n, b, i) \21do { \22(n) = ( ((u32) (b)[(i) + 3]) << 24 ) \23| ( ((u32) (b)[(i) + 2]) << 16 ) \24| ( ((u32) (b)[(i) + 1]) << 8 ) \25| ( ((u32) (b)[(i) ]) ); \26} while( 0 )27#endif2829#ifndef PUT_UINT32_LE30#define PUT_UINT32_LE(n, b, i) \31do { \32(b)[(i) + 3] = (u8) ( (n) >> 24 ); \33(b)[(i) + 2] = (u8) ( (n) >> 16 ); \34(b)[(i) + 1] = (u8) ( (n) >> 8 ); \35(b)[(i) ] = (u8) ( (n) ); \36} while( 0 )37#endif3839/*40* 64-bit integer manipulation macros (big endian)41*/42#ifndef PUT_UINT64_LE43#define PUT_UINT64_LE(n,b,i) \44do { \45(b)[(i) + 7] = (u8) ( (n) >> 56 ); \46(b)[(i) + 6] = (u8) ( (n) >> 48 ); \47(b)[(i) + 5] = (u8) ( (n) >> 40 ); \48(b)[(i) + 4] = (u8) ( (n) >> 32 ); \49(b)[(i) + 3] = (u8) ( (n) >> 24 ); \50(b)[(i) + 2] = (u8) ( (n) >> 16 ); \51(b)[(i) + 1] = (u8) ( (n) >> 8 ); \52(b)[(i) ] = (u8) ( (n) ); \53} while( 0 )54#endif /* PUT_UINT64_LE */5556/* Elements related to RIPEMD160 */57#define ROTL_RIPEMD160(x, n) ((((u32)(x)) << (n)) | (((u32)(x)) >> (32-(n))))5859#define F1_RIPEMD160(x, y, z) ((x) ^ (y) ^ (z))60#define F2_RIPEMD160(x, y, z) (((x) & (y)) | ((~(x)) & (z)))61#define F3_RIPEMD160(x, y, z) (((x) | (~(y))) ^ (z))62#define F4_RIPEMD160(x, y, z) (((x) & (z)) | ((y) & (~(z))))63#define F5_RIPEMD160(x, y, z) ((x) ^ ((y) | (~(z))))6465/* Left constants */66static const u32 KL_RIPEMD160[5] = {670x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e68};69/* Right constants */70static const u32 KR_RIPEMD160[5] = {710x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x0000000072};7374/* Left line */75static const u8 RL_RIPEMD160[5][16] = {76{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },77{ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8 },78{ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12 },79{ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2 },80{ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 }81};82static const u8 SL_RIPEMD160[5][16] = {83{ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8 },84{ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12 },85{ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5 },86{ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12 },87{ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 }88};8990/* Right line */91static const u8 RR_RIPEMD160[5][16] = {92{ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12 },93{ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2 },94{ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13 },95{ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14 },96{ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 }97};98static const u8 SR_RIPEMD160[5][16] = {99{ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6 },100{ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11 },101{ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5 },102{ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8 },103{ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 }104};105106#define RIPEMD160_CORE(a, b, c, d, e, round, idx, w, F, S, R, K) do { \107u32 t = ROTL_RIPEMD160(a + F(b, c, d) + w[R[round][idx]] + K[round], S[round][idx]) + e;\108a = e; e = d; d = ROTL_RIPEMD160(c, 10); c = b; b = t; \109} while(0)110111/* RIPEMD160 core processing */112ATTRIBUTE_WARN_UNUSED_RET static int ripemd160_process(ripemd160_context *ctx,113const u8 data[RIPEMD160_BLOCK_SIZE])114{115/* Left line */116u32 al, bl, cl, dl, el;117/* Right line */118u32 ar, br, cr, dr, er;119/* Temporary data */120u32 tt;121/* Data */122u32 W[16];123unsigned int i;124int ret;125126MUST_HAVE((data != NULL), ret, err);127RIPEMD160_HASH_CHECK_INITIALIZED(ctx, ret, err);128129/* Init our inner variables */130al = ar = ctx->ripemd160_state[0];131bl = br = ctx->ripemd160_state[1];132cl = cr = ctx->ripemd160_state[2];133dl = dr = ctx->ripemd160_state[3];134el = er = ctx->ripemd160_state[4];135136/* Load data */137for (i = 0; i < 16; i++) {138GET_UINT32_LE(W[i], data, (4 * i));139}140141/* Round 1 */142for(i = 0; i < 16; i++){143RIPEMD160_CORE(al, bl, cl, dl, el, 0, i, W, F1_RIPEMD160, SL_RIPEMD160, RL_RIPEMD160, KL_RIPEMD160);144RIPEMD160_CORE(ar, br, cr, dr, er, 0, i, W, F5_RIPEMD160, SR_RIPEMD160, RR_RIPEMD160, KR_RIPEMD160);145}146/* Round 2 */147for(i = 0; i < 16; i++){148RIPEMD160_CORE(al, bl, cl, dl, el, 1, i, W, F2_RIPEMD160, SL_RIPEMD160, RL_RIPEMD160, KL_RIPEMD160);149RIPEMD160_CORE(ar, br, cr, dr, er, 1, i, W, F4_RIPEMD160, SR_RIPEMD160, RR_RIPEMD160, KR_RIPEMD160);150}151/* Round 3 */152for(i = 0; i < 16; i++){153RIPEMD160_CORE(al, bl, cl, dl, el, 2, i, W, F3_RIPEMD160, SL_RIPEMD160, RL_RIPEMD160, KL_RIPEMD160);154RIPEMD160_CORE(ar, br, cr, dr, er, 2, i, W, F3_RIPEMD160, SR_RIPEMD160, RR_RIPEMD160, KR_RIPEMD160);155}156/* Round 4 */157for(i = 0; i < 16; i++){158RIPEMD160_CORE(al, bl, cl, dl, el, 3, i, W, F4_RIPEMD160, SL_RIPEMD160, RL_RIPEMD160, KL_RIPEMD160);159RIPEMD160_CORE(ar, br, cr, dr, er, 3, i, W, F2_RIPEMD160, SR_RIPEMD160, RR_RIPEMD160, KR_RIPEMD160);160}161/* Round 5 */162for(i = 0; i < 16; i++){163RIPEMD160_CORE(al, bl, cl, dl, el, 4, i, W, F5_RIPEMD160, SL_RIPEMD160, RL_RIPEMD160, KL_RIPEMD160);164RIPEMD160_CORE(ar, br, cr, dr, er, 4, i, W, F1_RIPEMD160, SR_RIPEMD160, RR_RIPEMD160, KR_RIPEMD160);165}166167/* Mix the lines and update state */168tt = (ctx->ripemd160_state[1] + cl + dr);169ctx->ripemd160_state[1] = (ctx->ripemd160_state[2] + dl + er);170ctx->ripemd160_state[2] = (ctx->ripemd160_state[3] + el + ar);171ctx->ripemd160_state[3] = (ctx->ripemd160_state[4] + al + br);172ctx->ripemd160_state[4] = (ctx->ripemd160_state[0] + bl + cr);173ctx->ripemd160_state[0] = tt;174175ret = 0;176177err:178return ret;179}180181/* Init hash function */182int ripemd160_init(ripemd160_context *ctx)183{184int ret;185186MUST_HAVE((ctx != NULL), ret, err);187188ctx->ripemd160_total = 0;189ctx->ripemd160_state[0] = 0x67452301;190ctx->ripemd160_state[1] = 0xefcdab89;191ctx->ripemd160_state[2] = 0x98badcfe;192ctx->ripemd160_state[3] = 0x10325476;193ctx->ripemd160_state[4] = 0xc3d2e1f0;194195/* Tell that we are initialized */196ctx->magic = RIPEMD160_HASH_MAGIC;197198ret = 0;199200err:201return ret;202}203204/* Update hash function */205int ripemd160_update(ripemd160_context *ctx, const u8 *input, u32 ilen)206{207const u8 *data_ptr = input;208u32 remain_ilen = ilen;209u16 fill;210u8 left;211int ret;212213MUST_HAVE((input != NULL) || (ilen == 0), ret, err);214RIPEMD160_HASH_CHECK_INITIALIZED(ctx, ret, err);215216/* Nothing to process, return */217if (ilen == 0) {218ret = 0;219goto err;220}221222/* Get what's left in our local buffer */223left = (ctx->ripemd160_total & 0x3F);224fill = (u16)(RIPEMD160_BLOCK_SIZE - left);225226ctx->ripemd160_total += ilen;227228if ((left > 0) && (remain_ilen >= fill)) {229/* Copy data at the end of the buffer */230ret = local_memcpy(ctx->ripemd160_buffer + left, data_ptr, fill); EG(ret, err);231ret = ripemd160_process(ctx, ctx->ripemd160_buffer); EG(ret, err);232data_ptr += fill;233remain_ilen -= fill;234left = 0;235}236237while (remain_ilen >= RIPEMD160_BLOCK_SIZE) {238ret = ripemd160_process(ctx, data_ptr); EG(ret, err);239data_ptr += RIPEMD160_BLOCK_SIZE;240remain_ilen -= RIPEMD160_BLOCK_SIZE;241}242243if (remain_ilen > 0) {244ret = local_memcpy(ctx->ripemd160_buffer + left, data_ptr, remain_ilen); EG(ret, err);245}246247ret = 0;248249err:250return ret;251}252253/* Finalize */254int ripemd160_final(ripemd160_context *ctx, u8 output[RIPEMD160_DIGEST_SIZE])255{256unsigned int block_present = 0;257u8 last_padded_block[2 * RIPEMD160_BLOCK_SIZE];258int ret;259260MUST_HAVE((output != NULL), ret, err);261RIPEMD160_HASH_CHECK_INITIALIZED(ctx, ret, err);262263/* Fill in our last block with zeroes */264ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err);265266/* This is our final step, so we proceed with the padding */267block_present = (ctx->ripemd160_total % RIPEMD160_BLOCK_SIZE);268if (block_present != 0) {269/* Copy what's left in our temporary context buffer */270ret = local_memcpy(last_padded_block, ctx->ripemd160_buffer,271block_present); EG(ret, err);272}273274/* Put the 0x80 byte, beginning of padding */275last_padded_block[block_present] = 0x80;276277/* Handle possible additional block */278if (block_present > (RIPEMD160_BLOCK_SIZE - 1 - sizeof(u64))) {279/* We need an additional block */280PUT_UINT64_LE(8 * ctx->ripemd160_total, last_padded_block,281(2 * RIPEMD160_BLOCK_SIZE) - sizeof(u64));282ret = ripemd160_process(ctx, last_padded_block); EG(ret, err);283ret = ripemd160_process(ctx, last_padded_block + RIPEMD160_BLOCK_SIZE); EG(ret, err);284} else {285/* We do not need an additional block */286PUT_UINT64_LE(8 * ctx->ripemd160_total, last_padded_block,287RIPEMD160_BLOCK_SIZE - sizeof(u64));288ret = ripemd160_process(ctx, last_padded_block); EG(ret, err);289}290291/* Output the hash result */292PUT_UINT32_LE(ctx->ripemd160_state[0], output, 0);293PUT_UINT32_LE(ctx->ripemd160_state[1], output, 4);294PUT_UINT32_LE(ctx->ripemd160_state[2], output, 8);295PUT_UINT32_LE(ctx->ripemd160_state[3], output, 12);296PUT_UINT32_LE(ctx->ripemd160_state[4], output, 16);297298/* Tell that we are uninitialized */299ctx->magic = WORD(0);300301ret = 0;302303err:304return ret;305}306307int ripemd160_scattered(const u8 **inputs, const u32 *ilens,308u8 output[RIPEMD160_DIGEST_SIZE])309{310ripemd160_context ctx;311int ret, pos = 0;312313MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);314315ret = ripemd160_init(&ctx); EG(ret, err);316317while (inputs[pos] != NULL) {318ret = ripemd160_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);319pos += 1;320}321322ret = ripemd160_final(&ctx, output);323324err:325return ret;326}327328int ripemd160(const u8 *input, u32 ilen, u8 output[RIPEMD160_DIGEST_SIZE])329{330ripemd160_context ctx;331int ret;332333ret = ripemd160_init(&ctx); EG(ret, err);334ret = ripemd160_update(&ctx, input, ilen); EG(ret, err);335ret = ripemd160_final(&ctx, output);336337err:338return ret;339}340341#else /* WITH_HASH_RIPEMD160 */342343/*344* Dummy definition to avoid the empty translation unit ISO C warning345*/346typedef int dummy;347#endif /* WITH_HASH_RIPEMD160 */348349350