File Coverage

include/horus_md5.h
Criterion Covered Total %
statement 111 114 97.3
branch 14 16 87.5
condition n/a
subroutine n/a
pod n/a
total 125 130 96.1


line stmt bran cond sub pod time code
1             #ifndef HORUS_MD5_H
2             #define HORUS_MD5_H
3              
4             /*
5             * horus_md5.h - Minimal embedded MD5 implementation (RFC 1321)
6             *
7             * Self-contained, no external dependencies. All functions static
8             * to avoid symbol conflicts with system MD5.
9             */
10              
11             #include
12             #include
13              
14             typedef struct {
15             uint32_t state[4];
16             uint64_t count;
17             unsigned char buffer[64];
18             } horus_md5_ctx;
19              
20             #define HORUS_MD5_F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
21             #define HORUS_MD5_G(x, y, z) (((x) & (z)) | ((y) & (~(z))))
22             #define HORUS_MD5_HH(x, y, z) ((x) ^ (y) ^ (z))
23             #define HORUS_MD5_I(x, y, z) ((y) ^ ((x) | (~(z))))
24             #define HORUS_MD5_ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
25              
26             #define HORUS_MD5_STEP(f, a, b, c, d, x, t, s) \
27             (a) += f((b), (c), (d)) + (x) + (t); \
28             (a) = HORUS_MD5_ROTL((a), (s)); \
29             (a) += (b)
30              
31 80           static inline uint32_t horus_md5_decode32(const unsigned char *p) {
32 80           return (uint32_t)p[0] | ((uint32_t)p[1] << 8)
33 80           | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
34             }
35              
36 5           static void horus_md5_transform(uint32_t state[4], const unsigned char block[64]) {
37 5           uint32_t a = state[0], b = state[1], c = state[2], d = state[3];
38             uint32_t M[16];
39             int i;
40              
41 85 100         for (i = 0; i < 16; i++)
42 80           M[i] = horus_md5_decode32(block + i * 4);
43              
44             /* Round 1 */
45 5           HORUS_MD5_STEP(HORUS_MD5_F, a, b, c, d, M[ 0], 0xd76aa478, 7);
46 5           HORUS_MD5_STEP(HORUS_MD5_F, d, a, b, c, M[ 1], 0xe8c7b756, 12);
47 5           HORUS_MD5_STEP(HORUS_MD5_F, c, d, a, b, M[ 2], 0x242070db, 17);
48 5           HORUS_MD5_STEP(HORUS_MD5_F, b, c, d, a, M[ 3], 0xc1bdceee, 22);
49 5           HORUS_MD5_STEP(HORUS_MD5_F, a, b, c, d, M[ 4], 0xf57c0faf, 7);
50 5           HORUS_MD5_STEP(HORUS_MD5_F, d, a, b, c, M[ 5], 0x4787c62a, 12);
51 5           HORUS_MD5_STEP(HORUS_MD5_F, c, d, a, b, M[ 6], 0xa8304613, 17);
52 5           HORUS_MD5_STEP(HORUS_MD5_F, b, c, d, a, M[ 7], 0xfd469501, 22);
53 5           HORUS_MD5_STEP(HORUS_MD5_F, a, b, c, d, M[ 8], 0x698098d8, 7);
54 5           HORUS_MD5_STEP(HORUS_MD5_F, d, a, b, c, M[ 9], 0x8b44f7af, 12);
55 5           HORUS_MD5_STEP(HORUS_MD5_F, c, d, a, b, M[10], 0xffff5bb1, 17);
56 5           HORUS_MD5_STEP(HORUS_MD5_F, b, c, d, a, M[11], 0x895cd7be, 22);
57 5           HORUS_MD5_STEP(HORUS_MD5_F, a, b, c, d, M[12], 0x6b901122, 7);
58 5           HORUS_MD5_STEP(HORUS_MD5_F, d, a, b, c, M[13], 0xfd987193, 12);
59 5           HORUS_MD5_STEP(HORUS_MD5_F, c, d, a, b, M[14], 0xa679438e, 17);
60 5           HORUS_MD5_STEP(HORUS_MD5_F, b, c, d, a, M[15], 0x49b40821, 22);
61              
62             /* Round 2 */
63 5           HORUS_MD5_STEP(HORUS_MD5_G, a, b, c, d, M[ 1], 0xf61e2562, 5);
64 5           HORUS_MD5_STEP(HORUS_MD5_G, d, a, b, c, M[ 6], 0xc040b340, 9);
65 5           HORUS_MD5_STEP(HORUS_MD5_G, c, d, a, b, M[11], 0x265e5a51, 14);
66 5           HORUS_MD5_STEP(HORUS_MD5_G, b, c, d, a, M[ 0], 0xe9b6c7aa, 20);
67 5           HORUS_MD5_STEP(HORUS_MD5_G, a, b, c, d, M[ 5], 0xd62f105d, 5);
68 5           HORUS_MD5_STEP(HORUS_MD5_G, d, a, b, c, M[10], 0x02441453, 9);
69 5           HORUS_MD5_STEP(HORUS_MD5_G, c, d, a, b, M[15], 0xd8a1e681, 14);
70 5           HORUS_MD5_STEP(HORUS_MD5_G, b, c, d, a, M[ 4], 0xe7d3fbc8, 20);
71 5           HORUS_MD5_STEP(HORUS_MD5_G, a, b, c, d, M[ 9], 0x21e1cde6, 5);
72 5           HORUS_MD5_STEP(HORUS_MD5_G, d, a, b, c, M[14], 0xc33707d6, 9);
73 5           HORUS_MD5_STEP(HORUS_MD5_G, c, d, a, b, M[ 3], 0xf4d50d87, 14);
74 5           HORUS_MD5_STEP(HORUS_MD5_G, b, c, d, a, M[ 8], 0x455a14ed, 20);
75 5           HORUS_MD5_STEP(HORUS_MD5_G, a, b, c, d, M[13], 0xa9e3e905, 5);
76 5           HORUS_MD5_STEP(HORUS_MD5_G, d, a, b, c, M[ 2], 0xfcefa3f8, 9);
77 5           HORUS_MD5_STEP(HORUS_MD5_G, c, d, a, b, M[ 7], 0x676f02d9, 14);
78 5           HORUS_MD5_STEP(HORUS_MD5_G, b, c, d, a, M[12], 0x8d2a4c8a, 20);
79              
80             /* Round 3 */
81 5           HORUS_MD5_STEP(HORUS_MD5_HH, a, b, c, d, M[ 5], 0xfffa3942, 4);
82 5           HORUS_MD5_STEP(HORUS_MD5_HH, d, a, b, c, M[ 8], 0x8771f681, 11);
83 5           HORUS_MD5_STEP(HORUS_MD5_HH, c, d, a, b, M[11], 0x6d9d6122, 16);
84 5           HORUS_MD5_STEP(HORUS_MD5_HH, b, c, d, a, M[14], 0xfde5380c, 23);
85 5           HORUS_MD5_STEP(HORUS_MD5_HH, a, b, c, d, M[ 1], 0xa4beea44, 4);
86 5           HORUS_MD5_STEP(HORUS_MD5_HH, d, a, b, c, M[ 4], 0x4bdecfa9, 11);
87 5           HORUS_MD5_STEP(HORUS_MD5_HH, c, d, a, b, M[ 7], 0xf6bb4b60, 16);
88 5           HORUS_MD5_STEP(HORUS_MD5_HH, b, c, d, a, M[10], 0xbebfbc70, 23);
89 5           HORUS_MD5_STEP(HORUS_MD5_HH, a, b, c, d, M[13], 0x289b7ec6, 4);
90 5           HORUS_MD5_STEP(HORUS_MD5_HH, d, a, b, c, M[ 0], 0xeaa127fa, 11);
91 5           HORUS_MD5_STEP(HORUS_MD5_HH, c, d, a, b, M[ 3], 0xd4ef3085, 16);
92 5           HORUS_MD5_STEP(HORUS_MD5_HH, b, c, d, a, M[ 6], 0x04881d05, 23);
93 5           HORUS_MD5_STEP(HORUS_MD5_HH, a, b, c, d, M[ 9], 0xd9d4d039, 4);
94 5           HORUS_MD5_STEP(HORUS_MD5_HH, d, a, b, c, M[12], 0xe6db99e5, 11);
95 5           HORUS_MD5_STEP(HORUS_MD5_HH, c, d, a, b, M[15], 0x1fa27cf8, 16);
96 5           HORUS_MD5_STEP(HORUS_MD5_HH, b, c, d, a, M[ 2], 0xc4ac5665, 23);
97              
98             /* Round 4 */
99 5           HORUS_MD5_STEP(HORUS_MD5_I, a, b, c, d, M[ 0], 0xf4292244, 6);
100 5           HORUS_MD5_STEP(HORUS_MD5_I, d, a, b, c, M[ 7], 0x432aff97, 10);
101 5           HORUS_MD5_STEP(HORUS_MD5_I, c, d, a, b, M[14], 0xab9423a7, 15);
102 5           HORUS_MD5_STEP(HORUS_MD5_I, b, c, d, a, M[ 5], 0xfc93a039, 21);
103 5           HORUS_MD5_STEP(HORUS_MD5_I, a, b, c, d, M[12], 0x655b59c3, 6);
104 5           HORUS_MD5_STEP(HORUS_MD5_I, d, a, b, c, M[ 3], 0x8f0ccc92, 10);
105 5           HORUS_MD5_STEP(HORUS_MD5_I, c, d, a, b, M[10], 0xffeff47d, 15);
106 5           HORUS_MD5_STEP(HORUS_MD5_I, b, c, d, a, M[ 1], 0x85845dd1, 21);
107 5           HORUS_MD5_STEP(HORUS_MD5_I, a, b, c, d, M[ 8], 0x6fa87e4f, 6);
108 5           HORUS_MD5_STEP(HORUS_MD5_I, d, a, b, c, M[15], 0xfe2ce6e0, 10);
109 5           HORUS_MD5_STEP(HORUS_MD5_I, c, d, a, b, M[ 6], 0xa3014314, 15);
110 5           HORUS_MD5_STEP(HORUS_MD5_I, b, c, d, a, M[13], 0x4e0811a1, 21);
111 5           HORUS_MD5_STEP(HORUS_MD5_I, a, b, c, d, M[ 4], 0xf7537e82, 6);
112 5           HORUS_MD5_STEP(HORUS_MD5_I, d, a, b, c, M[11], 0xbd3af235, 10);
113 5           HORUS_MD5_STEP(HORUS_MD5_I, c, d, a, b, M[ 2], 0x2ad7d2bb, 15);
114 5           HORUS_MD5_STEP(HORUS_MD5_I, b, c, d, a, M[ 9], 0xeb86d391, 21);
115              
116 5           state[0] += a;
117 5           state[1] += b;
118 5           state[2] += c;
119 5           state[3] += d;
120 5           }
121              
122 5           static inline void horus_md5_init(horus_md5_ctx *ctx) {
123 5           ctx->count = 0;
124 5           ctx->state[0] = 0x67452301;
125 5           ctx->state[1] = 0xefcdab89;
126 5           ctx->state[2] = 0x98badcfe;
127 5           ctx->state[3] = 0x10325476;
128 5           }
129              
130 20           static inline void horus_md5_update(horus_md5_ctx *ctx,
131             const unsigned char *data, size_t len) {
132 20           size_t index = (size_t)(ctx->count & 0x3F);
133 20           ctx->count += len;
134              
135 20 100         if (index) {
136 15           size_t part_len = 64 - index;
137 15 100         if (len >= part_len) {
138 5           memcpy(ctx->buffer + index, data, part_len);
139 5           horus_md5_transform(ctx->state, ctx->buffer);
140 5           data += part_len;
141 5           len -= part_len;
142             } else {
143 10           memcpy(ctx->buffer + index, data, len);
144 10           return;
145             }
146             }
147              
148 10 50         while (len >= 64) {
149 0           horus_md5_transform(ctx->state, data);
150 0           data += 64;
151 0           len -= 64;
152             }
153              
154 10 100         if (len)
155 5           memcpy(ctx->buffer, data, len);
156             }
157              
158 5           static inline void horus_md5_final(unsigned char digest[16], horus_md5_ctx *ctx) {
159             static const unsigned char padding[64] = { 0x80 };
160             unsigned char bits[8];
161 5           uint64_t bit_count = ctx->count << 3;
162             size_t index;
163             int i;
164              
165             /* Encode bit count as little-endian */
166 45 100         for (i = 0; i < 8; i++)
167 40           bits[i] = (unsigned char)(bit_count >> (i * 8));
168              
169             /* Pad to 56 mod 64 */
170 5           index = (size_t)(ctx->count & 0x3F);
171 5 50         horus_md5_update(ctx, padding, (index < 56) ? (56 - index) : (120 - index));
172              
173             /* Append length */
174 5           horus_md5_update(ctx, bits, 8);
175              
176             /* Encode state as little-endian */
177 25 100         for (i = 0; i < 4; i++) {
178 20           digest[i*4 + 0] = (unsigned char)(ctx->state[i]);
179 20           digest[i*4 + 1] = (unsigned char)(ctx->state[i] >> 8);
180 20           digest[i*4 + 2] = (unsigned char)(ctx->state[i] >> 16);
181 20           digest[i*4 + 3] = (unsigned char)(ctx->state[i] >> 24);
182             }
183 5           }
184              
185             /* Convenience: hash data in one shot */
186             static inline void horus_md5(unsigned char digest[16],
187             const unsigned char *data, size_t len) {
188             horus_md5_ctx ctx;
189             horus_md5_init(&ctx);
190             horus_md5_update(&ctx, data, len);
191             horus_md5_final(digest, &ctx);
192             }
193              
194             #endif /* HORUS_MD5_H */