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 (c) 2008, Aleksey Kravchenko
5             *
6             * Permission to use, copy, modify, and/or distribute this software for any
7             * purpose with or without fee is hereby granted.
8             *
9             * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10             * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11             * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12             * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13             * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14             * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15             * PERFORMANCE OF THIS SOFTWARE.
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           }