+/* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved.
+ *
+ * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
+ * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
+ * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
+ * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
+ * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
+ * EXPOSE YOU TO LIABILITY.
+ ***************************************************************************
+ *
+ * ckSHA1.c - generic, portable SHA-1 hash object
+ *
+ * Revision History
+ * ----------------
+ * 10/06/98 ap
+ * Changed to compile with C++.
+ * 07 Jan 1998 at Apple
+ * Created.
+ */
+
+#include "ckconfig.h"
+#include "feeTypes.h"
+#include "ckSHA1.h"
+
+#if CRYPTKIT_LIBMD_DIGEST
+/*
+ * For linking with AppleCSP: use libSystem SHA1 implementation.
+ */
+#include <CommonCrypto/CommonDigest.h>
+#else
+#include "ckSHA1_priv.h"
+#endif
+#include "falloc.h"
+#include "platform.h"
+
+#if CRYPTKIT_LIBMD_DIGEST
+/*
+ * Trivial wrapper for SHA_CTX; a sha1Obj is a pointer to this.
+ */
+typedef struct {
+ CC_SHA1_CTX ctx;
+ unsigned char digest[CC_SHA1_DIGEST_LENGTH];
+} Sha1Obj;
+
+sha1Obj sha1Alloc(void)
+{
+ void *rtn = fmalloc(sizeof(Sha1Obj));
+ memset(rtn, 0, sizeof(Sha1Obj));
+ CC_SHA1_Init(&(((Sha1Obj *)rtn)->ctx));
+ return (sha1Obj)rtn;
+}
+
+void sha1Reinit(sha1Obj sha1)
+{
+ Sha1Obj *ctx = (Sha1Obj *)sha1;
+ CC_SHA1_Init(&ctx->ctx);
+}
+
+void sha1Free(sha1Obj sha1)
+{
+ memset(sha1, 0, sizeof(Sha1Obj));
+ ffree(sha1);
+}
+
+void sha1AddData(sha1Obj sha1,
+ const unsigned char *data,
+ unsigned dataLen)
+{
+ Sha1Obj *ctx = (Sha1Obj *)sha1;
+ CC_SHA1_Update(&ctx->ctx, data, dataLen);
+}
+
+unsigned char *sha1Digest(sha1Obj sha1)
+{
+ Sha1Obj *ctx = (Sha1Obj *)sha1;
+ CC_SHA1_Final(ctx->digest, &ctx->ctx);
+ return ctx->digest;
+}
+
+unsigned sha1DigestLen(void)
+{
+ return CC_SHA1_DIGEST_LENGTH;
+}
+
+#else /* standalone cryptkit implementation */
+
+/*
+ * Private data for this object. A sha1Obj handle is cast to a pointer
+ * to one of these.
+ */
+typedef struct {
+ SHS_INFO context;
+ int isDone;
+
+ /*
+ * For storing partial blocks
+ */
+ BYTE dataBuf[SHS_BLOCKSIZE];
+ unsigned bufBytes; // valid bytes in dataBuf[p]
+} sha1Inst;
+
+/*
+ * Alloc and init an empty sha1 object.
+ */
+sha1Obj sha1Alloc(void)
+{
+ sha1Inst *sinst;
+
+ sinst = (sha1Inst *)fmalloc(sizeof(sha1Inst));
+ if(sinst == NULL) {
+ return NULL;
+ }
+ shsInit(&sinst->context);
+ sha1Reinit((sha1Obj)sinst);
+ return (sha1Obj)sinst;
+}
+
+/*
+ * Reusable init function.
+ */
+void sha1Reinit(sha1Obj sha1)
+{
+ sha1Inst *sinst = (sha1Inst *) sha1;
+
+ shsInit(&sinst->context);
+ sinst->isDone = 0;
+ sinst->bufBytes = 0;
+}
+
+/*
+ * Free an sha1 object.
+ */
+void sha1Free(sha1Obj sha1)
+{
+ sha1Inst *sinst = (sha1Inst *) sha1;
+
+ memset(sha1, 0, sizeof(sha1Inst));
+ ffree(sinst);
+}
+
+/*
+ * Add some data to the sha1 object.
+ */
+void sha1AddData(sha1Obj sha1,
+ const unsigned char *data,
+ unsigned dataLen)
+{
+ sha1Inst *sinst = (sha1Inst *) sha1;
+ unsigned toMove;
+ unsigned blocks;
+
+ if(sinst->isDone) {
+ /*
+ * Log some kind of error here...
+ */
+ return;
+ }
+
+ /*
+ * First deal with partial buffered block
+ */
+ if(sinst->bufBytes != 0) {
+ toMove = SHS_BLOCKSIZE - sinst->bufBytes;
+ if(toMove > dataLen) {
+ toMove = dataLen;
+ }
+ memmove(sinst->dataBuf+sinst->bufBytes, data, toMove);
+ data += toMove;
+ dataLen -= toMove;
+ sinst->bufBytes += toMove;
+ if(sinst->bufBytes == SHS_BLOCKSIZE) {
+ shsUpdate(&sinst->context, sinst->dataBuf, SHS_BLOCKSIZE);
+ sinst->bufBytes = 0;
+ }
+ }
+
+ /*
+ * Now the bulk of the data, in a multiple of full blocks
+ */
+ blocks = dataLen / SHS_BLOCKSIZE;
+ toMove = blocks * SHS_BLOCKSIZE;
+ if(toMove != 0) {
+ shsUpdate(&sinst->context, data, toMove);
+ data += toMove;
+ dataLen -= toMove;
+ }
+
+ /*
+ * Store any remainder in dataBuf
+ */
+ if(dataLen != 0) {
+ memmove(sinst->dataBuf, data, dataLen);
+ sinst->bufBytes = dataLen;
+ }
+}
+
+/*
+ * Obtain a pointer to completed message digest, and the length of the digest.
+ */
+unsigned char *sha1Digest(sha1Obj sha1)
+{
+ sha1Inst *sinst = (sha1Inst *) sha1;
+
+ if(!sinst->isDone) {
+ /*
+ * Deal with partial resid block
+ */
+ if(sinst->bufBytes != 0) {
+ shsUpdate(&sinst->context, sinst->dataBuf,
+ sinst->bufBytes);
+ sinst->bufBytes = 0;
+ }
+ shsFinal(&sinst->context);
+ sinst->isDone = 1;
+ }
+ /*
+ * FIXME - should do explicit conversion to char array....?
+ */
+ return (unsigned char *)sinst->context.digest;
+}
+
+unsigned sha1DigestLen(void)
+{
+ return SHS_DIGESTSIZE;
+}
+
+#endif /* CRYPTKIT_LIBMD_DIGEST */