File Coverage

include/horus_sha1.h
Criterion Covered Total %
statement 69 72 95.8
branch 24 26 92.3
condition n/a
subroutine n/a
pod n/a
total 93 98 94.9


line stmt bran cond sub pod time code
1             #ifndef HORUS_SHA1_H
2             #define HORUS_SHA1_H
3              
4             /*
5             * horus_sha1.h - Minimal embedded SHA-1 implementation (RFC 3174)
6             *
7             * Self-contained, no external dependencies. All functions static
8             * to avoid symbol conflicts with system SHA1.
9             */
10              
11             #include
12             #include
13              
14             typedef struct {
15             uint32_t state[5];
16             uint64_t count;
17             unsigned char buffer[64];
18             } horus_sha1_ctx;
19              
20             #define HORUS_SHA1_ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
21              
22 80           static inline uint32_t horus_sha1_decode32be(const unsigned char *p) {
23 80           return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16)
24 80           | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
25             }
26              
27 5           static void horus_sha1_transform(uint32_t state[5], const unsigned char block[64]) {
28             uint32_t W[80];
29             uint32_t a, b, c, d, e;
30             int t;
31              
32 85 100         for (t = 0; t < 16; t++)
33 80           W[t] = horus_sha1_decode32be(block + t * 4);
34 325 100         for (t = 16; t < 80; t++)
35 320           W[t] = HORUS_SHA1_ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
36              
37 5           a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4];
38              
39 105 100         for (t = 0; t < 20; t++) {
40 100           uint32_t tmp = HORUS_SHA1_ROTL(a, 5) + ((b & c) | ((~b) & d))
41 100           + e + W[t] + 0x5A827999;
42 100           e = d; d = c; c = HORUS_SHA1_ROTL(b, 30); b = a; a = tmp;
43             }
44 105 100         for (t = 20; t < 40; t++) {
45 100           uint32_t tmp = HORUS_SHA1_ROTL(a, 5) + (b ^ c ^ d)
46 100           + e + W[t] + 0x6ED9EBA1;
47 100           e = d; d = c; c = HORUS_SHA1_ROTL(b, 30); b = a; a = tmp;
48             }
49 105 100         for (t = 40; t < 60; t++) {
50 100           uint32_t tmp = HORUS_SHA1_ROTL(a, 5) + ((b & c) | (b & d) | (c & d))
51 100           + e + W[t] + 0x8F1BBCDC;
52 100           e = d; d = c; c = HORUS_SHA1_ROTL(b, 30); b = a; a = tmp;
53             }
54 105 100         for (t = 60; t < 80; t++) {
55 100           uint32_t tmp = HORUS_SHA1_ROTL(a, 5) + (b ^ c ^ d)
56 100           + e + W[t] + 0xCA62C1D6;
57 100           e = d; d = c; c = HORUS_SHA1_ROTL(b, 30); b = a; a = tmp;
58             }
59              
60 5           state[0] += a;
61 5           state[1] += b;
62 5           state[2] += c;
63 5           state[3] += d;
64 5           state[4] += e;
65 5           }
66              
67 5           static inline void horus_sha1_init(horus_sha1_ctx *ctx) {
68 5           ctx->count = 0;
69 5           ctx->state[0] = 0x67452301;
70 5           ctx->state[1] = 0xEFCDAB89;
71 5           ctx->state[2] = 0x98BADCFE;
72 5           ctx->state[3] = 0x10325476;
73 5           ctx->state[4] = 0xC3D2E1F0;
74 5           }
75              
76 20           static inline void horus_sha1_update(horus_sha1_ctx *ctx,
77             const unsigned char *data, size_t len) {
78 20           size_t index = (size_t)(ctx->count & 0x3F);
79 20           ctx->count += len;
80              
81 20 100         if (index) {
82 15           size_t part_len = 64 - index;
83 15 100         if (len >= part_len) {
84 5           memcpy(ctx->buffer + index, data, part_len);
85 5           horus_sha1_transform(ctx->state, ctx->buffer);
86 5           data += part_len;
87 5           len -= part_len;
88             } else {
89 10           memcpy(ctx->buffer + index, data, len);
90 10           return;
91             }
92             }
93              
94 10 50         while (len >= 64) {
95 0           horus_sha1_transform(ctx->state, data);
96 0           data += 64;
97 0           len -= 64;
98             }
99              
100 10 100         if (len)
101 5           memcpy(ctx->buffer, data, len);
102             }
103              
104 5           static inline void horus_sha1_final(unsigned char digest[20], horus_sha1_ctx *ctx) {
105             unsigned char padding[64];
106             unsigned char bits[8];
107 5           uint64_t bit_count = ctx->count << 3;
108             size_t index;
109             int i;
110              
111 5           memset(padding, 0, sizeof(padding));
112 5           padding[0] = 0x80;
113              
114             /* Encode bit count as big-endian */
115 45 100         for (i = 0; i < 8; i++)
116 40           bits[7 - i] = (unsigned char)(bit_count >> (i * 8));
117              
118             /* Pad to 56 mod 64 */
119 5           index = (size_t)(ctx->count & 0x3F);
120 5 50         horus_sha1_update(ctx, padding, (index < 56) ? (56 - index) : (120 - index));
121              
122             /* Append length */
123 5           horus_sha1_update(ctx, bits, 8);
124              
125             /* Encode state as big-endian */
126 30 100         for (i = 0; i < 5; i++) {
127 25           digest[i*4 + 0] = (unsigned char)(ctx->state[i] >> 24);
128 25           digest[i*4 + 1] = (unsigned char)(ctx->state[i] >> 16);
129 25           digest[i*4 + 2] = (unsigned char)(ctx->state[i] >> 8);
130 25           digest[i*4 + 3] = (unsigned char)(ctx->state[i]);
131             }
132 5           }
133              
134             /* Convenience: hash data in one shot */
135             static inline void horus_sha1(unsigned char digest[20],
136             const unsigned char *data, size_t len) {
137             horus_sha1_ctx ctx;
138             horus_sha1_init(&ctx);
139             horus_sha1_update(&ctx, data, len);
140             horus_sha1_final(digest, &ctx);
141             }
142              
143             #endif /* HORUS_SHA1_H */