1/*
2 * Copyright (c) 2012 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24// #define COMMON_DIGEST_FUNCTIONS
25#define COMMON_DIGEST_FOR_RFC_1321
26
27#include "CommonDigest.h"
28#include "CommonDigestPriv.h"
29#include "CommonDigestSPI.h"
30#include "ccErrors.h"
31#include "ccGlobals.h"
32#include "ccMemory.h"
33#include "ccdebug.h"
34#include <stdio.h>
35#include <dispatch/dispatch.h>
36#include <dispatch/queue.h>
37#include <corecrypto/ccmd2.h>
38#include <corecrypto/ccmd4.h>
39#include <corecrypto/ccmd5.h>
40#include <corecrypto/ccripemd.h>
41#include <corecrypto/ccsha1.h>
42#include <corecrypto/ccsha2.h>
43
44// #define NDEBUG
45#ifndef	NDEBUG
46#define ASSERT(s)
47#else
48#define ASSERT(s)	assert(s)
49#endif
50
51static const size_t diMax = kCCDigestSkein512+1;
52
53// This returns a pointer to the corecrypto "di" structure for a digest.
54// It's used for all functions that need a di (HMac, Key Derivation, etc).
55
56const struct ccdigest_info *
57CCDigestGetDigestInfo(CCDigestAlgorithm algorithm) {
58    cc_globals_t globals = _cc_globals();
59    dispatch_once(&globals->digest_info_init, ^{
60        globals->digest_info = (const struct ccdigest_info **)calloc(diMax, sizeof(struct ccdigest_info *));
61        globals->digest_info[kCCDigestNone] = NULL;
62        globals->digest_info[kCCDigestMD2] = &ccmd2_di;
63        globals->digest_info[kCCDigestMD4] = &ccmd4_di;
64        globals->digest_info[kCCDigestMD5] = ccmd5_di();
65        globals->digest_info[kCCDigestRMD128] = &ccrmd128_di;
66        globals->digest_info[kCCDigestRMD160] = &ccrmd160_di;
67        globals->digest_info[kCCDigestRMD256] = &ccrmd256_di;
68        globals->digest_info[kCCDigestRMD320] = &ccrmd320_di;
69        globals->digest_info[kCCDigestSHA1] = ccsha1_di();
70        globals->digest_info[kCCDigestSHA224] = ccsha224_di();
71        globals->digest_info[kCCDigestSHA256] = ccsha256_di();
72        globals->digest_info[kCCDigestSHA384] = ccsha384_di();
73        globals->digest_info[kCCDigestSHA512] = ccsha512_di();
74        globals->digest_info[kCCDigestSkein128] = NULL;
75        globals->digest_info[kCCDigestSkein160] = NULL;
76        globals->digest_info[15] = NULL; // gap
77        globals->digest_info[kCCDigestSkein224] = NULL;
78        globals->digest_info[kCCDigestSkein256] = NULL;
79        globals->digest_info[kCCDigestSkein384] = NULL;
80        globals->digest_info[kCCDigestSkein512] = NULL;
81    });
82    return globals->digest_info[algorithm];
83}
84
85
86int
87CCDigestInit(CCDigestAlgorithm alg, CCDigestRef c)
88{
89    if(alg == 0 || alg >= diMax) return kCCParamError;
90    if(!c) return kCCParamError;
91
92    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering Algorithm: %d\n", alg);
93    CCDigestCtxPtr p = (CCDigestCtxPtr) c;
94
95    if((p->di = CCDigestGetDigestInfo(alg)) != NULL) {
96        ccdigest_init(p->di, (struct ccdigest_ctx *) p->md);
97		return 0;
98    } else {
99        return kCCUnimplemented;
100    }
101}
102
103int
104CCDigestUpdate(CCDigestRef c, const void *data, size_t len)
105{
106    // CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
107    if(c == NULL) return kCCParamError;
108    if(len == 0) return kCCSuccess;
109    if(data == NULL) return kCCParamError; /* this is only a problem if len > 0 */
110    CCDigestCtxPtr p = (CCDigestCtxPtr) c;
111    if(p->di) {
112        ccdigest_update(p->di, (struct ccdigest_ctx *) p->md, len, data);
113        return kCCSuccess;
114    }
115    return kCCUnimplemented;
116}
117
118int
119CCDigestFinal(CCDigestRef c, uint8_t *out)
120{
121    // CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
122	if(c == NULL || out == NULL) return kCCParamError;
123	CCDigestCtxPtr p = (CCDigestCtxPtr) c;
124    if(p->di) {
125        ccdigest_final(p->di, (struct ccdigest_ctx *) p->md, out);
126        return 0;
127    }
128    return kCCUnimplemented;
129}
130
131int
132CCDigest(CCDigestAlgorithm alg, const uint8_t *data, size_t len, uint8_t *out)
133{
134    const struct ccdigest_info *di;
135
136    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering Algorithm: %d\n", alg);
137    if((di = CCDigestGetDigestInfo(alg)) != NULL) {
138        ccdigest(di, len, data, out);
139        return 0;
140    }
141    return kCCUnimplemented;
142}
143
144size_t
145CCDigestGetBlockSize(CCDigestAlgorithm algorithm)
146{
147    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering Algorithm: %d\n", algorithm);
148    const struct ccdigest_info *di = CCDigestGetDigestInfo(algorithm);
149    if(di) return di->block_size;
150    return kCCUnimplemented;
151}
152
153size_t
154CCDigestGetOutputSize(CCDigestAlgorithm algorithm)
155{
156    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering Algorithm: %d\n", algorithm);
157    const struct ccdigest_info *di = CCDigestGetDigestInfo(algorithm);
158    if(di) return di->output_size;
159    return kCCUnimplemented;
160}
161
162size_t
163CCDigestGetBlockSizeFromRef(CCDigestRef ctx)
164{
165    // CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
166    CCDigestCtxPtr p = (CCDigestCtxPtr) ctx;
167    if(p->di) return p->di->block_size;
168    return kCCUnimplemented;
169}
170
171size_t
172CCDigestBlockSize(CCDigestRef ctx)
173{
174    // CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
175    return CCDigestGetBlockSizeFromRef(ctx);
176}
177
178size_t
179CCDigestOutputSize(CCDigestRef ctx)
180{
181    // CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
182    return CCDigestGetOutputSizeFromRef(ctx);
183}
184
185size_t
186CCDigestGetOutputSizeFromRef(CCDigestRef ctx)
187{
188    // CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
189    CCDigestCtxPtr p = (CCDigestCtxPtr) ctx;
190    if(p->di) return p->di->output_size;
191    return kCCUnimplemented;
192}
193
194
195
196
197
198CCDigestRef
199CCDigestCreate(CCDigestAlgorithm alg)
200{
201	CCDigestRef retval = CC_XMALLOC(sizeof(CCDigestCtx));
202
203    // CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
204    if(!retval) return NULL;
205    if(CCDigestInit(alg, retval)) {
206    	CC_XFREE(retval, sizeof(CCDigestCtx_t));
207    	return NULL;
208    }
209    return retval;
210}
211
212
213uint8_t *
214CCDigestOID(CCDigestRef ctx)
215{
216    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
217    CCDigestCtxPtr p = (CCDigestCtxPtr) ctx;
218	return p->di->oid;
219}
220
221size_t
222CCDigestOIDLen(CCDigestRef ctx)
223{
224    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
225    CCDigestCtxPtr p = (CCDigestCtxPtr) ctx;
226	return p->di->oid_size;
227}
228
229CCDigestRef
230CCDigestCreateByOID(uint8_t *OID, size_t OIDlen)
231{
232    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
233    for(unsigned int i=kCCDigestMD2; i<diMax; i++) {
234        const struct ccdigest_info *di = CCDigestGetDigestInfo(i);
235        if(di && (OIDlen == di->oid_size) && (CC_XMEMCMP(OID, di->oid, OIDlen) == 0))
236            return CCDigestCreate(i);
237    }
238    return NULL;
239}
240
241void
242CCDigestReset(CCDigestRef ctx)
243{
244    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
245    CCDigestCtxPtr p = (CCDigestCtxPtr) ctx;
246    if(p->di) ccdigest_init(p->di, (struct ccdigest_ctx *) p->md);
247}
248
249
250void
251CCDigestDestroy(CCDigestRef ctx)
252{
253    // CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
254	if(ctx) {
255		CC_XZEROMEM(ctx, sizeof(CCDigestCtx_t));
256		CC_XFREE(ctx, sizeof(CCDigestCtx_t));
257    }
258}
259/*
260 * Legacy CommonDigest API shims.
261 */
262
263#define CC_COMPAT_DIGEST_RETURN 1
264
265// corecrypto to CommonCrypto
266#define CC_ccToCC_DIGEST_CTX(di,cc_c,CC_c)                                \
267    CC_XMEMCPY((uint8_t*)CC_c, ccdigest_state_u8(di, cc_c), di->state_size); \
268    CC_XMEMCPY(&CC_c->data[0], ccdigest_data(di, cc_c), di->block_size);  \
269    CC_XMEMCPY(&CC_c->Nl, &ccdigest_nbits(di, cc_c), 2*sizeof(CC_c->Nl)); \
270    CC_c->num=ccdigest_num(di, cc_c);
271
272// CommonCrypto to corecrypto
273#define CC_CCTocc_DIGEST_CTX(di,CC_c,cc_c)                                \
274    CC_XMEMCPY(ccdigest_state_u8(di, cc_c), (uint8_t*)CC_c, di->state_size); \
275    CC_XMEMCPY(ccdigest_data(di, cc_c), &CC_c->data[0], di->block_size);  \
276    CC_XMEMCPY(&ccdigest_nbits(di, cc_c), &CC_c->Nl, 2*sizeof(CC_c->Nl)); \
277    ccdigest_num(di, cc_c)=CC_c->num;
278
279
280#define DIGEST_SHIMS(_name_,_constant_) \
281\
282int CC_##_name_##_Init(CC_##_name_##_CTX *CC_ctx) { \
283    ASSERT(sizeof(CC_##_name_##_CTX) <= ccdigest_di_size(CCDigestGetDigestInfo(_constant_))); \
284    const struct ccdigest_info *di=CCDigestGetDigestInfo(_constant_); \
285    ccdigest_di_decl(di, cc_ctx); \
286    ccdigest_init(di, cc_ctx); \
287    CC_ccToCC_DIGEST_CTX(di,cc_ctx,CC_ctx); \
288	return 1; \
289} \
290 \
291int \
292CC_##_name_##_Update(CC_##_name_##_CTX *CC_ctx, const void *data, CC_LONG len) \
293{ \
294    const struct ccdigest_info *di=CCDigestGetDigestInfo(_constant_); \
295    ccdigest_di_decl(di, cc_ctx); \
296    CC_CCTocc_DIGEST_CTX(di,CC_ctx,cc_ctx); \
297    ccdigest_update(di, cc_ctx, len, data); \
298    CC_ccToCC_DIGEST_CTX(di,cc_ctx,CC_ctx); \
299	return 1; \
300} \
301 \
302int \
303CC_##_name_##_Final(unsigned char *md, CC_##_name_##_CTX *CC_ctx) \
304{ \
305    const struct ccdigest_info *di=CCDigestGetDigestInfo(_constant_); \
306    ccdigest_di_decl(di, cc_ctx); \
307    CC_CCTocc_DIGEST_CTX(di,CC_ctx,cc_ctx); \
308    ccdigest_final(di, cc_ctx, md); \
309    CC_ccToCC_DIGEST_CTX(di,cc_ctx,CC_ctx); \
310	return 1; \
311} \
312 \
313unsigned char * \
314CC_##_name_ (const void *data, CC_LONG len, unsigned char *md) \
315{ \
316	(void) CCDigest(_constant_, data, len, md); \
317	return md; \
318}
319
320
321#define DIGEST_FINAL_SHIMS(_name_,_constant_) \
322unsigned char * \
323CC_##_name_ (const void *data, CC_LONG len, unsigned char *md) \
324{ \
325(void) CCDigest(_constant_, data, len, md); \
326return md; \
327}
328
329
330
331DIGEST_FINAL_SHIMS(MD2, kCCDigestMD2)
332DIGEST_SHIMS(MD4, kCCDigestMD4)
333DIGEST_SHIMS(MD5, kCCDigestMD5)
334DIGEST_SHIMS(SHA1, kCCDigestSHA1)
335DIGEST_FINAL_SHIMS(SHA224, kCCDigestSHA224)
336DIGEST_FINAL_SHIMS(SHA256, kCCDigestSHA256)
337DIGEST_FINAL_SHIMS(SHA384, kCCDigestSHA384)
338DIGEST_FINAL_SHIMS(SHA512, kCCDigestSHA512)
339
340
341#define MD5_CTX                     CC_MD5_CTX
342void MD5Final(unsigned char md[16], MD5_CTX *c)
343{
344    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
345    (void) CC_MD5_Final(md, c);
346}
347
348static void
349ccdigest_process(const struct ccdigest_info *di, uint8_t *bufptr, ccdigest_state_t state,
350                 uint64_t curlen, size_t len, const uint8_t *data)
351{
352    while(len) {
353        if (curlen == 0 && len >= di->block_size) {
354            uint64_t fullblocks = len / di->block_size;
355            di->compress(state, (unsigned long) fullblocks, data);
356            uint64_t nbytes = fullblocks * di->block_size;
357            len -= nbytes; data += nbytes;
358        } else {
359            uint64_t n = CC_XMIN(len, (di->block_size - curlen));
360            CC_XMEMCPY(bufptr + curlen, data, n);
361            curlen += n; len -= n; data += n;
362            if (curlen == di->block_size) {
363                di->compress(state, 1, bufptr);
364                curlen = 0;
365            }
366        }
367    }
368}
369
370static void
371ccdigest_finalize(const struct ccdigest_info *di, uint8_t *bufptr, ccdigest_state_t state,
372                  uint64_t curlen, uint64_t totalLen)
373{
374    bufptr[curlen++] = (unsigned char)0x80;
375    int reserve = 8;
376    if(di->block_size == 128) reserve = 16; // SHA384/512 reserves 16 bytes below.
377
378    /* if the length is currently above block_size - reserve bytes we append zeros
379     * then compress.  Then we can fall back to padding zeros and length
380     * encoding like normal.
381     */
382
383    if (curlen > (di->block_size - reserve)) {
384        while (curlen < di->block_size) bufptr[curlen++] = (unsigned char)0;
385        di->compress(state, 1, bufptr);
386        curlen = 0;
387    }
388
389    /* pad out with zeros, but store length in last 8 bytes (sizeof uint64_t) */
390    while (curlen < (di->block_size - 8))  bufptr[curlen++] = (unsigned char)0;
391    totalLen *= 8; // size in bits
392    CC_XSTORE64H(totalLen, bufptr+(di->block_size - 8));
393    di->compress(state, 1, bufptr);
394}
395
396/*
397 #define CC_MD2_DIGEST_LENGTH    16
398 #define CC_MD2_BLOCK_BYTES      64
399 #define CC_MD2_BLOCK_LONG       (CC_MD2_BLOCK_BYTES / sizeof(CC_LONG))
400
401
402 typedef struct CC_MD2state_st
403 {
404 int num;
405 unsigned char data[CC_MD2_DIGEST_LENGTH];
406 CC_LONG cksm[CC_MD2_BLOCK_LONG];
407 CC_LONG state[CC_MD2_BLOCK_LONG];
408 } CC_MD2_CTX;
409 */
410
411static inline void md2in(const struct ccdigest_info *di, ccdigest_ctx_t ctx, CC_MD2_CTX *c)
412{
413    CC_XMEMCPY(ccdigest_state_u8(di, ctx)+48, c->cksm, CC_MD2_BLOCK_LONG);
414    CC_XMEMCPY(ccdigest_state_u8(di, ctx), c->state, CC_MD2_BLOCK_LONG);
415    CC_XMEMCPY(ccdigest_data(di, ctx), c->data, CC_MD2_DIGEST_LENGTH);
416    ccdigest_num(di, ctx) = c->num;
417}
418
419static inline void md2out(const struct ccdigest_info *di, CC_MD2_CTX *c, ccdigest_ctx_t ctx)
420{
421    CC_XMEMCPY(c->cksm, ccdigest_state_u8(di, ctx)+48, CC_MD2_BLOCK_LONG);
422    CC_XMEMCPY(c->state, ccdigest_state_u8(di, ctx), CC_MD2_BLOCK_LONG);
423    CC_XMEMCPY(c->data, ccdigest_data(di, ctx), CC_MD2_DIGEST_LENGTH);
424    c->num = (int) ccdigest_num(di, ctx);
425}
426
427int CC_MD2_Init(CC_MD2_CTX *c)
428{
429    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestMD2);
430    ccdigest_di_decl(di, ctx);
431    ccdigest_init(di, ctx);
432    md2out(di, c, ctx);
433    return CC_COMPAT_DIGEST_RETURN;
434}
435
436int CC_MD2_Update(CC_MD2_CTX *c, const void *data, CC_LONG len)
437{
438    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestMD2);
439    ccdigest_di_decl(di, ctx);
440    md2in(di, ctx, c);
441    ccdigest_update(di, ctx, len, data);
442    md2out(di, c, ctx);
443    return CC_COMPAT_DIGEST_RETURN;
444}
445
446int CC_MD2_Final(unsigned char *md, CC_MD2_CTX *c)
447{
448    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestMD2);
449    ccdigest_di_decl(di, ctx);
450    md2in(di, ctx, c);
451    ccdigest_final(di, ctx, md);
452    md2out(di, c, ctx);
453    return CC_COMPAT_DIGEST_RETURN;
454}
455
456
457
458
459
460/*
461 typedef struct CC_SHA256state_st
462 {
463     CC_LONG count[2];
464     CC_LONG hash[8];
465     CC_LONG wbuf[16];
466 } CC_SHA256_CTX;
467
468 */
469
470typedef struct CC_SHA256state_x
471{
472    uint64_t count;
473    uint32_t hash[8];
474    uint32_t wbuf[16];
475} CC_SHA256_CTX_X;
476
477
478
479int
480CC_SHA256_Init(CC_SHA256_CTX *x)
481{
482    CC_SHA256_CTX_X *c = (CC_SHA256_CTX_X *) x;
483    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
484    ASSERT(sizeof(CC_SHA256_CTX) == sizeof(CC_SHA256_CTX_X));
485    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestSHA256);
486    ASSERT(di->state_size == CC_SHA256_DIGEST_LENGTH);
487    CC_XZEROMEM(c->hash, CC_SHA256_DIGEST_LENGTH);
488    ASSERT(di->block_size == CC_SHA256_BLOCK_BYTES);
489    CC_XZEROMEM(c->wbuf, CC_SHA256_BLOCK_BYTES);
490    c->count = 0;
491    CC_XMEMCPY(c->hash, di->initial_state, di->state_size);
492	return CC_COMPAT_DIGEST_RETURN;
493}
494
495int
496CC_SHA256_Update(CC_SHA256_CTX *x, const void *data, CC_LONG len)
497{
498    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestSHA256);
499    CC_SHA256_CTX_X *c = (CC_SHA256_CTX_X *) x;
500    uint64_t totalLen = c->count;
501	uint64_t curlen = totalLen % di->block_size;
502	uint8_t *bufptr = (uint8_t *) c->wbuf;
503    struct ccdigest_state *state = (struct ccdigest_state *) c->hash;
504
505    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
506   	if(!len || !data) return CC_COMPAT_DIGEST_RETURN;
507    c->count += len;
508
509    ccdigest_process(di, bufptr, state, curlen, len, data);
510
511    return CC_COMPAT_DIGEST_RETURN;
512}
513
514int
515CC_SHA256_Final(unsigned char *md, CC_SHA256_CTX *x)
516{
517    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestSHA256);
518    CC_SHA256_CTX_X *c = (CC_SHA256_CTX_X *) x;
519    uint64_t totalLen = c->count;
520	uint64_t curlen = totalLen % di->block_size;
521	uint8_t *bufptr = (uint8_t *) c->wbuf;
522    struct ccdigest_state *state = (struct ccdigest_state *) c->hash;
523
524    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
525    if(!md) return CC_COMPAT_DIGEST_RETURN;
526
527    ccdigest_finalize(di, bufptr, state, curlen, totalLen);
528
529    /* copy output */
530    for (int i = 0; i < 8; i++)  CC_XSTORE32H(c->hash[i], md+(4*i));
531
532	return CC_COMPAT_DIGEST_RETURN;
533}
534
535
536/*
537typedef struct CC_SHA512state_st
538{   CC_LONG64 count[2];
539    CC_LONG64 hash[8];
540    CC_LONG64 wbuf[16];
541} CC_SHA512_CTX;
542*/
543
544typedef struct CC_SHA512state_x
545{
546    uint64_t count;
547    uint64_t countx;
548    uint64_t hash[8];
549    uint64_t wbuf[16];
550} CC_SHA512_CTX_X;
551
552
553int
554CC_SHA512_Init(CC_SHA512_CTX *x)
555{
556    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
557    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestSHA512);
558    CC_SHA512_CTX_X *c = (CC_SHA512_CTX_X *) x;
559    ASSERT(di->state_size == CC_SHA512_DIGEST_LENGTH);
560    CC_XZEROMEM(c->hash, CC_SHA512_DIGEST_LENGTH);
561    ASSERT(di->block_size == CC_SHA512_BLOCK_BYTES);
562    CC_XZEROMEM(c->wbuf, CC_SHA512_BLOCK_BYTES);
563    c->count = 0;
564    CC_XMEMCPY(c->hash, di->initial_state, di->state_size);
565	return CC_COMPAT_DIGEST_RETURN;
566}
567
568int
569CC_SHA512_Update(CC_SHA512_CTX *x, const void *data, CC_LONG len)
570{
571    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestSHA512);
572    CC_SHA512_CTX_X *c = (CC_SHA512_CTX_X *) x;
573    uint64_t totalLen = c->count;
574	uint64_t curlen = totalLen % di->block_size;
575	uint8_t *bufptr = (uint8_t *) c->wbuf;
576    struct ccdigest_state *state = (struct ccdigest_state *) c->hash;
577
578    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
579
580   	if(!len || !data) return CC_COMPAT_DIGEST_RETURN;
581
582    c->count += len;
583    ccdigest_process(di, bufptr, state, curlen, len, data);
584    return CC_COMPAT_DIGEST_RETURN;
585}
586
587int
588CC_SHA512_Final(unsigned char *md, CC_SHA512_CTX *x)
589{
590    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestSHA512);
591    CC_SHA512_CTX_X *c = (CC_SHA512_CTX_X *) x;
592    uint64_t totalLen = c->count;
593	uint64_t curlen = totalLen % di->block_size;
594	uint8_t *bufptr = (uint8_t *) c->wbuf;
595    struct ccdigest_state *state = (struct ccdigest_state *) c->hash;
596
597    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
598    if(!md) return CC_COMPAT_DIGEST_RETURN;
599
600    ccdigest_finalize(di, bufptr, state, curlen, totalLen);
601
602    /* copy output */
603    for (unsigned long i = 0; i < di->output_size/8; i++)  CC_XSTORE64H(c->hash[i], md+(8*i));
604
605	return CC_COMPAT_DIGEST_RETURN;
606}
607
608/*
609 * Dependent sets of routines (SHA224 and SHA384)
610 */
611
612int
613CC_SHA224_Init(CC_SHA256_CTX *c)
614{
615    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
616    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestSHA224);
617    ASSERT(di->state_size == CC_SHA256_DIGEST_LENGTH);
618    CC_XZEROMEM(c->hash, CC_SHA256_DIGEST_LENGTH);
619    ASSERT(di->block_size == CC_SHA256_BLOCK_BYTES);
620    CC_XZEROMEM(c->wbuf, CC_SHA256_BLOCK_BYTES);
621    c->count[0] = c->count[1] = 0;
622    CC_XMEMCPY(c->hash, di->initial_state, di->state_size);
623	return CC_COMPAT_DIGEST_RETURN;
624}
625
626int
627CC_SHA224_Update(CC_SHA256_CTX *c, const void *data, CC_LONG len)
628{
629    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
630	return CC_SHA256_Update(c, data, len);
631}
632
633int
634CC_SHA224_Final(unsigned char *md, CC_SHA256_CTX *c)
635{
636    uint32_t buf[CC_SHA256_DIGEST_LENGTH/4];
637    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
638
639    CC_SHA256_Final((unsigned char *) buf, c);
640    CC_XMEMCPY(md, buf, CC_SHA224_DIGEST_LENGTH);
641	return CC_COMPAT_DIGEST_RETURN;
642}
643
644
645int
646CC_SHA384_Init(CC_SHA512_CTX *c)
647{
648    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
649    const struct ccdigest_info *di = CCDigestGetDigestInfo(kCCDigestSHA384);
650    ASSERT(di->state_size == CC_SHA512_DIGEST_LENGTH);
651    CC_XZEROMEM(c->hash, CC_SHA512_DIGEST_LENGTH);
652    ASSERT(di->block_size == CC_SHA512_BLOCK_BYTES);
653    CC_XZEROMEM(c->wbuf, CC_SHA512_BLOCK_BYTES);
654    c->count[0] = c->count[1] = 0;
655    CC_XMEMCPY(c->hash, di->initial_state, di->state_size);
656	return CC_COMPAT_DIGEST_RETURN;
657}
658
659
660int
661CC_SHA384_Update(CC_SHA512_CTX *c, const void *data, CC_LONG len)
662{
663    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
664	return CC_SHA512_Update(c, data, len);
665}
666
667int
668CC_SHA384_Final(unsigned char *md, CC_SHA512_CTX *c)
669{
670    uint64_t buf[CC_SHA512_DIGEST_LENGTH/8];
671
672    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
673    CC_SHA512_Final((unsigned char *) buf, c);
674    CC_XMEMCPY(md, buf, CC_SHA384_DIGEST_LENGTH);
675	return CC_COMPAT_DIGEST_RETURN;
676}
677
678