File Coverage

_sha1.c
Criterion Covered Total %
statement 76 93 81.7
branch 22 32 68.7
condition n/a
subroutine n/a
pod n/a
total 98 125 78.4


line stmt bran cond sub pod time code
1             /* sha1.c - an implementation of Secure Hash Algorithm 1 (SHA1)
2             * based on RFC 3174.
3             *
4             * Copyright: 2008-2012 Aleksey Kravchenko
5             *
6             * Permission is hereby granted, free of charge, to any person obtaining a
7             * copy of this software and associated documentation files (the "Software"),
8             * to deal in the Software without restriction, including without limitation
9             * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10             * and/or sell copies of the Software, and to permit persons to whom the
11             * Software is furnished to do so.
12             *
13             * This program is distributed in the hope that it will be useful, but
14             * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15             * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
16             */
17              
18             #include
19             #include "byte_order.h"
20             #include "sha1.h"
21              
22             /**
23             * Initialize context before calculaing hash.
24             *
25             * @param ctx context to initialize
26             */
27 8           void rhash_sha1_init(sha1_ctx *ctx)
28             {
29 8           ctx->length = 0;
30              
31             /* initialize algorithm state */
32 8           ctx->hash[0] = 0x67452301;
33 8           ctx->hash[1] = 0xefcdab89;
34 8           ctx->hash[2] = 0x98badcfe;
35 8           ctx->hash[3] = 0x10325476;
36 8           ctx->hash[4] = 0xc3d2e1f0;
37 8           }
38              
39             /**
40             * The core transformation. Process a 512-bit block.
41             * The function has been taken from RFC 3174 with little changes.
42             *
43             * @param hash algorithm state
44             * @param block the message block to process
45             */
46 8           static void rhash_sha1_process_block(unsigned* hash, const unsigned* block)
47             {
48             int t; /* Loop counter */
49             uint32_t temp; /* Temporary word value */
50             uint32_t W[80]; /* Word sequence */
51             uint32_t A, B, C, D, E; /* Word buffers */
52              
53             /* initialize the first 16 words in the array W */
54 136 100         for (t = 0; t < 16; t++) {
55             /* note: it is much faster to apply be2me here, then using be32_copy */
56 128           W[t] = be2me_32(block[t]);
57             }
58              
59             /* initialize the rest */
60 520 100         for (t = 16; t < 80; t++) {
61 512           W[t] = ROTL32(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
62             }
63              
64 8           A = hash[0];
65 8           B = hash[1];
66 8           C = hash[2];
67 8           D = hash[3];
68 8           E = hash[4];
69              
70 168 100         for (t = 0; t < 20; t++) {
71             /* the following is faster than ((B & C) | ((~B) & D)) */
72 320           temp = ROTL32(A, 5) + (((C ^ D) & B) ^ D)
73 160           + E + W[t] + 0x5A827999;
74 160           E = D;
75 160           D = C;
76 160           C = ROTL32(B, 30);
77 160           B = A;
78 160           A = temp;
79             }
80              
81 168 100         for (t = 20; t < 40; t++) {
82 160           temp = ROTL32(A, 5) + (B ^ C ^ D) + E + W[t] + 0x6ED9EBA1;
83 160           E = D;
84 160           D = C;
85 160           C = ROTL32(B, 30);
86 160           B = A;
87 160           A = temp;
88             }
89              
90 168 100         for (t = 40; t < 60; t++) {
91 320           temp = ROTL32(A, 5) + ((B & C) | (B & D) | (C & D))
92 160           + E + W[t] + 0x8F1BBCDC;
93 160           E = D;
94 160           D = C;
95 160           C = ROTL32(B, 30);
96 160           B = A;
97 160           A = temp;
98             }
99              
100 168 100         for (t = 60; t < 80; t++) {
101 160           temp = ROTL32(A, 5) + (B ^ C ^ D) + E + W[t] + 0xCA62C1D6;
102 160           E = D;
103 160           D = C;
104 160           C = ROTL32(B, 30);
105 160           B = A;
106 160           A = temp;
107             }
108              
109 8           hash[0] += A;
110 8           hash[1] += B;
111 8           hash[2] += C;
112 8           hash[3] += D;
113 8           hash[4] += E;
114 8           }
115              
116             /**
117             * Calculate message hash.
118             * Can be called repeatedly with chunks of the message to be hashed.
119             *
120             * @param ctx the algorithm context containing current hashing state
121             * @param msg message chunk
122             * @param size length of the message chunk
123             */
124 8           void rhash_sha1_update(sha1_ctx *ctx, const unsigned char* msg, size_t size)
125             {
126 8           unsigned index = (unsigned)ctx->length & 63;
127 8           ctx->length += size;
128              
129             /* fill partial block */
130 8 50         if (index) {
131 0           unsigned left = sha1_block_size - index;
132 0           memcpy(ctx->message + index, msg, (size < left ? size : left));
133 0 0         if (size < left) return;
134              
135             /* process partial block */
136 0           rhash_sha1_process_block(ctx->hash, (unsigned*)ctx->message);
137 0           msg += left;
138 0           size -= left;
139             }
140 8 50         while (size >= sha1_block_size) {
141             unsigned* aligned_message_block;
142 0 0         if (IS_ALIGNED_32(msg)) {
143             /* the most common case is processing of an already aligned message
144             without copying it */
145 0           aligned_message_block = (unsigned*)msg;
146             } else {
147 0           memcpy(ctx->message, msg, sha1_block_size);
148 0           aligned_message_block = (unsigned*)ctx->message;
149             }
150              
151 0           rhash_sha1_process_block(ctx->hash, aligned_message_block);
152 0           msg += sha1_block_size;
153 0           size -= sha1_block_size;
154             }
155 8 50         if (size) {
156             /* save leftovers */
157 8           memcpy(ctx->message, msg, size);
158             }
159             }
160              
161             /**
162             * Store calculated hash into the given array.
163             *
164             * @param ctx the algorithm context containing current hashing state
165             * @param result calculated hash in binary form
166             */
167 8           void rhash_sha1_final(sha1_ctx *ctx, unsigned char* result)
168             {
169 8           unsigned index = (unsigned)ctx->length & 63;
170 8           unsigned* msg32 = (unsigned*)ctx->message;
171              
172             /* pad message and run for last block */
173 8           ctx->message[index++] = 0x80;
174 20 100         while ((index & 3) != 0) {
175 12           ctx->message[index++] = 0;
176             }
177 8           index >>= 2;
178              
179             /* if no room left in the message to store 64-bit message length */
180 8 50         if (index > 14) {
181             /* then fill the rest with zeros and process it */
182 0 0         while (index < 16) {
183 0           msg32[index++] = 0;
184             }
185 0           rhash_sha1_process_block(ctx->hash, msg32);
186 0           index = 0;
187             }
188 86 100         while (index < 14) {
189 78           msg32[index++] = 0;
190             }
191 8           msg32[14] = be2me_32( (unsigned)(ctx->length >> 29) );
192 8           msg32[15] = be2me_32( (unsigned)(ctx->length << 3) );
193 8           rhash_sha1_process_block(ctx->hash, msg32);
194              
195 8 100         if (result) be32_copy(result, 0, &ctx->hash, sha1_hash_size);
196 8           }