libcoap 4.3.5-develop-72190a8
Loading...
Searching...
No Matches
coap_sha1.c
Go to the documentation of this file.
1/*
2 * coap_sha1.c
3 *
4 * Full Copyright Statement RFC3174
5 *
6 * =======================================================================
7 *
8 * Copyright (C) The Internet Society (2001). All Rights Reserved.
9 *
10 * This document and translations of it may be copied and furnished to
11 * others, and derivative works that comment on or otherwise explain it
12 * or assist in its implementation may be prepared, copied, published
13 * and distributed, in whole or in part, without restriction of any
14 * kind, provided that the above copyright notice and this paragraph are
15 * included on all such copies and derivative works. However, this
16 * document itself may not be modified in any way, such as by removing
17 * the copyright notice or references to the Internet Society or other
18 * Internet organizations, except as needed for the purpose of
19 * developing Internet standards in which case the procedures for
20 * copyrights defined in the Internet Standards process must be
21 * followed, or as required to translate it into languages other than
22 * English.
23 *
24 * The limited permissions granted above are perpetual and will not be
25 * revoked by the Internet Society or its successors or assigns.
26 *
27 * This document and the information contained herein is provided on an
28 * "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
29 * TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
30 * BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
31 * HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
32 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
33 *
34 * =======================================================================
35 *
36 * Description:
37 * This file implements the Secure Hashing Algorithm 1 as
38 * defined in FIPS PUB 180-1 published April 17, 1995.
39 *
40 * The SHA-1, produces a 160-bit message digest for a given
41 * data stream. It should take about 2**n steps to find a
42 * message with the same digest as a given message and
43 * 2**(n/2) to find any two messages with the same digest,
44 * when n is the digest size in bits. Therefore, this
45 * algorithm can serve as a means of providing a
46 * "fingerprint" for a message.
47 *
48 * Portability Issues:
49 * SHA-1 is defined in terms of 32-bit "words". This code
50 * uses <stdint.h> (included via "sha1.h" to define 32 and 8
51 * bit unsigned integer types. If your C compiler does not
52 * support 32 bit unsigned integers, this code is not
53 * appropriate.
54 *
55 * Caveats:
56 * SHA-1 is designed to work with messages less than 2^64 bits
57 * long. Although SHA-1 allows a message digest to be generated
58 * for messages of any number of bits less than 2^64, this
59 * implementation only works with messages with a length that is
60 * a multiple of the size of an 8-bit character.
61 *
62 * Taken from https://datatracker.ietf.org/doc/html/rfc3174#section-7.2
63 * Reformatted as appropriate.
64 */
65
72
73#if COAP_WS_SUPPORT && !defined(COAP_WITH_LIBOPENSSL) && !defined(COAP_WITH_LIBGNUTLS) && !defined(COAP_WITH_LIBMBEDTLS) && !defined(COAP_WITH_LIBWOLFSSL)
74/*
75 * Define the SHA1 circular left shift macro
76 */
77#define SHA1CircularShift(bits,word) \
78 (((word) << (bits)) | ((word) >> (32-(bits))))
79
80/* Local Function Prototyptes */
81void SHA1PadMessage(SHA1Context *);
82void SHA1ProcessMessageBlock(SHA1Context *);
83
84/*
85 * SHA1Reset
86 *
87 * Description:
88 * This function will initialize the SHA1Context in preparation
89 * for computing a new SHA1 message digest.
90 *
91 * Parameters:
92 * context: [in/out]
93 * The context to reset.
94 *
95 * Returns:
96 * sha Error Code.
97 *
98 */
99int
100SHA1Reset(SHA1Context *context) {
101 if (!context) {
102 return shaNull;
103 }
104
105 context->Length_Low = 0;
106 context->Length_High = 0;
107 context->Message_Block_Index = 0;
108
109 context->Intermediate_Hash[0] = 0x67452301;
110 context->Intermediate_Hash[1] = 0xEFCDAB89;
111 context->Intermediate_Hash[2] = 0x98BADCFE;
112 context->Intermediate_Hash[3] = 0x10325476;
113 context->Intermediate_Hash[4] = 0xC3D2E1F0;
114
115 context->Computed = 0;
116 context->Corrupted = 0;
117
118 return shaSuccess;
119}
120
121/*
122 * SHA1Result
123 *
124 * Description:
125 * This function will return the 160-bit message digest into the
126 * Message_Digest array provided by the caller.
127 * NOTE: The first octet of hash is stored in the 0th element,
128 * the last octet of hash in the 19th element.
129 *
130 * Parameters:
131 * context: [in/out]
132 * The context to use to calculate the SHA-1 hash.
133 * Message_Digest: [out]
134 * Where the digest is returned.
135 *
136 * Returns:
137 * sha Error Code.
138 *
139 */
140int
141SHA1Result(SHA1Context *context,
142 uint8_t Message_Digest[SHA1HashSize]) {
143 int i;
144
145 if (!context || !Message_Digest) {
146 return shaNull;
147 }
148
149 if (context->Corrupted) {
150 return context->Corrupted;
151 }
152
153 if (!context->Computed) {
154 SHA1PadMessage(context);
155 for (i=0; i<64; ++i) {
156 /* message may be sensitive, clear it out */
157 context->Message_Block[i] = 0;
158 }
159 context->Length_Low = 0; /* and clear length */
160 context->Length_High = 0;
161 context->Computed = 1;
162 }
163
164 for (i = 0; i < SHA1HashSize; ++i) {
165 Message_Digest[i] = context->Intermediate_Hash[i>>2]
166 >> 8 * (3 - (i & 0x03));
167 }
168
169 return shaSuccess;
170}
171
172/*
173 * SHA1Input
174 *
175 * Description:
176 * This function accepts an array of octets as the next portion
177 * of the message.
178 *
179 * Parameters:
180 * context: [in/out]
181 * The SHA context to update
182 * message_array: [in]
183 * An array of characters representing the next portion of
184 * the message.
185 * length: [in]
186 * The length of the message in message_array
187 *
188 * Returns:
189 * sha Error Code.
190 *
191 */
192int
193SHA1Input(SHA1Context *context,
194 const uint8_t *message_array,
195 unsigned length) {
196 if (!length) {
197 return shaSuccess;
198 }
199
200 if (!context || !message_array) {
201 return shaNull;
202 }
203
204 if (context->Computed) {
205 context->Corrupted = shaStateError;
206 return shaStateError;
207 }
208
209 if (context->Corrupted) {
210 return context->Corrupted;
211 }
212 while (length-- && !context->Corrupted) {
213 context->Message_Block[context->Message_Block_Index++] =
214 (*message_array & 0xFF);
215
216 context->Length_Low += 8;
217 if (context->Length_Low == 0) {
218 context->Length_High++;
219 if (context->Length_High == 0) {
220 /* Message is too long */
221 context->Corrupted = 1;
222 }
223 }
224
225 if (context->Message_Block_Index == 64) {
226 SHA1ProcessMessageBlock(context);
227 }
228
229 message_array++;
230 }
231
232 return shaSuccess;
233}
234
235/*
236 * SHA1ProcessMessageBlock
237 *
238 * Description:
239 * This function will process the next 512 bits of the message
240 * stored in the Message_Block array.
241 *
242 * Parameters:
243 * None.
244 *
245 * Returns:
246 * Nothing.
247 *
248 * Comments:
249 * Many of the variable names in this code, especially the
250 * single character names, were used because those were the
251 * names used in the publication.
252 *
253 *
254 */
255void
256SHA1ProcessMessageBlock(SHA1Context *context) {
257 const uint32_t K[] = { /* Constants defined in SHA-1 */
258 0x5A827999,
259 0x6ED9EBA1,
260 0x8F1BBCDC,
261 0xCA62C1D6
262 };
263 int t; /* Loop counter */
264 uint32_t temp; /* Temporary word value */
265 uint32_t W[80]; /* Word sequence */
266 uint32_t A, B, C, D, E; /* Word buffers */
267
268 /*
269 * Initialize the first 16 words in the array W
270 */
271 for (t = 0; t < 16; t++) {
272 W[t] = (uint32_t)(context->Message_Block[t * 4]) << 24;
273 W[t] |= (uint32_t)(context->Message_Block[t * 4 + 1]) << 16;
274 W[t] |= context->Message_Block[t * 4 + 2] << 8;
275 W[t] |= context->Message_Block[t * 4 + 3];
276 }
277
278 for (t = 16; t < 80; t++) {
279 W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
280 }
281
282 A = context->Intermediate_Hash[0];
283 B = context->Intermediate_Hash[1];
284 C = context->Intermediate_Hash[2];
285 D = context->Intermediate_Hash[3];
286 E = context->Intermediate_Hash[4];
287
288 for (t = 0; t < 20; t++) {
289 temp = SHA1CircularShift(5,A) +
290 ((B & C) | ((~B) & D)) + E + W[t] + K[0];
291 E = D;
292 D = C;
293 C = SHA1CircularShift(30,B);
294 B = A;
295 A = temp;
296 }
297
298 for (t = 20; t < 40; t++) {
299 temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
300 E = D;
301 D = C;
302 C = SHA1CircularShift(30,B);
303 B = A;
304 A = temp;
305 }
306
307 for (t = 40; t < 60; t++) {
308 temp = SHA1CircularShift(5,A) +
309 ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
310 E = D;
311 D = C;
312 C = SHA1CircularShift(30,B);
313 B = A;
314 A = temp;
315 }
316
317 for (t = 60; t < 80; t++) {
318 temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
319 E = D;
320 D = C;
321 C = SHA1CircularShift(30,B);
322 B = A;
323 A = temp;
324 }
325
326 context->Intermediate_Hash[0] += A;
327 context->Intermediate_Hash[1] += B;
328 context->Intermediate_Hash[2] += C;
329 context->Intermediate_Hash[3] += D;
330 context->Intermediate_Hash[4] += E;
331
332 context->Message_Block_Index = 0;
333}
334
335
336/*
337 * SHA1PadMessage
338 *
339 * Description:
340 * According to the standard, the message must be padded to an even
341 * 512 bits. The first padding bit must be a '1'. The last 64
342 * bits represent the length of the original message. All bits in
343 * between should be 0. This function will pad the message
344 * according to those rules by filling the Message_Block array
345 * accordingly. It will also call the ProcessMessageBlock function
346 * provided appropriately. When it returns, it can be assumed that
347 * the message digest has been computed.
348 *
349 * Parameters:
350 * context: [in/out]
351 * The context to pad
352 * ProcessMessageBlock: [in]
353 * The appropriate SHA*ProcessMessageBlock function
354 * Returns:
355 * Nothing.
356 *
357 */
358
359void
360SHA1PadMessage(SHA1Context *context) {
361 /*
362 * Check to see if the current message block is too small to hold
363 * the initial padding bits and length. If so, we will pad the
364 * block, process it, and then continue padding into a second
365 * block.
366 */
367 if (context->Message_Block_Index > 55) {
368 context->Message_Block[context->Message_Block_Index++] = 0x80;
369 while (context->Message_Block_Index < 64) {
370 context->Message_Block[context->Message_Block_Index++] = 0;
371 }
372
373 SHA1ProcessMessageBlock(context);
374
375 while (context->Message_Block_Index < 56) {
376 context->Message_Block[context->Message_Block_Index++] = 0;
377 }
378 } else {
379 context->Message_Block[context->Message_Block_Index++] = 0x80;
380 while (context->Message_Block_Index < 56) {
381 context->Message_Block[context->Message_Block_Index++] = 0;
382 }
383 }
384
385 /*
386 * Store the message length as the last 8 octets
387 */
388 context->Message_Block[56] = context->Length_High >> 24;
389 context->Message_Block[57] = context->Length_High >> 16;
390 context->Message_Block[58] = context->Length_High >> 8;
391 context->Message_Block[59] = context->Length_High;
392 context->Message_Block[60] = context->Length_Low >> 24;
393 context->Message_Block[61] = context->Length_Low >> 16;
394 context->Message_Block[62] = context->Length_Low >> 8;
395 context->Message_Block[63] = context->Length_Low;
396
397 SHA1ProcessMessageBlock(context);
398}
399#endif /* COAP_WS_SUPPORT && !defined(COAP_WITH_LIBOPENSSL) && !defined(COAP_WITH_LIBGNUTLS) && !defined(COAP_WITH_LIBMBEDTLS) */
Library specific build wrapper for coap_internal.h.
int SHA1Result(SHA1Context *, uint8_t Message_Digest[SHA1HashSize])
int SHA1Reset(SHA1Context *)
int SHA1Input(SHA1Context *, const uint8_t *, unsigned int)
@ shaSuccess
@ shaNull
@ shaStateError
#define SHA1HashSize
uint32_t Intermediate_Hash[SHA1HashSize/4]
uint8_t Message_Block[64]
int_least16_t Message_Block_Index