1*f0865ec9SKyle Evans /* 2*f0865ec9SKyle Evans * Copyright (C) 2021 - This file is part of libecc project 3*f0865ec9SKyle Evans * 4*f0865ec9SKyle Evans * Authors: 5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com> 6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 7*f0865ec9SKyle Evans * 8*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license. 9*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project. 10*f0865ec9SKyle Evans */ 11*f0865ec9SKyle Evans #include "mdc2.h" 12*f0865ec9SKyle Evans 13*f0865ec9SKyle Evans /* Include DES helpers */ 14*f0865ec9SKyle Evans #include "tdes.h" 15*f0865ec9SKyle Evans 16*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_set_padding_type(mdc2_context *ctx, 17*f0865ec9SKyle Evans padding_type p) 18*f0865ec9SKyle Evans { 19*f0865ec9SKyle Evans int ret; 20*f0865ec9SKyle Evans 21*f0865ec9SKyle Evans MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err); 22*f0865ec9SKyle Evans 23*f0865ec9SKyle Evans /* We cannot change the padding type after the first update */ 24*f0865ec9SKyle Evans MUST_HAVE((ctx->mdc2_total == 0), ret, err); 25*f0865ec9SKyle Evans 26*f0865ec9SKyle Evans if((p != ISOIEC10118_TYPE1) && (p != ISOIEC10118_TYPE2)){ 27*f0865ec9SKyle Evans ret = -1; 28*f0865ec9SKyle Evans goto err; 29*f0865ec9SKyle Evans } 30*f0865ec9SKyle Evans 31*f0865ec9SKyle Evans ctx->padding = p; 32*f0865ec9SKyle Evans 33*f0865ec9SKyle Evans ret = 0; 34*f0865ec9SKyle Evans 35*f0865ec9SKyle Evans err: 36*f0865ec9SKyle Evans return ret; 37*f0865ec9SKyle Evans } 38*f0865ec9SKyle Evans 39*f0865ec9SKyle Evans /* MDC-2 core processing. Returns 0 on success, -1 on error. */ 40*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int mdc2_process(mdc2_context *ctx, 41*f0865ec9SKyle Evans const u8 data[MDC2_BLOCK_SIZE]) 42*f0865ec9SKyle Evans { 43*f0865ec9SKyle Evans int ret; 44*f0865ec9SKyle Evans unsigned int j; 45*f0865ec9SKyle Evans u8 V[8], W[8]; 46*f0865ec9SKyle Evans u8 *A, *B; 47*f0865ec9SKyle Evans des_context des_ctx; 48*f0865ec9SKyle Evans 49*f0865ec9SKyle Evans /* Get the current internal state in A and B */ 50*f0865ec9SKyle Evans A = (u8*)&(ctx->mdc2_state[0]); 51*f0865ec9SKyle Evans B = (u8*)&(ctx->mdc2_state[8]); 52*f0865ec9SKyle Evans 53*f0865ec9SKyle Evans A[0] = (u8)((A[0] & 0x9f) | 0x40); 54*f0865ec9SKyle Evans B[0] = (u8)((B[0] & 0x9f) | 0x20); 55*f0865ec9SKyle Evans /* Set odd parity */ 56*f0865ec9SKyle Evans for(j = 0; j < 8; j++){ 57*f0865ec9SKyle Evans A[j] = odd_parity[A[j]]; 58*f0865ec9SKyle Evans B[j] = odd_parity[B[j]]; 59*f0865ec9SKyle Evans } 60*f0865ec9SKyle Evans /* Compute V_i = M_i + E(M_i, A_i) */ 61*f0865ec9SKyle Evans ret = local_memset(&des_ctx, 0, sizeof(des_context)); EG(ret, err); 62*f0865ec9SKyle Evans ret = des_set_key(&des_ctx, A, DES_ENCRYPTION); EG(ret, err); 63*f0865ec9SKyle Evans ret = des(&des_ctx, &data[0], V); EG(ret, err); 64*f0865ec9SKyle Evans for(j = 0; j < 8; j++){ 65*f0865ec9SKyle Evans V[j] = (V[j] ^ data[j]); 66*f0865ec9SKyle Evans } 67*f0865ec9SKyle Evans /* Compute W_i = M_i + E(M_i, B_i) */ 68*f0865ec9SKyle Evans ret = local_memset(&des_ctx, 0, sizeof(des_context)); EG(ret, err); 69*f0865ec9SKyle Evans ret = des_set_key(&des_ctx, B, DES_ENCRYPTION); EG(ret, err); 70*f0865ec9SKyle Evans ret = des(&des_ctx, &data[0], W); EG(ret, err); 71*f0865ec9SKyle Evans for(j = 0; j < 8; j++){ 72*f0865ec9SKyle Evans W[j] = (W[j] ^ data[j]); 73*f0865ec9SKyle Evans } 74*f0865ec9SKyle Evans /* Cross the results */ 75*f0865ec9SKyle Evans /* In A */ 76*f0865ec9SKyle Evans ret = local_memcpy(&A[0], &V[0], 4); EG(ret, err); 77*f0865ec9SKyle Evans ret = local_memcpy(&A[4], &W[4], 4); EG(ret, err); 78*f0865ec9SKyle Evans /* In B */ 79*f0865ec9SKyle Evans ret = local_memcpy(&B[0], &W[0], 4); EG(ret, err); 80*f0865ec9SKyle Evans ret = local_memcpy(&B[4], &V[4], 4); EG(ret, err); 81*f0865ec9SKyle Evans 82*f0865ec9SKyle Evans err: 83*f0865ec9SKyle Evans return ret; 84*f0865ec9SKyle Evans } 85*f0865ec9SKyle Evans 86*f0865ec9SKyle Evans /* Init hash function. Returns 0 on success, -1 on error. */ 87*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_init(mdc2_context *ctx) 88*f0865ec9SKyle Evans { 89*f0865ec9SKyle Evans int ret; 90*f0865ec9SKyle Evans 91*f0865ec9SKyle Evans MUST_HAVE((ctx != NULL), ret, err); 92*f0865ec9SKyle Evans 93*f0865ec9SKyle Evans /* Sanity check on size */ 94*f0865ec9SKyle Evans MUST_HAVE((MDC2_DIGEST_SIZE <= MAX_DIGEST_SIZE), ret, err); 95*f0865ec9SKyle Evans 96*f0865ec9SKyle Evans ctx->mdc2_total = 0; 97*f0865ec9SKyle Evans /* Initialize A1 */ 98*f0865ec9SKyle Evans ret = local_memset(&(ctx->mdc2_state[0]), 0x52, 8); EG(ret, err); 99*f0865ec9SKyle Evans /* Initialize B1 */ 100*f0865ec9SKyle Evans ret = local_memset(&(ctx->mdc2_state[8]), 0x25, 8); EG(ret, err); 101*f0865ec9SKyle Evans /* Initialize default padding type */ 102*f0865ec9SKyle Evans ctx->padding = ISOIEC10118_TYPE1; 103*f0865ec9SKyle Evans 104*f0865ec9SKyle Evans /* Tell that we are initialized */ 105*f0865ec9SKyle Evans ctx->magic = MDC2_HASH_MAGIC; 106*f0865ec9SKyle Evans 107*f0865ec9SKyle Evans ret = 0; 108*f0865ec9SKyle Evans 109*f0865ec9SKyle Evans err: 110*f0865ec9SKyle Evans return ret; 111*f0865ec9SKyle Evans } 112*f0865ec9SKyle Evans 113*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_update(mdc2_context *ctx, const u8 *input, u32 ilen) 114*f0865ec9SKyle Evans { 115*f0865ec9SKyle Evans const u8 *data_ptr = input; 116*f0865ec9SKyle Evans u32 remain_ilen = ilen; 117*f0865ec9SKyle Evans u16 fill; 118*f0865ec9SKyle Evans u8 left; 119*f0865ec9SKyle Evans int ret; 120*f0865ec9SKyle Evans 121*f0865ec9SKyle Evans MUST_HAVE((input != NULL) || (ilen == 0), ret, err); 122*f0865ec9SKyle Evans MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err); 123*f0865ec9SKyle Evans 124*f0865ec9SKyle Evans /* Nothing to process, return */ 125*f0865ec9SKyle Evans if (ilen == 0) { 126*f0865ec9SKyle Evans ret = 0; 127*f0865ec9SKyle Evans goto err; 128*f0865ec9SKyle Evans } 129*f0865ec9SKyle Evans 130*f0865ec9SKyle Evans /* Get what's left in our local buffer */ 131*f0865ec9SKyle Evans left = (ctx->mdc2_total & 0xF); 132*f0865ec9SKyle Evans fill = (u16)(MDC2_BLOCK_SIZE - left); 133*f0865ec9SKyle Evans 134*f0865ec9SKyle Evans ctx->mdc2_total += ilen; 135*f0865ec9SKyle Evans 136*f0865ec9SKyle Evans if ((left > 0) && (remain_ilen >= fill)) { 137*f0865ec9SKyle Evans /* Copy data at the end of the buffer */ 138*f0865ec9SKyle Evans ret = local_memcpy(ctx->mdc2_buffer + left, data_ptr, fill); EG(ret, err); 139*f0865ec9SKyle Evans ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err); 140*f0865ec9SKyle Evans data_ptr += fill; 141*f0865ec9SKyle Evans remain_ilen -= fill; 142*f0865ec9SKyle Evans left = 0; 143*f0865ec9SKyle Evans } 144*f0865ec9SKyle Evans 145*f0865ec9SKyle Evans while (remain_ilen >= MDC2_BLOCK_SIZE) { 146*f0865ec9SKyle Evans ret = mdc2_process(ctx, data_ptr); EG(ret, err); 147*f0865ec9SKyle Evans data_ptr += MDC2_BLOCK_SIZE; 148*f0865ec9SKyle Evans remain_ilen -= MDC2_BLOCK_SIZE; 149*f0865ec9SKyle Evans } 150*f0865ec9SKyle Evans 151*f0865ec9SKyle Evans if (remain_ilen > 0) { 152*f0865ec9SKyle Evans ret = local_memcpy(ctx->mdc2_buffer + left, data_ptr, remain_ilen); EG(ret, err); 153*f0865ec9SKyle Evans } 154*f0865ec9SKyle Evans 155*f0865ec9SKyle Evans ret = 0; 156*f0865ec9SKyle Evans 157*f0865ec9SKyle Evans err: 158*f0865ec9SKyle Evans return ret; 159*f0865ec9SKyle Evans } 160*f0865ec9SKyle Evans 161*f0865ec9SKyle Evans /* Finalize. Returns 0 on success, -1 on error.*/ 162*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_final(mdc2_context *ctx, u8 output[MDC2_DIGEST_SIZE]) 163*f0865ec9SKyle Evans { 164*f0865ec9SKyle Evans int ret; 165*f0865ec9SKyle Evans unsigned int i; 166*f0865ec9SKyle Evans u8 pad_byte; 167*f0865ec9SKyle Evans 168*f0865ec9SKyle Evans MUST_HAVE((output != NULL), ret, err); 169*f0865ec9SKyle Evans MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err); 170*f0865ec9SKyle Evans 171*f0865ec9SKyle Evans if(ctx->padding == ISOIEC10118_TYPE1){ 172*f0865ec9SKyle Evans /* "Padding method 1" in ISO-IEC-10118 */ 173*f0865ec9SKyle Evans /* This is our final step, so we proceed with the padding: the last block 174*f0865ec9SKyle Evans * is padded with zeroes. 175*f0865ec9SKyle Evans */ 176*f0865ec9SKyle Evans pad_byte = 0x00; 177*f0865ec9SKyle Evans if((ctx->mdc2_total % MDC2_BLOCK_SIZE) != 0){ 178*f0865ec9SKyle Evans for(i = (ctx->mdc2_total % MDC2_BLOCK_SIZE); i < MDC2_BLOCK_SIZE; i++){ 179*f0865ec9SKyle Evans ctx->mdc2_buffer[i] = pad_byte; 180*f0865ec9SKyle Evans } 181*f0865ec9SKyle Evans /* And process the block */ 182*f0865ec9SKyle Evans ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err); 183*f0865ec9SKyle Evans } 184*f0865ec9SKyle Evans } 185*f0865ec9SKyle Evans else if(ctx->padding == ISOIEC10118_TYPE2){ 186*f0865ec9SKyle Evans /* "Padding method 2" in ISO-IEC-10118 */ 187*f0865ec9SKyle Evans /* This is our final step, so we proceed with the padding: the last block 188*f0865ec9SKyle Evans * is appended 0x80 and then padded with zeroes. 189*f0865ec9SKyle Evans */ 190*f0865ec9SKyle Evans ctx->mdc2_buffer[(ctx->mdc2_total % MDC2_BLOCK_SIZE)] = 0x80; 191*f0865ec9SKyle Evans pad_byte = 0x00; 192*f0865ec9SKyle Evans for(i = ((unsigned int)(ctx->mdc2_total % MDC2_BLOCK_SIZE) + 1); i < MDC2_BLOCK_SIZE; i++){ 193*f0865ec9SKyle Evans ctx->mdc2_buffer[i] = pad_byte; 194*f0865ec9SKyle Evans } 195*f0865ec9SKyle Evans /* And process the block */ 196*f0865ec9SKyle Evans ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err); 197*f0865ec9SKyle Evans } 198*f0865ec9SKyle Evans else{ 199*f0865ec9SKyle Evans /* Unkown padding */ 200*f0865ec9SKyle Evans ret = -1; 201*f0865ec9SKyle Evans goto err; 202*f0865ec9SKyle Evans } 203*f0865ec9SKyle Evans 204*f0865ec9SKyle Evans /* Output the hash result */ 205*f0865ec9SKyle Evans ret = local_memcpy(output, ctx->mdc2_state, MDC2_DIGEST_SIZE); EG(ret, err); 206*f0865ec9SKyle Evans 207*f0865ec9SKyle Evans /* Tell that we are uninitialized */ 208*f0865ec9SKyle Evans ctx->magic = WORD(0); 209*f0865ec9SKyle Evans 210*f0865ec9SKyle Evans ret = 0; 211*f0865ec9SKyle Evans 212*f0865ec9SKyle Evans err: 213*f0865ec9SKyle Evans return ret; 214*f0865ec9SKyle Evans } 215*f0865ec9SKyle Evans 216*f0865ec9SKyle Evans 217*f0865ec9SKyle Evans /* 218*f0865ec9SKyle Evans * Scattered version performing init/update/finalize on a vector of buffers 219*f0865ec9SKyle Evans * 'inputs' with the length of each buffer passed via 'ilens'. The function 220*f0865ec9SKyle Evans * loops on pointers in 'inputs' until it finds a NULL pointer. The function 221*f0865ec9SKyle Evans * returns 0 on success, -1 on error. 222*f0865ec9SKyle Evans */ 223*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered(const u8 **inputs, const u32 *ilens, 224*f0865ec9SKyle Evans u8 output[MDC2_DIGEST_SIZE], padding_type p) 225*f0865ec9SKyle Evans { 226*f0865ec9SKyle Evans mdc2_context ctx; 227*f0865ec9SKyle Evans int ret, pos = 0; 228*f0865ec9SKyle Evans 229*f0865ec9SKyle Evans MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err); 230*f0865ec9SKyle Evans 231*f0865ec9SKyle Evans ret = mdc2_init(&ctx); EG(ret, err); 232*f0865ec9SKyle Evans 233*f0865ec9SKyle Evans ret = mdc2_set_padding_type(&ctx, p); EG(ret, err); 234*f0865ec9SKyle Evans 235*f0865ec9SKyle Evans while (inputs[pos] != NULL) { 236*f0865ec9SKyle Evans ret = mdc2_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err); 237*f0865ec9SKyle Evans pos += 1; 238*f0865ec9SKyle Evans } 239*f0865ec9SKyle Evans 240*f0865ec9SKyle Evans ret = mdc2_final(&ctx, output); 241*f0865ec9SKyle Evans 242*f0865ec9SKyle Evans err: 243*f0865ec9SKyle Evans return ret; 244*f0865ec9SKyle Evans } 245*f0865ec9SKyle Evans 246*f0865ec9SKyle Evans /* 247*f0865ec9SKyle Evans * Scattered version performing init/update/finalize on a vector of buffers 248*f0865ec9SKyle Evans * 'inputs' with the length of each buffer passed via 'ilens'. The function 249*f0865ec9SKyle Evans * loops on pointers in 'inputs' until it finds a NULL pointer. The function 250*f0865ec9SKyle Evans * returns 0 on success, -1 on error. 251*f0865ec9SKyle Evans */ 252*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered_padding1(const u8 **inputs, const u32 *ilens, 253*f0865ec9SKyle Evans u8 output[MDC2_DIGEST_SIZE]) 254*f0865ec9SKyle Evans { 255*f0865ec9SKyle Evans return mdc2_scattered(inputs, ilens, output, ISOIEC10118_TYPE1); 256*f0865ec9SKyle Evans } 257*f0865ec9SKyle Evans 258*f0865ec9SKyle Evans /* 259*f0865ec9SKyle Evans * Scattered version performing init/update/finalize on a vector of buffers 260*f0865ec9SKyle Evans * 'inputs' with the length of each buffer passed via 'ilens'. The function 261*f0865ec9SKyle Evans * loops on pointers in 'inputs' until it finds a NULL pointer. The function 262*f0865ec9SKyle Evans * returns 0 on success, -1 on error. 263*f0865ec9SKyle Evans */ 264*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered_padding2(const u8 **inputs, const u32 *ilens, 265*f0865ec9SKyle Evans u8 output[MDC2_DIGEST_SIZE]) 266*f0865ec9SKyle Evans { 267*f0865ec9SKyle Evans return mdc2_scattered(inputs, ilens, output, ISOIEC10118_TYPE2); 268*f0865ec9SKyle Evans } 269*f0865ec9SKyle Evans 270*f0865ec9SKyle Evans /* 271*f0865ec9SKyle Evans * Single call version performing init/update/final on given input. 272*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 273*f0865ec9SKyle Evans */ 274*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE], padding_type p) 275*f0865ec9SKyle Evans { 276*f0865ec9SKyle Evans mdc2_context ctx; 277*f0865ec9SKyle Evans int ret; 278*f0865ec9SKyle Evans 279*f0865ec9SKyle Evans ret = mdc2_init(&ctx); EG(ret, err); 280*f0865ec9SKyle Evans ret = mdc2_set_padding_type(&ctx, p); EG(ret, err); 281*f0865ec9SKyle Evans ret = mdc2_update(&ctx, input, ilen); EG(ret, err); 282*f0865ec9SKyle Evans ret = mdc2_final(&ctx, output); 283*f0865ec9SKyle Evans 284*f0865ec9SKyle Evans err: 285*f0865ec9SKyle Evans return ret; 286*f0865ec9SKyle Evans } 287*f0865ec9SKyle Evans 288*f0865ec9SKyle Evans 289*f0865ec9SKyle Evans /* 290*f0865ec9SKyle Evans * Single call version performing init/update/final on given input. 291*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 292*f0865ec9SKyle Evans */ 293*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_padding1(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE]) 294*f0865ec9SKyle Evans { 295*f0865ec9SKyle Evans return mdc2(input, ilen, output, ISOIEC10118_TYPE1); 296*f0865ec9SKyle Evans } 297*f0865ec9SKyle Evans 298*f0865ec9SKyle Evans /* 299*f0865ec9SKyle Evans * Single call version performing init/update/final on given input. 300*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 301*f0865ec9SKyle Evans */ 302*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_padding2(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE]) 303*f0865ec9SKyle Evans { 304*f0865ec9SKyle Evans return mdc2(input, ilen, output, ISOIEC10118_TYPE2); 305*f0865ec9SKyle Evans } 306