libcoap 4.3.5
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
67
68#if COAP_WS_SUPPORT && !defined(COAP_WITH_LIBOPENSSL) && !defined(COAP_WITH_LIBGNUTLS) && !defined(COAP_WITH_LIBMBEDTLS) && !defined(COAP_WITH_LIBWOLFSSL)
69/*
70 * Define the SHA1 circular left shift macro
71 */
72#define SHA1CircularShift(bits,word) \
73 (((word) << (bits)) | ((word) >> (32-(bits))))
74
75/* Local Function Prototyptes */
76void SHA1PadMessage(SHA1Context *);
77void SHA1ProcessMessageBlock(SHA1Context *);
78
79/*
80 * SHA1Reset
81 *
82 * Description:
83 * This function will initialize the SHA1Context in preparation
84 * for computing a new SHA1 message digest.
85 *
86 * Parameters:
87 * context: [in/out]
88 * The context to reset.
89 *
90 * Returns:
91 * sha Error Code.
92 *
93 */
94int
95SHA1Reset(SHA1Context *context) {
96 if (!context) {
97 return shaNull;
98 }
99
100 context->Length_Low = 0;
101 context->Length_High = 0;
102 context->Message_Block_Index = 0;
103
104 context->Intermediate_Hash[0] = 0x67452301;
105 context->Intermediate_Hash[1] = 0xEFCDAB89;
106 context->Intermediate_Hash[2] = 0x98BADCFE;
107 context->Intermediate_Hash[3] = 0x10325476;
108 context->Intermediate_Hash[4] = 0xC3D2E1F0;
109
110 context->Computed = 0;
111 context->Corrupted = 0;
112
113 return shaSuccess;
114}
115
116/*
117 * SHA1Result
118 *
119 * Description:
120 * This function will return the 160-bit message digest into the
121 * Message_Digest array provided by the caller.
122 * NOTE: The first octet of hash is stored in the 0th element,
123 * the last octet of hash in the 19th element.
124 *
125 * Parameters:
126 * context: [in/out]
127 * The context to use to calculate the SHA-1 hash.
128 * Message_Digest: [out]
129 * Where the digest is returned.
130 *
131 * Returns:
132 * sha Error Code.
133 *
134 */
135int
136SHA1Result(SHA1Context *context,
137 uint8_t Message_Digest[SHA1HashSize]) {
138 int i;
139
140 if (!context || !Message_Digest) {
141 return shaNull;
142 }
143
144 if (context->Corrupted) {
145 return context->Corrupted;
146 }
147
148 if (!context->Computed) {
149 SHA1PadMessage(context);
150 for (i=0; i<64; ++i) {
151 /* message may be sensitive, clear it out */
152 context->Message_Block[i] = 0;
153 }
154 context->Length_Low = 0; /* and clear length */
155 context->Length_High = 0;
156 context->Computed = 1;
157 }
158
159 for (i = 0; i < SHA1HashSize; ++i) {
160 Message_Digest[i] = context->Intermediate_Hash[i>>2]
161 >> 8 * (3 - (i & 0x03));
162 }
163
164 return shaSuccess;
165}
166
167/*
168 * SHA1Input
169 *
170 * Description:
171 * This function accepts an array of octets as the next portion
172 * of the message.
173 *
174 * Parameters:
175 * context: [in/out]
176 * The SHA context to update
177 * message_array: [in]
178 * An array of characters representing the next portion of
179 * the message.
180 * length: [in]
181 * The length of the message in message_array
182 *
183 * Returns:
184 * sha Error Code.
185 *
186 */
187int
188SHA1Input(SHA1Context *context,
189 const uint8_t *message_array,
190 unsigned length) {
191 if (!length) {
192 return shaSuccess;
193 }
194
195 if (!context || !message_array) {
196 return shaNull;
197 }
198
199 if (context->Computed) {
200 context->Corrupted = shaStateError;
201 return shaStateError;
202 }
203
204 if (context->Corrupted) {
205 return context->Corrupted;
206 }
207 while (length-- && !context->Corrupted) {
208 context->Message_Block[context->Message_Block_Index++] =
209 (*message_array & 0xFF);
210
211 context->Length_Low += 8;
212 if (context->Length_Low == 0) {
213 context->Length_High++;
214 if (context->Length_High == 0) {
215 /* Message is too long */
216 context->Corrupted = 1;
217 }
218 }
219
220 if (context->Message_Block_Index == 64) {
221 SHA1ProcessMessageBlock(context);
222 }
223
224 message_array++;
225 }
226
227 return shaSuccess;
228}
229
230/*
231 * SHA1ProcessMessageBlock
232 *
233 * Description:
234 * This function will process the next 512 bits of the message
235 * stored in the Message_Block array.
236 *
237 * Parameters:
238 * None.
239 *
240 * Returns:
241 * Nothing.
242 *
243 * Comments:
244 * Many of the variable names in this code, especially the
245 * single character names, were used because those were the
246 * names used in the publication.
247 *
248 *
249 */
250void
251SHA1ProcessMessageBlock(SHA1Context *context) {
252 const uint32_t K[] = { /* Constants defined in SHA-1 */
253 0x5A827999,
254 0x6ED9EBA1,
255 0x8F1BBCDC,
256 0xCA62C1D6
257 };
258 int t; /* Loop counter */
259 uint32_t temp; /* Temporary word value */
260 uint32_t W[80]; /* Word sequence */
261 uint32_t A, B, C, D, E; /* Word buffers */
262
263 /*
264 * Initialize the first 16 words in the array W
265 */
266 for (t = 0; t < 16; t++) {
267 W[t] = (uint32_t)(context->Message_Block[t * 4]) << 24;
268 W[t] |= (uint32_t)(context->Message_Block[t * 4 + 1]) << 16;
269 W[t] |= context->Message_Block[t * 4 + 2] << 8;
270 W[t] |= context->Message_Block[t * 4 + 3];
271 }
272
273 for (t = 16; t < 80; t++) {
274 W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
275 }
276
277 A = context->Intermediate_Hash[0];
278 B = context->Intermediate_Hash[1];
279 C = context->Intermediate_Hash[2];
280 D = context->Intermediate_Hash[3];
281 E = context->Intermediate_Hash[4];
282
283 for (t = 0; t < 20; t++) {
284 temp = SHA1CircularShift(5,A) +
285 ((B & C) | ((~B) & D)) + E + W[t] + K[0];
286 E = D;
287 D = C;
288 C = SHA1CircularShift(30,B);
289 B = A;
290 A = temp;
291 }
292
293 for (t = 20; t < 40; t++) {
294 temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
295 E = D;
296 D = C;
297 C = SHA1CircularShift(30,B);
298 B = A;
299 A = temp;
300 }
301
302 for (t = 40; t < 60; t++) {
303 temp = SHA1CircularShift(5,A) +
304 ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
305 E = D;
306 D = C;
307 C = SHA1CircularShift(30,B);
308 B = A;
309 A = temp;
310 }
311
312 for (t = 60; t < 80; t++) {
313 temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
314 E = D;
315 D = C;
316 C = SHA1CircularShift(30,B);
317 B = A;
318 A = temp;
319 }
320
321 context->Intermediate_Hash[0] += A;
322 context->Intermediate_Hash[1] += B;
323 context->Intermediate_Hash[2] += C;
324 context->Intermediate_Hash[3] += D;
325 context->Intermediate_Hash[4] += E;
326
327 context->Message_Block_Index = 0;
328}
329
330
331/*
332 * SHA1PadMessage
333 *
334 * Description:
335 * According to the standard, the message must be padded to an even
336 * 512 bits. The first padding bit must be a '1'. The last 64
337 * bits represent the length of the original message. All bits in
338 * between should be 0. This function will pad the message
339 * according to those rules by filling the Message_Block array
340 * accordingly. It will also call the ProcessMessageBlock function
341 * provided appropriately. When it returns, it can be assumed that
342 * the message digest has been computed.
343 *
344 * Parameters:
345 * context: [in/out]
346 * The context to pad
347 * ProcessMessageBlock: [in]
348 * The appropriate SHA*ProcessMessageBlock function
349 * Returns:
350 * Nothing.
351 *
352 */
353
354void
355SHA1PadMessage(SHA1Context *context) {
356 /*
357 * Check to see if the current message block is too small to hold
358 * the initial padding bits and length. If so, we will pad the
359 * block, process it, and then continue padding into a second
360 * block.
361 */
362 if (context->Message_Block_Index > 55) {
363 context->Message_Block[context->Message_Block_Index++] = 0x80;
364 while (context->Message_Block_Index < 64) {
365 context->Message_Block[context->Message_Block_Index++] = 0;
366 }
367
368 SHA1ProcessMessageBlock(context);
369
370 while (context->Message_Block_Index < 56) {
371 context->Message_Block[context->Message_Block_Index++] = 0;
372 }
373 } else {
374 context->Message_Block[context->Message_Block_Index++] = 0x80;
375 while (context->Message_Block_Index < 56) {
376 context->Message_Block[context->Message_Block_Index++] = 0;
377 }
378 }
379
380 /*
381 * Store the message length as the last 8 octets
382 */
383 context->Message_Block[56] = context->Length_High >> 24;
384 context->Message_Block[57] = context->Length_High >> 16;
385 context->Message_Block[58] = context->Length_High >> 8;
386 context->Message_Block[59] = context->Length_High;
387 context->Message_Block[60] = context->Length_Low >> 24;
388 context->Message_Block[61] = context->Length_Low >> 16;
389 context->Message_Block[62] = context->Length_Low >> 8;
390 context->Message_Block[63] = context->Length_Low;
391
392 SHA1ProcessMessageBlock(context);
393}
394#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