Path: blob/main/crypto/libecc/src/examples/hash/mdc2.c
34889 views
/*1* Copyright (C) 2021 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[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 "mdc2.h"1112/* Include DES helpers */13#include "tdes.h"1415ATTRIBUTE_WARN_UNUSED_RET int mdc2_set_padding_type(mdc2_context *ctx,16padding_type p)17{18int ret;1920MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err);2122/* We cannot change the padding type after the first update */23MUST_HAVE((ctx->mdc2_total == 0), ret, err);2425if((p != ISOIEC10118_TYPE1) && (p != ISOIEC10118_TYPE2)){26ret = -1;27goto err;28}2930ctx->padding = p;3132ret = 0;3334err:35return ret;36}3738/* MDC-2 core processing. Returns 0 on success, -1 on error. */39ATTRIBUTE_WARN_UNUSED_RET static inline int mdc2_process(mdc2_context *ctx,40const u8 data[MDC2_BLOCK_SIZE])41{42int ret;43unsigned int j;44u8 V[8], W[8];45u8 *A, *B;46des_context des_ctx;4748/* Get the current internal state in A and B */49A = (u8*)&(ctx->mdc2_state[0]);50B = (u8*)&(ctx->mdc2_state[8]);5152A[0] = (u8)((A[0] & 0x9f) | 0x40);53B[0] = (u8)((B[0] & 0x9f) | 0x20);54/* Set odd parity */55for(j = 0; j < 8; j++){56A[j] = odd_parity[A[j]];57B[j] = odd_parity[B[j]];58}59/* Compute V_i = M_i + E(M_i, A_i) */60ret = local_memset(&des_ctx, 0, sizeof(des_context)); EG(ret, err);61ret = des_set_key(&des_ctx, A, DES_ENCRYPTION); EG(ret, err);62ret = des(&des_ctx, &data[0], V); EG(ret, err);63for(j = 0; j < 8; j++){64V[j] = (V[j] ^ data[j]);65}66/* Compute W_i = M_i + E(M_i, B_i) */67ret = local_memset(&des_ctx, 0, sizeof(des_context)); EG(ret, err);68ret = des_set_key(&des_ctx, B, DES_ENCRYPTION); EG(ret, err);69ret = des(&des_ctx, &data[0], W); EG(ret, err);70for(j = 0; j < 8; j++){71W[j] = (W[j] ^ data[j]);72}73/* Cross the results */74/* In A */75ret = local_memcpy(&A[0], &V[0], 4); EG(ret, err);76ret = local_memcpy(&A[4], &W[4], 4); EG(ret, err);77/* In B */78ret = local_memcpy(&B[0], &W[0], 4); EG(ret, err);79ret = local_memcpy(&B[4], &V[4], 4); EG(ret, err);8081err:82return ret;83}8485/* Init hash function. Returns 0 on success, -1 on error. */86ATTRIBUTE_WARN_UNUSED_RET int mdc2_init(mdc2_context *ctx)87{88int ret;8990MUST_HAVE((ctx != NULL), ret, err);9192/* Sanity check on size */93MUST_HAVE((MDC2_DIGEST_SIZE <= MAX_DIGEST_SIZE), ret, err);9495ctx->mdc2_total = 0;96/* Initialize A1 */97ret = local_memset(&(ctx->mdc2_state[0]), 0x52, 8); EG(ret, err);98/* Initialize B1 */99ret = local_memset(&(ctx->mdc2_state[8]), 0x25, 8); EG(ret, err);100/* Initialize default padding type */101ctx->padding = ISOIEC10118_TYPE1;102103/* Tell that we are initialized */104ctx->magic = MDC2_HASH_MAGIC;105106ret = 0;107108err:109return ret;110}111112ATTRIBUTE_WARN_UNUSED_RET int mdc2_update(mdc2_context *ctx, const u8 *input, u32 ilen)113{114const u8 *data_ptr = input;115u32 remain_ilen = ilen;116u16 fill;117u8 left;118int ret;119120MUST_HAVE((input != NULL) || (ilen == 0), ret, err);121MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err);122123/* Nothing to process, return */124if (ilen == 0) {125ret = 0;126goto err;127}128129/* Get what's left in our local buffer */130left = (ctx->mdc2_total & 0xF);131fill = (u16)(MDC2_BLOCK_SIZE - left);132133ctx->mdc2_total += ilen;134135if ((left > 0) && (remain_ilen >= fill)) {136/* Copy data at the end of the buffer */137ret = local_memcpy(ctx->mdc2_buffer + left, data_ptr, fill); EG(ret, err);138ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err);139data_ptr += fill;140remain_ilen -= fill;141left = 0;142}143144while (remain_ilen >= MDC2_BLOCK_SIZE) {145ret = mdc2_process(ctx, data_ptr); EG(ret, err);146data_ptr += MDC2_BLOCK_SIZE;147remain_ilen -= MDC2_BLOCK_SIZE;148}149150if (remain_ilen > 0) {151ret = local_memcpy(ctx->mdc2_buffer + left, data_ptr, remain_ilen); EG(ret, err);152}153154ret = 0;155156err:157return ret;158}159160/* Finalize. Returns 0 on success, -1 on error.*/161ATTRIBUTE_WARN_UNUSED_RET int mdc2_final(mdc2_context *ctx, u8 output[MDC2_DIGEST_SIZE])162{163int ret;164unsigned int i;165u8 pad_byte;166167MUST_HAVE((output != NULL), ret, err);168MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err);169170if(ctx->padding == ISOIEC10118_TYPE1){171/* "Padding method 1" in ISO-IEC-10118 */172/* This is our final step, so we proceed with the padding: the last block173* is padded with zeroes.174*/175pad_byte = 0x00;176if((ctx->mdc2_total % MDC2_BLOCK_SIZE) != 0){177for(i = (ctx->mdc2_total % MDC2_BLOCK_SIZE); i < MDC2_BLOCK_SIZE; i++){178ctx->mdc2_buffer[i] = pad_byte;179}180/* And process the block */181ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err);182}183}184else if(ctx->padding == ISOIEC10118_TYPE2){185/* "Padding method 2" in ISO-IEC-10118 */186/* This is our final step, so we proceed with the padding: the last block187* is appended 0x80 and then padded with zeroes.188*/189ctx->mdc2_buffer[(ctx->mdc2_total % MDC2_BLOCK_SIZE)] = 0x80;190pad_byte = 0x00;191for(i = ((unsigned int)(ctx->mdc2_total % MDC2_BLOCK_SIZE) + 1); i < MDC2_BLOCK_SIZE; i++){192ctx->mdc2_buffer[i] = pad_byte;193}194/* And process the block */195ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err);196}197else{198/* Unkown padding */199ret = -1;200goto err;201}202203/* Output the hash result */204ret = local_memcpy(output, ctx->mdc2_state, MDC2_DIGEST_SIZE); EG(ret, err);205206/* Tell that we are uninitialized */207ctx->magic = WORD(0);208209ret = 0;210211err:212return ret;213}214215216/*217* Scattered version performing init/update/finalize on a vector of buffers218* 'inputs' with the length of each buffer passed via 'ilens'. The function219* loops on pointers in 'inputs' until it finds a NULL pointer. The function220* returns 0 on success, -1 on error.221*/222ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered(const u8 **inputs, const u32 *ilens,223u8 output[MDC2_DIGEST_SIZE], padding_type p)224{225mdc2_context ctx;226int ret, pos = 0;227228MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);229230ret = mdc2_init(&ctx); EG(ret, err);231232ret = mdc2_set_padding_type(&ctx, p); EG(ret, err);233234while (inputs[pos] != NULL) {235ret = mdc2_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);236pos += 1;237}238239ret = mdc2_final(&ctx, output);240241err:242return ret;243}244245/*246* Scattered version performing init/update/finalize on a vector of buffers247* 'inputs' with the length of each buffer passed via 'ilens'. The function248* loops on pointers in 'inputs' until it finds a NULL pointer. The function249* returns 0 on success, -1 on error.250*/251ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered_padding1(const u8 **inputs, const u32 *ilens,252u8 output[MDC2_DIGEST_SIZE])253{254return mdc2_scattered(inputs, ilens, output, ISOIEC10118_TYPE1);255}256257/*258* Scattered version performing init/update/finalize on a vector of buffers259* 'inputs' with the length of each buffer passed via 'ilens'. The function260* loops on pointers in 'inputs' until it finds a NULL pointer. The function261* returns 0 on success, -1 on error.262*/263ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered_padding2(const u8 **inputs, const u32 *ilens,264u8 output[MDC2_DIGEST_SIZE])265{266return mdc2_scattered(inputs, ilens, output, ISOIEC10118_TYPE2);267}268269/*270* Single call version performing init/update/final on given input.271* Returns 0 on success, -1 on error.272*/273ATTRIBUTE_WARN_UNUSED_RET int mdc2(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE], padding_type p)274{275mdc2_context ctx;276int ret;277278ret = mdc2_init(&ctx); EG(ret, err);279ret = mdc2_set_padding_type(&ctx, p); EG(ret, err);280ret = mdc2_update(&ctx, input, ilen); EG(ret, err);281ret = mdc2_final(&ctx, output);282283err:284return ret;285}286287288/*289* Single call version performing init/update/final on given input.290* Returns 0 on success, -1 on error.291*/292ATTRIBUTE_WARN_UNUSED_RET int mdc2_padding1(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE])293{294return mdc2(input, ilen, output, ISOIEC10118_TYPE1);295}296297/*298* Single call version performing init/update/final on given input.299* Returns 0 on success, -1 on error.300*/301ATTRIBUTE_WARN_UNUSED_RET int mdc2_padding2(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE])302{303return mdc2(input, ilen, output, ISOIEC10118_TYPE2);304}305306307