2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * This SHA1 code is based on the basic framework from the reference
31 * implementation for MD5. That implementation is Copyright (C)
32 * 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
34 * License to copy and use this software is granted provided that it
35 * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
36 * Algorithm" in all material mentioning or referencing this software
39 * License is also granted to make and use derivative works provided
40 * that such works are identified as "derived from the RSA Data
41 * Security, Inc. MD5 Message-Digest Algorithm" in all material
42 * mentioning or referencing the derived work.
44 * RSA Data Security, Inc. makes no representations concerning either
45 * the merchantability of this software or the suitability of this
46 * software for any particular purpose. It is provided "as is"
47 * without express or implied warranty of any kind.
49 * These notices must be retained in any copies of any part of this
50 * documentation and/or software.
52 * Based on the FIPS 180-1: Secure Hash Algorithm (SHA-1) available at
53 * http://www.itl.nist.gov/div897/pubs/fip180-1.htm
56 #include <sys/types.h>
57 #include <sys/systm.h>
58 #include <libkern/OSAtomic.h>
59 #include <libkern/crypto/sha1.h>
60 #define SHA1_TIMER 0 // change to nonzero to write timing stamps to profile sha1transform
63 #include <sys/kdebug.h>
66 #define memset(x, y, z) bzero(x, z);
67 #define memcpy(x, y, z) bcopy(y, x, z)
69 /* Internal mappings to the legacy sha1_ctxt structure. */
75 * The digest algorithm interprets the input message as a sequence of 32-bit
76 * big-endian words. We must reverse bytes in each word on x86/64 platforms,
77 * but not on big-endian ones such as PPC. For performance, we take advantage
78 * of the bswap instruction on x86/64 to perform byte-reversal. On PPC, we
79 * could do 4-byte load if the address is 4-byte aligned which should further
80 * improve the performance. But for code simplicity, we punt and do 1-byte
83 #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__)
84 #define FETCH_32(p) ({ \
85 register u_int32_t l = (u_int32_t)*((const u_int32_t *)(p)); \
86 __asm__ __volatile__("bswap %0" : "=r" (l) : "0" (l)); \
91 (((u_int32_t)*((const u_int8_t *)(p) + 3)) | \
92 (((u_int32_t)*((const u_int8_t *)(p) + 2)) << 8) | \
93 (((u_int32_t)*((const u_int8_t *)(p) + 1)) << 16) | \
94 (((u_int32_t)*((const u_int8_t *)(p))) << 24))
95 #endif /* __i386__ || __x86_64__ */
98 * Encodes input (u_int32_t) into output (unsigned char). Assumes len is
99 * a multiple of 4. This is not compatible with memcpy().
102 Encode(unsigned char *output
, u_int32_t
*input
, unsigned int len
)
106 for (i
= 0, j
= 0; j
< len
; i
++, j
+= 4) {
107 output
[j
+ 3] = input
[i
] & 0xff;
108 output
[j
+ 2] = (input
[i
] >> 8) & 0xff;
109 output
[j
+ 1] = (input
[i
] >> 16) & 0xff;
110 output
[j
] = (input
[i
] >> 24) & 0xff;
114 static unsigned char PADDING
[64] = { 0x80, /* zeros */ };
116 /* Constants from FIPS 180-1 */
117 #define K_00_19 0x5a827999UL
118 #define K_20_39 0x6ed9eba1UL
119 #define K_40_59 0x8f1bbcdcUL
120 #define K_60_79 0xca62c1d6UL
122 /* F, G, H and I are basic SHA1 functions. */
123 #define F(b, c, d) ((((c) ^ (d)) & (b)) ^ (d))
124 #define G(b, c, d) ((b) ^ (c) ^ (d))
125 #define H(b, c, d) (((b) & (c)) | (((b) | (c)) & (d)))
127 /* ROTATE_LEFT rotates x left n bits. */
128 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
130 /* R, R1-R4 are macros used during each transformation round. */
131 #define R(f, k, v, w, x, y, z, i) { \
132 (v) = ROTATE_LEFT(w, 5) + f(x, y, z) + (v) + (i) + (k); \
133 (x) = ROTATE_LEFT(x, 30); \
136 #define R1(v, w, x, y, z, i) R(F, K_00_19, v, w, x, y, z, i)
137 #define R2(v, w, x, y, z, i) R(G, K_20_39, v, w, x, y, z, i)
138 #define R3(v, w, x, y, z, i) R(H, K_40_59, v, w, x, y, z, i)
139 #define R4(v, w, x, y, z, i) R(G, K_60_79, v, w, x, y, z, i)
141 /* WUPDATE represents Wt variable that gets updated for steps 16-79 */
142 #define WUPDATE(p, q, r, s) { \
143 (p) = ((q) ^ (r) ^ (s) ^ (p)); \
144 (p) = ROTATE_LEFT(p, 1); \
147 #if (defined (__x86_64__) || defined (__i386__))
148 extern void SHA1Transform(SHA1_CTX
*, const u_int8_t
*, u_int32_t Nblocks
);
150 static void SHA1Transform(SHA1_CTX
*, const u_int8_t
*);
153 void _SHA1Update(SHA1_CTX
*context
, const void *inpp
, size_t inputLen
);
155 void SHA1Final_r(SHA1_CTX
*, void *);
157 typedef kern_return_t (*InKernelPerformSHA1Func
)(void *ref
, const void *data
, size_t dataLen
, u_int32_t
*inHash
, u_int32_t options
, u_int32_t
*outHash
, Boolean usePhysicalAddress
);
158 void sha1_hardware_hook(Boolean option
, InKernelPerformSHA1Func func
, void *ref
);
159 static void *SHA1Ref
;
160 InKernelPerformSHA1Func performSHA1WithinKernelOnly
;
161 #define SHA1_USE_HARDWARE_THRESHOLD 2048 //bytes
165 * SHA1 initialization. Begins a SHA1 operation, writing a new context.
168 SHA1Init(SHA1_CTX
*context
)
170 context
->bcount
[0] = context
->bcount
[1] = 0;
173 /* Load magic initialization constants. */
174 context
->state
[0] = 0x67452301UL
;
175 context
->state
[1] = 0xefcdab89UL
;
176 context
->state
[2] = 0x98badcfeUL
;
177 context
->state
[3] = 0x10325476UL
;
178 context
->state
[4] = 0xc3d2e1f0UL
;
182 * SHA1 block update operation. Continues a SHA1 message-digest
183 * operation, processing another message block, and updating the
187 _SHA1Update(SHA1_CTX
*context
, const void *inpp
, size_t inputLen
)
189 u_int32_t i
, index
, partLen
;
190 const unsigned char *input
= (const unsigned char *)inpp
;
195 /* Compute number of bytes mod 64 */
196 index
= (context
->bcount
[1] >> 3) & 0x3F;
198 /* Update number of bits */
199 if ((context
->bcount
[1] += (inputLen
<< 3)) < (inputLen
<< 3))
200 context
->bcount
[0]++;
201 context
->bcount
[0] += (inputLen
>> 29);
203 partLen
= 64 - index
;
205 /* Transform as many times as possible. */
207 if (inputLen
>= partLen
) {
209 memcpy(&context
->buffer
[index
], input
, partLen
);
210 #if (defined (__x86_64__) || defined (__i386__))
211 SHA1Transform(context
, context
->buffer
, 1);
213 SHA1Transform(context
, context
->buffer
);
219 KERNEL_DEBUG_CONSTANT(0xaa800004 | DBG_FUNC_START
, 0, 0, 0, 0, 0);
221 #if (defined (__x86_64__) || defined (__i386__))
223 int kk
= (inputLen
-i
)>>6;
225 SHA1Transform(context
, &input
[i
], kk
);
230 for (; i
+ 63 < inputLen
; i
+= 64)
231 SHA1Transform(context
, &input
[i
]);
236 KERNEL_DEBUG_CONSTANT(0xaa800004 | DBG_FUNC_END
, 0, 0, 0, 0, 0);
244 /* Buffer remaining input */
245 memcpy(&context
->buffer
[index
], &input
[i
], inputLen
- i
);
252 * This function is called by the SHA1 hardware kext during its init.
253 * This will register the function to call to perform SHA1 using hardware.
255 void sha1_hardware_hook(Boolean option
, InKernelPerformSHA1Func func
, void *ref
)
258 // Establish the hook. The hardware is ready.
259 OSCompareAndSwapPtr((void*)NULL
, (void*)ref
, (void * volatile*)&SHA1Ref
);
261 if(!OSCompareAndSwapPtr((void *)NULL
, (void *)func
, (void * volatile *)&performSHA1WithinKernelOnly
)) {
262 panic("sha1_hardware_hook: Called twice.. Should never happen\n");
266 // The hardware is going away. Tear down the hook.
267 performSHA1WithinKernelOnly
= NULL
;
272 static u_int32_t
SHA1UpdateWithHardware(SHA1_CTX
*context
, const unsigned char *data
, size_t dataLen
, Boolean usePhysicalAddress
)
274 u_int32_t
*inHashBuffer
= context
->state
;
275 u_int32_t options
= 0;
278 result
= performSHA1WithinKernelOnly(SHA1Ref
, data
, dataLen
, inHashBuffer
, options
, inHashBuffer
, usePhysicalAddress
);
279 if(result
!= KERN_SUCCESS
) {
280 //The hardware failed to hash for some reason. Fall back to software.
284 //Update the context with the total length.
285 /* Update number of bits */
286 if ((context
->bcount
[1] += (dataLen
<< 3)) < (dataLen
<< 3))
287 context
->bcount
[0]++;
288 context
->bcount
[0] += (dataLen
>> 29);
293 * This is function is only called in from the pagefault path or from page_copy().
294 * So we assume that we can safely convert the virtual address to the physical address and use it.
295 * Assumptions: The passed in address(inpp) is a kernel virtual address
296 * and a physical page has been faulted in.
297 * The inputLen passed in should always be less than or equal to a page size (4096)
298 * and inpp should be on a page boundary.
299 * "performSHA1WithinKernelOnly" is initialized only when the hardware driver exists and is ready.
301 void SHA1UpdateUsePhysicalAddress(SHA1_CTX
*context
, const void *inpp
, size_t inputLen
)
303 Boolean usePhysicalAddress
= TRUE
;
304 if((inputLen
== PAGE_SIZE
) && performSHA1WithinKernelOnly
) { // If hardware exists and is ready.
305 if(SHA1UpdateWithHardware(context
, (const unsigned char *)inpp
, inputLen
, usePhysicalAddress
))
307 //else for some reason the hardware failed..
308 //fall through to software and try the hash in software.
310 //Use the software implementation since the hardware is absent or
311 // has not been initialized yet or inputLen != PAGE_SIZE.
312 _SHA1Update(context
, inpp
, inputLen
);
316 * A wrapper around _SHA1Update() to pick between software or hardware based SHA1.
319 void SHA1Update(SHA1_CTX
*context
, const void *inpp
, size_t inputLen
)
321 const unsigned char *input
= (const unsigned char *)inpp
;
322 Boolean usePhysicalAddress
= FALSE
;
325 if((inputLen
> SHA1_USE_HARDWARE_THRESHOLD
) && performSHA1WithinKernelOnly
) {
326 index
= (context
->bcount
[1] >> 3) & 0x3F;
327 if(index
!= 0) { //bytes left in the context. Handle them first.
328 u_int32_t partLen
= 64 - index
;
329 memcpy(&context
->buffer
[index
], input
, partLen
);
330 _SHA1Update(context
, inpp
, inputLen
);
335 u_int32_t lenForHardware
= inputLen
& (~0x3F); //multiple of 64
336 u_int32_t bytesHashed
= 0;
337 bytesHashed
= SHA1UpdateWithHardware(context
, input
, lenForHardware
, usePhysicalAddress
);
339 inputLen
-= bytesHashed
;
340 input
+= bytesHashed
;
343 //Fall through to the software implementation.
344 _SHA1Update(context
, input
, inputLen
);
348 * For backwards compatibility, sha1_result symbol is mapped to this
349 * routine since it's equivalent to SHA1Final with reversed parameters.
352 SHA1Final_r(SHA1_CTX
*context
, void *digest
)
354 SHA1Final(digest
, context
);
358 * SHA1 finalization. Ends an SHA1 message-digest operation, writing the
359 * the message digest and zeroizing the context.
362 SHA1Final(void *digest
, SHA1_CTX
*context
)
364 unsigned char bits
[8];
365 u_int32_t index
= (context
->bcount
[1] >> 3) & 0x3f;
367 /* Save number of bits */
368 Encode(bits
, context
->bcount
, 8);
370 /* Pad out to 56 mod 64. */
371 SHA1Update(context
, PADDING
, ((index
< 56) ? 56 : 120) - index
);
373 /* Append length (before padding) */
374 SHA1Update(context
, bits
, 8);
376 /* Store state in digest */
377 Encode(digest
, context
->state
, 20);
379 /* Zeroize sensitive information. */
380 memset(context
, 0, sizeof (*context
));
384 * SHA1 basic transformation. Transforms state based on block.
386 #if !(defined (__x86_64__) || defined (__i386__))
388 SHA1Transform(SHA1_CTX
*context
, const u_int8_t block
[64])
390 /* Register (instead of array) is a win in most cases */
391 register u_int32_t a
, b
, c
, d
, e
;
392 register u_int32_t w0
, w1
, w2
, w3
, w4
, w5
, w6
, w7
;
393 register u_int32_t w8
, w9
, w10
, w11
, w12
, w13
, w14
, w15
;
395 a
= context
->state
[0];
396 b
= context
->state
[1];
397 c
= context
->state
[2];
398 d
= context
->state
[3];
399 e
= context
->state
[4];
401 w15
= FETCH_32(block
+ 60);
402 w14
= FETCH_32(block
+ 56);
403 w13
= FETCH_32(block
+ 52);
404 w12
= FETCH_32(block
+ 48);
405 w11
= FETCH_32(block
+ 44);
406 w10
= FETCH_32(block
+ 40);
407 w9
= FETCH_32(block
+ 36);
408 w8
= FETCH_32(block
+ 32);
409 w7
= FETCH_32(block
+ 28);
410 w6
= FETCH_32(block
+ 24);
411 w5
= FETCH_32(block
+ 20);
412 w4
= FETCH_32(block
+ 16);
413 w3
= FETCH_32(block
+ 12);
414 w2
= FETCH_32(block
+ 8);
415 w1
= FETCH_32(block
+ 4);
416 w0
= FETCH_32(block
+ 0);
419 R1(e
, a
, b
, c
, d
, w0
); /* 0 */
420 R1(d
, e
, a
, b
, c
, w1
); /* 1 */
421 R1(c
, d
, e
, a
, b
, w2
); /* 2 */
422 R1(b
, c
, d
, e
, a
, w3
); /* 3 */
423 R1(a
, b
, c
, d
, e
, w4
); /* 4 */
424 R1(e
, a
, b
, c
, d
, w5
); /* 5 */
425 R1(d
, e
, a
, b
, c
, w6
); /* 6 */
426 R1(c
, d
, e
, a
, b
, w7
); /* 7 */
427 R1(b
, c
, d
, e
, a
, w8
); /* 8 */
428 R1(a
, b
, c
, d
, e
, w9
); /* 9 */
429 R1(e
, a
, b
, c
, d
, w10
); /* 10 */
430 R1(d
, e
, a
, b
, c
, w11
); /* 11 */
431 R1(c
, d
, e
, a
, b
, w12
); /* 12 */
432 R1(b
, c
, d
, e
, a
, w13
); /* 13 */
433 R1(a
, b
, c
, d
, e
, w14
); /* 14 */
434 R1(e
, a
, b
, c
, d
, w15
); /* 15 */
435 WUPDATE( w0
, w13
, w8
, w2
); R1(d
, e
, a
, b
, c
, w0
); /* 16 */
436 WUPDATE( w1
, w14
, w9
, w3
); R1(c
, d
, e
, a
, b
, w1
); /* 17 */
437 WUPDATE( w2
, w15
, w10
, w4
); R1(b
, c
, d
, e
, a
, w2
); /* 18 */
438 WUPDATE( w3
, w0
, w11
, w5
); R1(a
, b
, c
, d
, e
, w3
); /* 19 */
441 WUPDATE( w4
, w1
, w12
, w6
); R2(e
, a
, b
, c
, d
, w4
); /* 20 */
442 WUPDATE( w5
, w2
, w13
, w7
); R2(d
, e
, a
, b
, c
, w5
); /* 21 */
443 WUPDATE( w6
, w3
, w14
, w8
); R2(c
, d
, e
, a
, b
, w6
); /* 22 */
444 WUPDATE( w7
, w4
, w15
, w9
); R2(b
, c
, d
, e
, a
, w7
); /* 23 */
445 WUPDATE( w8
, w5
, w0
, w10
); R2(a
, b
, c
, d
, e
, w8
); /* 24 */
446 WUPDATE( w9
, w6
, w1
, w11
); R2(e
, a
, b
, c
, d
, w9
); /* 25 */
447 WUPDATE(w10
, w7
, w2
, w12
); R2(d
, e
, a
, b
, c
, w10
); /* 26 */
448 WUPDATE(w11
, w8
, w3
, w13
); R2(c
, d
, e
, a
, b
, w11
); /* 27 */
449 WUPDATE(w12
, w9
, w4
, w14
); R2(b
, c
, d
, e
, a
, w12
); /* 28 */
450 WUPDATE(w13
, w10
, w5
, w15
); R2(a
, b
, c
, d
, e
, w13
); /* 29 */
451 WUPDATE(w14
, w11
, w6
, w0
); R2(e
, a
, b
, c
, d
, w14
); /* 30 */
452 WUPDATE(w15
, w12
, w7
, w1
); R2(d
, e
, a
, b
, c
, w15
); /* 31 */
453 WUPDATE( w0
, w13
, w8
, w2
); R2(c
, d
, e
, a
, b
, w0
); /* 32 */
454 WUPDATE( w1
, w14
, w9
, w3
); R2(b
, c
, d
, e
, a
, w1
); /* 33 */
455 WUPDATE( w2
, w15
, w10
, w4
); R2(a
, b
, c
, d
, e
, w2
); /* 34 */
456 WUPDATE( w3
, w0
, w11
, w5
); R2(e
, a
, b
, c
, d
, w3
); /* 35 */
457 WUPDATE( w4
, w1
, w12
, w6
); R2(d
, e
, a
, b
, c
, w4
); /* 36 */
458 WUPDATE( w5
, w2
, w13
, w7
); R2(c
, d
, e
, a
, b
, w5
); /* 37 */
459 WUPDATE( w6
, w3
, w14
, w8
); R2(b
, c
, d
, e
, a
, w6
); /* 38 */
460 WUPDATE( w7
, w4
, w15
, w9
); R2(a
, b
, c
, d
, e
, w7
); /* 39 */
463 WUPDATE( w8
, w5
, w0
, w10
); R3(e
, a
, b
, c
, d
, w8
); /* 40 */
464 WUPDATE( w9
, w6
, w1
, w11
); R3(d
, e
, a
, b
, c
, w9
); /* 41 */
465 WUPDATE(w10
, w7
, w2
, w12
); R3(c
, d
, e
, a
, b
, w10
); /* 42 */
466 WUPDATE(w11
, w8
, w3
, w13
); R3(b
, c
, d
, e
, a
, w11
); /* 43 */
467 WUPDATE(w12
, w9
, w4
, w14
); R3(a
, b
, c
, d
, e
, w12
); /* 44 */
468 WUPDATE(w13
, w10
, w5
, w15
); R3(e
, a
, b
, c
, d
, w13
); /* 45 */
469 WUPDATE(w14
, w11
, w6
, w0
); R3(d
, e
, a
, b
, c
, w14
); /* 46 */
470 WUPDATE(w15
, w12
, w7
, w1
); R3(c
, d
, e
, a
, b
, w15
); /* 47 */
471 WUPDATE( w0
, w13
, w8
, w2
); R3(b
, c
, d
, e
, a
, w0
); /* 48 */
472 WUPDATE( w1
, w14
, w9
, w3
); R3(a
, b
, c
, d
, e
, w1
); /* 49 */
473 WUPDATE( w2
, w15
, w10
, w4
); R3(e
, a
, b
, c
, d
, w2
); /* 50 */
474 WUPDATE( w3
, w0
, w11
, w5
); R3(d
, e
, a
, b
, c
, w3
); /* 51 */
475 WUPDATE( w4
, w1
, w12
, w6
); R3(c
, d
, e
, a
, b
, w4
); /* 52 */
476 WUPDATE( w5
, w2
, w13
, w7
); R3(b
, c
, d
, e
, a
, w5
); /* 53 */
477 WUPDATE( w6
, w3
, w14
, w8
); R3(a
, b
, c
, d
, e
, w6
); /* 54 */
478 WUPDATE( w7
, w4
, w15
, w9
); R3(e
, a
, b
, c
, d
, w7
); /* 55 */
479 WUPDATE( w8
, w5
, w0
, w10
); R3(d
, e
, a
, b
, c
, w8
); /* 56 */
480 WUPDATE( w9
, w6
, w1
, w11
); R3(c
, d
, e
, a
, b
, w9
); /* 57 */
481 WUPDATE(w10
, w7
, w2
, w12
); R3(b
, c
, d
, e
, a
, w10
); /* 58 */
482 WUPDATE(w11
, w8
, w3
, w13
); R3(a
, b
, c
, d
, e
, w11
); /* 59 */
484 WUPDATE(w12
, w9
, w4
, w14
); R4(e
, a
, b
, c
, d
, w12
); /* 60 */
485 WUPDATE(w13
, w10
, w5
, w15
); R4(d
, e
, a
, b
, c
, w13
); /* 61 */
486 WUPDATE(w14
, w11
, w6
, w0
); R4(c
, d
, e
, a
, b
, w14
); /* 62 */
487 WUPDATE(w15
, w12
, w7
, w1
); R4(b
, c
, d
, e
, a
, w15
); /* 63 */
488 WUPDATE( w0
, w13
, w8
, w2
); R4(a
, b
, c
, d
, e
, w0
); /* 64 */
489 WUPDATE( w1
, w14
, w9
, w3
); R4(e
, a
, b
, c
, d
, w1
); /* 65 */
490 WUPDATE( w2
, w15
, w10
, w4
); R4(d
, e
, a
, b
, c
, w2
); /* 66 */
491 WUPDATE( w3
, w0
, w11
, w5
); R4(c
, d
, e
, a
, b
, w3
); /* 67 */
492 WUPDATE( w4
, w1
, w12
, w6
); R4(b
, c
, d
, e
, a
, w4
); /* 68 */
493 WUPDATE( w5
, w2
, w13
, w7
); R4(a
, b
, c
, d
, e
, w5
); /* 69 */
494 WUPDATE( w6
, w3
, w14
, w8
); R4(e
, a
, b
, c
, d
, w6
); /* 70 */
495 WUPDATE( w7
, w4
, w15
, w9
); R4(d
, e
, a
, b
, c
, w7
); /* 71 */
496 WUPDATE( w8
, w5
, w0
, w10
); R4(c
, d
, e
, a
, b
, w8
); /* 72 */
497 WUPDATE( w9
, w6
, w1
, w11
); R4(b
, c
, d
, e
, a
, w9
); /* 73 */
498 WUPDATE(w10
, w7
, w2
, w12
); R4(a
, b
, c
, d
, e
, w10
); /* 74 */
499 WUPDATE(w11
, w8
, w3
, w13
); R4(e
, a
, b
, c
, d
, w11
); /* 75 */
500 WUPDATE(w12
, w9
, w4
, w14
); R4(d
, e
, a
, b
, c
, w12
); /* 76 */
501 WUPDATE(w13
, w10
, w5
, w15
); R4(c
, d
, e
, a
, b
, w13
); /* 77 */
502 WUPDATE(w14
, w11
, w6
, w0
); R4(b
, c
, d
, e
, a
, w14
); /* 78 */
503 WUPDATE(w15
, w12
, w7
, w1
); R4(a
, b
, c
, d
, e
, w15
); /* 79 */
505 context
->state
[0] += a
;
506 context
->state
[1] += b
;
507 context
->state
[2] += c
;
508 context
->state
[3] += d
;
509 context
->state
[4] += e
;
511 /* Zeroize sensitive information. */
512 w15
= w14
= w13
= w12
= w11
= w10
= w9
= w8
= 0;
513 w7
= w6
= w5
= w4
= w3
= w2
= w1
= w0
= 0;