File Coverage

_md4.c
Criterion Covered Total %
statement 79 96 82.2
branch 7 18 38.8
condition n/a
subroutine n/a
pod n/a
total 86 114 75.4


line stmt bran cond sub pod time code
1             /* md4.c - an implementation of MD4 Message-Digest Algorithm based on RFC 1320.
2             *
3             * Copyright: 2007-2012 Aleksey Kravchenko
4             *
5             * Permission is hereby granted, free of charge, to any person obtaining a
6             * copy of this software and associated documentation files (the "Software"),
7             * to deal in the Software without restriction, including without limitation
8             * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9             * and/or sell copies of the Software, and to permit persons to whom the
10             * Software is furnished to do so.
11             *
12             * This program is distributed in the hope that it will be useful, but
13             * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14             * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
15             */
16              
17             #include
18             #include "byte_order.h"
19             #include "md4.h"
20              
21             /**
22             * Initialize context before calculaing hash.
23             *
24             * @param ctx context to initialize
25             */
26 7           void rhash_md4_init(md4_ctx *ctx)
27             {
28 7           ctx->length = 0;
29              
30             /* initialize state */
31 7           ctx->hash[0] = 0x67452301;
32 7           ctx->hash[1] = 0xefcdab89;
33 7           ctx->hash[2] = 0x98badcfe;
34 7           ctx->hash[3] = 0x10325476;
35 7           }
36              
37             /* First, define three auxiliary functions that each take as input
38             * three 32-bit words and returns a 32-bit word.
39             * F(x,y,z) = XY v not(X) Z = ((Y xor Z) X) xor Z (the last form is faster)
40             * G(X,Y,Z) = XY v XZ v YZ
41             * H(X,Y,Z) = X xor Y xor Z */
42              
43             #define MD4_F(x, y, z) ((((y) ^ (z)) & (x)) ^ (z))
44             #define MD4_G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
45             #define MD4_H(x, y, z) ((x) ^ (y) ^ (z))
46              
47             /* transformations for rounds 1, 2, and 3. */
48             #define MD4_ROUND1(a, b, c, d, x, s) { \
49             (a) += MD4_F((b), (c), (d)) + (x); \
50             (a) = ROTL32((a), (s)); \
51             }
52             #define MD4_ROUND2(a, b, c, d, x, s) { \
53             (a) += MD4_G((b), (c), (d)) + (x) + 0x5a827999; \
54             (a) = ROTL32((a), (s)); \
55             }
56             #define MD4_ROUND3(a, b, c, d, x, s) { \
57             (a) += MD4_H((b), (c), (d)) + (x) + 0x6ed9eba1; \
58             (a) = ROTL32((a), (s)); \
59             }
60              
61             /**
62             * The core transformation. Process a 512-bit block.
63             * The function has been taken from RFC 1320 with little changes.
64             *
65             * @param state algorithm state
66             * @param x the message block to process
67             */
68 5           static void rhash_md4_process_block(unsigned state[4], const unsigned* x)
69             {
70             register unsigned a, b, c, d;
71 5           a = state[0], b = state[1], c = state[2], d = state[3];
72              
73 5           MD4_ROUND1(a, b, c, d, x[ 0], 3);
74 5           MD4_ROUND1(d, a, b, c, x[ 1], 7);
75 5           MD4_ROUND1(c, d, a, b, x[ 2], 11);
76 5           MD4_ROUND1(b, c, d, a, x[ 3], 19);
77 5           MD4_ROUND1(a, b, c, d, x[ 4], 3);
78 5           MD4_ROUND1(d, a, b, c, x[ 5], 7);
79 5           MD4_ROUND1(c, d, a, b, x[ 6], 11);
80 5           MD4_ROUND1(b, c, d, a, x[ 7], 19);
81 5           MD4_ROUND1(a, b, c, d, x[ 8], 3);
82 5           MD4_ROUND1(d, a, b, c, x[ 9], 7);
83 5           MD4_ROUND1(c, d, a, b, x[10], 11);
84 5           MD4_ROUND1(b, c, d, a, x[11], 19);
85 5           MD4_ROUND1(a, b, c, d, x[12], 3);
86 5           MD4_ROUND1(d, a, b, c, x[13], 7);
87 5           MD4_ROUND1(c, d, a, b, x[14], 11);
88 5           MD4_ROUND1(b, c, d, a, x[15], 19);
89              
90 5           MD4_ROUND2(a, b, c, d, x[ 0], 3);
91 5           MD4_ROUND2(d, a, b, c, x[ 4], 5);
92 5           MD4_ROUND2(c, d, a, b, x[ 8], 9);
93 5           MD4_ROUND2(b, c, d, a, x[12], 13);
94 5           MD4_ROUND2(a, b, c, d, x[ 1], 3);
95 5           MD4_ROUND2(d, a, b, c, x[ 5], 5);
96 5           MD4_ROUND2(c, d, a, b, x[ 9], 9);
97 5           MD4_ROUND2(b, c, d, a, x[13], 13);
98 5           MD4_ROUND2(a, b, c, d, x[ 2], 3);
99 5           MD4_ROUND2(d, a, b, c, x[ 6], 5);
100 5           MD4_ROUND2(c, d, a, b, x[10], 9);
101 5           MD4_ROUND2(b, c, d, a, x[14], 13);
102 5           MD4_ROUND2(a, b, c, d, x[ 3], 3);
103 5           MD4_ROUND2(d, a, b, c, x[ 7], 5);
104 5           MD4_ROUND2(c, d, a, b, x[11], 9);
105 5           MD4_ROUND2(b, c, d, a, x[15], 13);
106              
107 5           MD4_ROUND3(a, b, c, d, x[ 0], 3);
108 5           MD4_ROUND3(d, a, b, c, x[ 8], 9);
109 5           MD4_ROUND3(c, d, a, b, x[ 4], 11);
110 5           MD4_ROUND3(b, c, d, a, x[12], 15);
111 5           MD4_ROUND3(a, b, c, d, x[ 2], 3);
112 5           MD4_ROUND3(d, a, b, c, x[10], 9);
113 5           MD4_ROUND3(c, d, a, b, x[ 6], 11);
114 5           MD4_ROUND3(b, c, d, a, x[14], 15);
115 5           MD4_ROUND3(a, b, c, d, x[ 1], 3);
116 5           MD4_ROUND3(d, a, b, c, x[ 9], 9);
117 5           MD4_ROUND3(c, d, a, b, x[ 5], 11);
118 5           MD4_ROUND3(b, c, d, a, x[13], 15);
119 5           MD4_ROUND3(a, b, c, d, x[ 3], 3);
120 5           MD4_ROUND3(d, a, b, c, x[11], 9);
121 5           MD4_ROUND3(c, d, a, b, x[ 7], 11);
122 5           MD4_ROUND3(b, c, d, a, x[15], 15);
123              
124 5           state[0] += a, state[1] += b, state[2] += c, state[3] += d;
125 5           }
126              
127             /**
128             * Calculate message hash.
129             * Can be called repeatedly with chunks of the message to be hashed.
130             *
131             * @param ctx the algorithm context containing current hashing state
132             * @param msg message chunk
133             * @param size length of the message chunk
134             */
135 5           void rhash_md4_update(md4_ctx *ctx, const unsigned char* msg, size_t size)
136             {
137 5           unsigned index = (unsigned)ctx->length & 63;
138 5           ctx->length += size;
139              
140             /* fill partial block */
141 5 50         if (index) {
142 0           unsigned left = md4_block_size - index;
143 0           le32_copy((char*)ctx->message, index, msg, (size < left ? size : left));
144 0 0         if (size < left) return;
145              
146             /* process partial block */
147 0           rhash_md4_process_block(ctx->hash, ctx->message);
148 0           msg += left;
149 0           size -= left;
150             }
151 5 50         while (size >= md4_block_size) {
152             unsigned* aligned_message_block;
153 0 0         if (IS_LITTLE_ENDIAN && IS_ALIGNED_32(msg)) {
154             /* the most common case is processing a 32-bit aligned message
155             on a little-endian CPU without copying it */
156 0           aligned_message_block = (unsigned*)msg;
157             } else {
158 0           le32_copy(ctx->message, 0, msg, md4_block_size);
159 0           aligned_message_block = ctx->message;
160             }
161              
162 0           rhash_md4_process_block(ctx->hash, aligned_message_block);
163 0           msg += md4_block_size;
164 0           size -= md4_block_size;
165             }
166 5 50         if (size) {
167             /* save leftovers */
168 5           le32_copy(ctx->message, 0, msg, size);
169             }
170             }
171              
172             /**
173             * Store calculated hash into the given array.
174             *
175             * @param ctx the algorithm context containing current hashing state
176             * @param result calculated hash in binary form
177             */
178 5           void rhash_md4_final(md4_ctx *ctx, unsigned char result[16])
179             {
180 5           unsigned index = ((unsigned)ctx->length & 63) >> 2;
181 5           unsigned shift = ((unsigned)ctx->length & 3) * 8;
182              
183             /* pad message and run for last block */
184              
185             /* append the byte 0x80 to the message */
186 5           ctx->message[index] &= ~(0xFFFFFFFFu << shift);
187 5           ctx->message[index++] ^= 0x80u << shift;
188              
189             /* if no room left in the message to store 64-bit message length */
190 5 50         if (index > 14) {
191             /* then fill the rest with zeros and process it */
192 0 0         while (index < 16) {
193 0           ctx->message[index++] = 0;
194             }
195 0           rhash_md4_process_block(ctx->hash, ctx->message);
196 0           index = 0;
197             }
198 70 100         while (index < 14) {
199 65           ctx->message[index++] = 0;
200             }
201 5           ctx->message[14] = (unsigned)(ctx->length << 3);
202 5           ctx->message[15] = (unsigned)(ctx->length >> 29);
203 5           rhash_md4_process_block(ctx->hash, ctx->message);
204              
205 5 50         if (result) le32_copy(result, 0, &ctx->hash, 16);
206 5           }