1/* Copyright (c) 1998,2004 Apple Computer, Inc.  All Rights Reserved.
2 *
3 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
4 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
5 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE COMPUTER, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE COMPUTER,
7 * INC.  ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
8 * EXPOSE YOU TO LIABILITY.
9 ***************************************************************************
10 *
11 * SHA1.c - generic, portable SHA-1 hash object
12 *
13 * Revision History
14 * ----------------
15 * 10/06/98		ap
16 *	Changed to compile with C++.
17 * 07 Jan 1998	Doug Mitchell at Apple
18 *	Created.
19 */
20
21#include "SHA1.h"
22#include "SHA1_priv.h"
23#include <strings.h>
24
25/* for now map falloc to malloc, FIXME */
26#include <stdlib.h>
27#define fmalloc(s)	malloc(s)
28#define ffree(p)	free(p)
29
30/*
31 * Private data for this object. A sha1Obj handle is cast to a pointer
32 * to one of these.
33 */
34typedef struct {
35	SHS_INFO 	context;
36	int 		isDone;
37
38	/*
39	 * For storing partial blocks
40	 */
41	BYTE		dataBuf[SHS_BLOCKSIZE];
42	unsigned	bufBytes;		// valid bytes in dataBuf[p]
43} sha1Inst;
44
45/*
46 * Alloc and init an empty sha1 object.
47 */
48sha1Obj sha1Alloc(void)
49{
50	sha1Inst *sinst;
51
52	sinst = (sha1Inst *)fmalloc(sizeof(sha1Inst));
53	if(sinst == NULL) {
54		return NULL;
55	}
56	shsInit(&sinst->context);
57	sha1Reinit((sha1Obj)sinst);
58	return (sha1Obj)sinst;
59}
60
61/*
62 * Reusable init function.
63 */
64void sha1Reinit(sha1Obj sha1)
65{
66	sha1Inst *sinst = (sha1Inst *) sha1;
67
68	shsInit(&sinst->context);
69	sinst->isDone = 0;
70	sinst->bufBytes = 0;
71}
72
73/*
74 * Free an sha1 object.
75 */
76void sha1Free(sha1Obj sha1)
77{
78	sha1Inst *sinst = (sha1Inst *) sha1;
79
80	memset(sha1, 0, sizeof(sha1Inst));
81	ffree(sinst);
82}
83
84/*
85 * Add some data to the sha1 object.
86 */
87void sha1AddData(sha1Obj sha1,
88	const unsigned char *data,
89	unsigned dataLen)
90{
91	sha1Inst *sinst = (sha1Inst *) sha1;
92	unsigned toMove;
93	unsigned blocks;
94
95	if(sinst->isDone) {
96		/*
97		 * Log some kind of error here...
98		 */
99		return;
100	}
101
102	/*
103	 * First deal with partial buffered block
104	 */
105	if(sinst->bufBytes != 0) {
106		toMove = SHS_BLOCKSIZE - sinst->bufBytes;
107		if(toMove > dataLen) {
108			toMove = dataLen;
109		}
110		memmove(sinst->dataBuf+sinst->bufBytes, data, toMove);
111		data += toMove;
112		dataLen -= toMove;
113		sinst->bufBytes += toMove;
114		if(sinst->bufBytes == SHS_BLOCKSIZE) {
115		    shsUpdate(&sinst->context, sinst->dataBuf, SHS_BLOCKSIZE);
116		    sinst->bufBytes = 0;
117		}
118	}
119
120	/*
121	 * Now the bulk of the data, in a multiple of full blocks
122	 */
123	blocks = dataLen / SHS_BLOCKSIZE;
124	toMove = blocks * SHS_BLOCKSIZE;
125	if(toMove != 0) {
126	    shsUpdate(&sinst->context, data, toMove);
127	    data += toMove;
128	    dataLen -= toMove;
129	}
130
131	/*
132	 * Store any remainder in dataBuf
133	 */
134	if(dataLen != 0) {
135		memmove(sinst->dataBuf, data, dataLen);
136		sinst->bufBytes = dataLen;
137	}
138}
139
140/*
141 * Obtain a pointer to completed message digest, and the length of the digest.
142 */
143unsigned char *sha1Digest(sha1Obj sha1)
144{
145	sha1Inst *sinst = (sha1Inst *) sha1;
146
147	if(!sinst->isDone) {
148		/*
149		 * Deal with partial resid block
150		 */
151		if(sinst->bufBytes != 0) {
152			shsUpdate(&sinst->context, sinst->dataBuf,
153				sinst->bufBytes);
154			sinst->bufBytes = 0;
155		}
156		shsFinal(&sinst->context);
157		sinst->isDone = 1;
158	}
159	/*
160	 * FIXME - should do explicit conversion to char array....?
161	 */
162	return (unsigned char *)sinst->context.digest;
163}
164
165/* As above, with copy. */
166void sha1GetDigest(sha1Obj sha1,
167	unsigned char *digest)
168{
169	unsigned char *dig = sha1Digest(sha1);
170	memmove(digest, dig, SHS_DIGESTSIZE);
171}
172
173unsigned sha1DigestLen(void)
174{
175	return SHS_DIGESTSIZE;
176}
177