Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers md4.c Source File

md4.c

Go to the documentation of this file.
00001 /**
00002  * @file md4.c
00003  * @brief MD4 (Message-Digest Algorithm)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneCrypto Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @section Description
00026  *
00027  * The MD4 algorithm takes as input a message of arbitrary length and produces
00028  * as output a 128-bit message digest of the input. Refer to RFC 1320
00029  *
00030  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00031  * @version 1.7.6
00032  **/
00033 
00034 //Switch to the appropriate trace level
00035 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
00036 
00037 //Dependencies
00038 #include <string.h>
00039 #include "crypto.h"
00040 #include "md4.h"
00041 
00042 //Check crypto library configuration
00043 #if (MD4_SUPPORT == ENABLED)
00044 
00045 //MD4 auxiliary functions
00046 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
00047 #define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
00048 #define H(x, y, z) ((x) ^ (y) ^ (z))
00049 
00050 #define FF(a, b, c, d, x, s) a += F(b, c, d) + (x), a = ROL32(a, s)
00051 #define GG(a, b, c, d, x, s) a += G(b, c, d) + (x) + 0x5A827999, a = ROL32(a, s)
00052 #define HH(a, b, c, d, x, s) a += H(b, c, d) + (x) + 0x6ED9EBA1, a = ROL32(a, s)
00053 
00054 //MD4 padding
00055 static const uint8_t padding[64] =
00056 {
00057    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00058    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00059    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00060    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00061 };
00062 
00063 //MD4 object identifier (1.2.840.113549.2.4)
00064 static const uint8_t md4Oid[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x04};
00065 
00066 //Common interface for hash algorithms
00067 const HashAlgo md4HashAlgo =
00068 {
00069    "MD4",
00070    md4Oid,
00071    sizeof(md4Oid),
00072    sizeof(Md4Context),
00073    MD4_BLOCK_SIZE,
00074    MD4_DIGEST_SIZE,
00075    (HashAlgoCompute) md4Compute,
00076    (HashAlgoInit) md4Init,
00077    (HashAlgoUpdate) md4Update,
00078    (HashAlgoFinal) md4Final
00079 };
00080 
00081 
00082 /**
00083  * @brief Digest a message using MD4
00084  * @param[in] data Pointer to the message being hashed
00085  * @param[in] length Length of the message
00086  * @param[out] digest Pointer to the calculated digest
00087  * @return Error code
00088  **/
00089 
00090 error_t md4Compute(const void *data, size_t length, uint8_t *digest)
00091 {
00092    //Allocate a memory buffer to hold the MD4 context
00093    Md4Context *context = cryptoAllocMem(sizeof(Md4Context));
00094    //Failed to allocate memory?
00095    if(context == NULL)
00096       return ERROR_OUT_OF_MEMORY;
00097 
00098    //Initialize the MD4 context
00099    md4Init(context);
00100    //Digest the message
00101    md4Update(context, data, length);
00102    //Finalize the MD4 message digest
00103    md4Final(context, digest);
00104 
00105    //Free previously allocated memory
00106    cryptoFreeMem(context);
00107    //Successful processing
00108    return NO_ERROR;
00109 }
00110 
00111 
00112 /**
00113  * @brief Initialize MD4 message digest context
00114  * @param[in] context Pointer to the MD4 context to initialize
00115  **/
00116 
00117 void md4Init(Md4Context *context)
00118 {
00119    //Set initial hash value
00120    context->h[0] = 0x67452301;
00121    context->h[1] = 0xEFCDAB89;
00122    context->h[2] = 0x98BADCFE;
00123    context->h[3] = 0x10325476;
00124 
00125    //Number of bytes in the buffer
00126    context->size = 0;
00127    //Total length of the message
00128    context->totalSize = 0;
00129 }
00130 
00131 
00132 /**
00133  * @brief Update the MD4 context with a portion of the message being hashed
00134  * @param[in] context Pointer to the MD4 context
00135  * @param[in] data Pointer to the buffer being hashed
00136  * @param[in] length Length of the buffer
00137  **/
00138 
00139 void md4Update(Md4Context *context, const void *data, size_t length)
00140 {
00141    size_t n;
00142 
00143    //Process the incoming data
00144    while(length > 0)
00145    {
00146       //The buffer can hold at most 64 bytes
00147       n = MIN(length, 64 - context->size);
00148 
00149       //Copy the data to the buffer
00150       memcpy(context->buffer + context->size, data, n);
00151 
00152       //Update the MD4 context
00153       context->size += n;
00154       context->totalSize += n;
00155       //Advance the data pointer
00156       data = (uint8_t *) data + n;
00157       //Remaining bytes to process
00158       length -= n;
00159 
00160       //Process message in 16-word blocks
00161       if(context->size == 64)
00162       {
00163          //Transform the 16-word block
00164          md4ProcessBlock(context);
00165          //Empty the buffer
00166          context->size = 0;
00167       }
00168    }
00169 }
00170 
00171 
00172 /**
00173  * @brief Finish the MD4 message digest
00174  * @param[in] context Pointer to the MD4 context
00175  * @param[out] digest Calculated digest (optional parameter)
00176  **/
00177 
00178 void md4Final(Md4Context *context, uint8_t *digest)
00179 {
00180    uint_t i;
00181    size_t paddingSize;
00182    uint64_t totalSize;
00183 
00184    //Length of the original message (before padding)
00185    totalSize = context->totalSize * 8;
00186 
00187    //Pad the message so that its length is congruent to 56 modulo 64
00188    if(context->size < 56)
00189       paddingSize = 56 - context->size;
00190    else
00191       paddingSize = 64 + 56 - context->size;
00192 
00193    //Append padding
00194    md4Update(context, padding, paddingSize);
00195 
00196    //Append the length of the original message
00197    context->x[14] = htole32((uint32_t) totalSize);
00198    context->x[15] = htole32((uint32_t) (totalSize >> 32));
00199 
00200    //Calculate the message digest
00201    md4ProcessBlock(context);
00202 
00203    //Convert from host byte order to little-endian byte order
00204    for(i = 0; i < 4; i++)
00205       context->h[i] = htole32(context->h[i]);
00206 
00207    //Copy the resulting digest
00208    if(digest != NULL)
00209       memcpy(digest, context->digest, MD4_DIGEST_SIZE);
00210 }
00211 
00212 
00213 /**
00214  * @brief Process message in 16-word blocks
00215  * @param[in] context Pointer to the MD4 context
00216  **/
00217 
00218 void md4ProcessBlock(Md4Context *context)
00219 {
00220    uint_t i;
00221 
00222    //Initialize the 4 working registers
00223    uint32_t a = context->h[0];
00224    uint32_t b = context->h[1];
00225    uint32_t c = context->h[2];
00226    uint32_t d = context->h[3];
00227 
00228    //Process message in 16-word blocks
00229    uint32_t *x = context->x;
00230 
00231    //Convert from little-endian byte order to host byte order
00232    for(i = 0; i < 16; i++)
00233       x[i] = letoh32(x[i]);
00234 
00235    //Round 1
00236    FF(a, b, c, d, x[0],  3);
00237    FF(d, a, b, c, x[1],  7);
00238    FF(c, d, a, b, x[2],  11);
00239    FF(b, c, d, a, x[3],  19);
00240    FF(a, b, c, d, x[4],  3);
00241    FF(d, a, b, c, x[5],  7);
00242    FF(c, d, a, b, x[6],  11);
00243    FF(b, c, d, a, x[7],  19);
00244    FF(a, b, c, d, x[8],  3);
00245    FF(d, a, b, c, x[9],  7);
00246    FF(c, d, a, b, x[10], 11);
00247    FF(b, c, d, a, x[11], 19);
00248    FF(a, b, c, d, x[12], 3);
00249    FF(d, a, b, c, x[13], 7);
00250    FF(c, d, a, b, x[14], 11);
00251    FF(b, c, d, a, x[15], 19);
00252 
00253    //Round 2
00254    GG(a, b, c, d, x[0],  3);
00255    GG(d, a, b, c, x[4],  5);
00256    GG(c, d, a, b, x[8],  9);
00257    GG(b, c, d, a, x[12], 13);
00258    GG(a, b, c, d, x[1],  3);
00259    GG(d, a, b, c, x[5],  5);
00260    GG(c, d, a, b, x[9],  9);
00261    GG(b, c, d, a, x[13], 13);
00262    GG(a, b, c, d, x[2],  3);
00263    GG(d, a, b, c, x[6],  5);
00264    GG(c, d, a, b, x[10], 9);
00265    GG(b, c, d, a, x[14], 13);
00266    GG(a, b, c, d, x[3],  3);
00267    GG(d, a, b, c, x[7],  5);
00268    GG(c, d, a, b, x[11], 9);
00269    GG(b, c, d, a, x[15], 13);
00270 
00271    //Round 3
00272    HH(a, b, c, d, x[0],  3);
00273    HH(d, a, b, c, x[8],  9);
00274    HH(c, d, a, b, x[4],  11);
00275    HH(b, c, d, a, x[12], 15);
00276    HH(a, b, c, d, x[2],  3);
00277    HH(d, a, b, c, x[10], 9);
00278    HH(c, d, a, b, x[6],  11);
00279    HH(b, c, d, a, x[14], 15);
00280    HH(a, b, c, d, x[1],  3);
00281    HH(d, a, b, c, x[9],  9);
00282    HH(c, d, a, b, x[5],  11);
00283    HH(b, c, d, a, x[13], 15);
00284    HH(a, b, c, d, x[3],  3);
00285    HH(d, a, b, c, x[11], 9);
00286    HH(c, d, a, b, x[7],  11);
00287    HH(b, c, d, a, x[15], 15);
00288 
00289    //Update the hash value
00290    context->h[0] += a;
00291    context->h[1] += b;
00292    context->h[2] += c;
00293    context->h[3] += d;
00294 }
00295 
00296 #endif
00297