--- /dev/null
+/* 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.
+ ***************************************************************************
+ *
+ * feeCipherFile.c
+ *
+ * Revision History
+ * ----------------
+ * 10/06/98 ap
+ * Changed to compile with C++.
+ * 05 Feb 97 at Apple
+ * Modified to use portable byte representation.
+ * 23 Oct 96 at NeXT
+ * Created.
+ */
+
+#include "feeCipherFile.h"
+#include "falloc.h"
+#include "platform.h"
+#include "feeDebug.h"
+#include "byteRep.h"
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif /* NULL */
+
+/*
+ * These must match constants of same name in CipherFileAtom.java.
+ */
+#define CFILE_MAGIC 0xfeecf111
+#define CFILE_VERSION 1
+#define CFILE_MIN_VERSION 1
+
+/*
+ * Format of a feeCipherFile header.
+ * Offsets and lengths refer to locations of components in cFileInst.dataRep.
+ * This struct appears at the start of a feeCipherFile data representation.
+ */
+typedef struct {
+ unsigned magic;
+ unsigned version;
+ unsigned minVersion;
+ unsigned totalLength; // equals dataRepLen
+ cipherFileEncrType encrType;
+ unsigned cipherTextOffset; // offset of ciphertext
+ unsigned cipherTextLen; // in bytes
+ unsigned sendPubKeyDataOffset; // optional
+ unsigned sendPubKeyDataLen;
+ unsigned otherKeyDataOffset; // optional
+ unsigned otherKeyDataLen;
+ unsigned sigDataOffset; // optional
+ unsigned sigDataLen; // 0 means no signature
+ unsigned userData;
+} cFileHeader;
+
+/*
+ * Private data, represented by a feeCipherFile handle.
+ */
+typedef struct {
+ cFileHeader header;
+ unsigned char *dataRep; // raw data
+ unsigned dataRepLen;
+} cFileInst;
+
+static unsigned lengthOfByteRepCfileHdr(void);
+static unsigned cfileHdrToByteRep(cFileHeader *hdr,
+ unsigned char *s);
+static void byteRepToCfileHdr(const unsigned char *s,
+ cFileHeader *hdr);
+
+
+/*
+ * alloc, free cFileInst
+ */
+static cFileInst *cFileInstAlloc()
+{
+ cFileInst *cfinst = (cFileInst *) fmalloc(sizeof(cFileInst));
+
+ bzero(cfinst, sizeof(cFileInst));
+ return cfinst;
+}
+
+static void cFileInstFree(cFileInst *cfinst)
+{
+ if(cfinst->dataRep) {
+ ffree(cfinst->dataRep);
+ }
+ ffree(cfinst);
+}
+
+/*
+ * Alloc and return a new feeCipherFile object associated with the specified
+ * data.
+ */
+feeCipherFile feeCFileNewFromCipherText(cipherFileEncrType encrType,
+ const unsigned char *cipherText,
+ unsigned cipherTextLen,
+ const unsigned char *sendPubKeyData, // optional
+ unsigned sendPubKeyDataLen, // 0 if sendPubKeyData is NULL
+ const unsigned char *otherKeyData, // optional
+ unsigned otherKeyDataLen, // 0 if otherKeyData is NULL
+ const unsigned char *sigData, // optional; NULL means no signature
+ unsigned sigDataLen, // 0 if sigData is NULL
+ unsigned userData) // for caller's convenience
+{
+ cFileInst *cfinst;
+ cFileHeader *header;
+ unsigned char *data;
+
+ if(cipherTextLen == 0) {
+ return NULL;
+ }
+ cfinst = cFileInstAlloc();
+ header = &cfinst->header;
+
+ /*
+ * Init the header.
+ */
+ header->magic = CFILE_MAGIC;
+ header->version = CFILE_VERSION;
+ header->minVersion = CFILE_MIN_VERSION;
+ header->totalLength = lengthOfByteRepCfileHdr() + cipherTextLen +
+ sendPubKeyDataLen + otherKeyDataLen +
+ sigDataLen;
+ header->encrType = encrType;
+ header->cipherTextOffset = lengthOfByteRepCfileHdr();
+ header->cipherTextLen = cipherTextLen;
+ header->sendPubKeyDataOffset = header->cipherTextOffset +
+ cipherTextLen;
+ header->sendPubKeyDataLen = sendPubKeyDataLen;
+ header->otherKeyDataOffset = header->sendPubKeyDataOffset +
+ sendPubKeyDataLen;
+ header->otherKeyDataLen = otherKeyDataLen;
+ header->sigDataOffset = header->otherKeyDataOffset +
+ otherKeyDataLen;
+ header->sigDataLen = sigDataLen;
+ header->userData = userData;
+
+ /*
+ * Alloc a data representation, copy various components to it.
+ */
+ cfinst->dataRepLen = header->totalLength;
+ data = cfinst->dataRep = (unsigned char*) fmalloc(cfinst->dataRepLen);
+ cfileHdrToByteRep(header, data);
+
+ data = cfinst->dataRep + header->cipherTextOffset;
+ bcopy(cipherText, data, cipherTextLen);
+ if(sendPubKeyDataLen) {
+ data = cfinst->dataRep + header->sendPubKeyDataOffset;
+ bcopy(sendPubKeyData, data, sendPubKeyDataLen);
+ }
+ if(otherKeyDataLen) {
+ data = cfinst->dataRep + header->otherKeyDataOffset;
+ bcopy(otherKeyData, data, otherKeyDataLen);
+ }
+ if(sigDataLen) {
+ data = cfinst->dataRep + header->sigDataOffset;
+ bcopy(sigData, data, sigDataLen);
+ }
+ return (feeCipherFile)cfinst;
+}
+
+/*
+ * Obtain the contents of a feeCipherFile as a byte stream.
+ */
+feeReturn feeCFileDataRepresentation(feeCipherFile cipherFile,
+ const unsigned char **dataRep,
+ unsigned *dataRepLen)
+{
+ cFileInst *cfinst = (cFileInst *)cipherFile;
+
+ if(cfinst->dataRepLen == 0) {
+ *dataRep = NULL;
+ *dataRepLen = 0;
+ return FR_BadCipherFile;
+ }
+ *dataRep = (unsigned char*) fmallocWithData(cfinst->dataRep, cfinst->dataRepLen);
+ *dataRepLen = cfinst->dataRepLen;
+ return FR_Success;
+}
+
+/*
+ * Alloc and return a new feeCipherFile object, given a byte stream (originally
+ * obtained from feeCFDataRepresentation()).
+ */
+feeReturn feeCFileNewFromDataRep(const unsigned char *dataRep,
+ unsigned dataRepLen,
+ feeCipherFile *cipherFile) // RETURNED if sucessful
+{
+ cFileInst *cfinst = cFileInstAlloc();
+ cFileHeader *header;
+
+ if(dataRepLen < lengthOfByteRepCfileHdr()) {
+ dbgLog(("datRep too short\n"));
+ goto abort;
+ }
+ cfinst->dataRep = (unsigned char*) fmallocWithData(dataRep, dataRepLen);
+ cfinst->dataRepLen = dataRepLen;
+ header = &cfinst->header;
+ byteRepToCfileHdr(dataRep, header);
+
+ /*
+ * As much consistency checking as we can manage here.
+ */
+ if(header->magic != CFILE_MAGIC) {
+ dbgLog(("Bad cipherFile magic number\n"));
+ goto abort;
+ }
+ if(header->minVersion > CFILE_VERSION) {
+ dbgLog(("Incompatible cipherFile version\n"));
+ goto abort;
+ }
+ if(header->totalLength != dataRepLen) {
+ dbgLog(("Bad totalLength in cipherFile header\n"));
+ goto abort;
+ }
+ if(((header->cipherTextOffset + header->cipherTextLen) >
+ header->totalLength) ||
+ ((header->sendPubKeyDataOffset + header->sendPubKeyDataLen) >
+ header->totalLength) ||
+ ((header->otherKeyDataOffset + header->otherKeyDataLen) >
+ header->totalLength) ||
+ ((header->sigDataOffset + header->sigDataLen) >
+ header->totalLength)) {
+ dbgLog(("Bad element lengths in cipherFile header\n"));
+ goto abort;
+ }
+
+ /*
+ * OK, looks good.
+ */
+ *cipherFile = (feeCipherFile)cfinst;
+ return FR_Success;
+abort:
+ cFileInstFree(cfinst);
+ *cipherFile = NULL;
+ return FR_BadCipherFile;
+}
+
+/*
+ * Free a feeCipherFile object.
+ */
+void feeCFileFree(feeCipherFile cipherFile)
+{
+ cFileInstFree((cFileInst *)cipherFile);
+}
+
+/*
+ * Given a feeCipherFile object (typically obtained from
+ * feeCFileNewFromData()), obtain its constituent parts.
+ *
+ * Data returned must be freed by caller.
+ * feeCFileSigData() may return NULL, indicating no signature present.
+ */
+cipherFileEncrType feeCFileEncrType(feeCipherFile cipherFile)
+{
+ cFileInst *cfinst = (cFileInst *)cipherFile;
+
+ return cfinst->header.encrType;
+}
+
+unsigned char *feeCFileCipherText(feeCipherFile cipherFile,
+ unsigned *cipherTextLen)
+{
+ cFileInst *cfinst = (cFileInst *)cipherFile;
+
+ if(cfinst->header.cipherTextLen) {
+ *cipherTextLen = cfinst->header.cipherTextLen;
+ return (unsigned char*) fmallocWithData(cfinst->dataRep +
+ cfinst->header.cipherTextOffset, *cipherTextLen);
+ }
+ else {
+ dbgLog(("feeCFileCipherText: no cipherText\n"));
+ *cipherTextLen = 0;
+ return NULL;
+ }
+}
+
+unsigned char *feeCFileSendPubKeyData(feeCipherFile cipherFile,
+ unsigned *sendPubKeyDataLen)
+{
+ cFileInst *cfinst = (cFileInst *)cipherFile;
+
+ if(cfinst->header.sendPubKeyDataLen) {
+ *sendPubKeyDataLen = cfinst->header.sendPubKeyDataLen;
+ return (unsigned char*) fmallocWithData(cfinst->dataRep +
+ cfinst->header.sendPubKeyDataOffset,
+ *sendPubKeyDataLen);
+ }
+ else {
+ *sendPubKeyDataLen = 0;
+ return NULL;
+ }
+}
+
+unsigned char *feeCFileOtherKeyData(feeCipherFile cipherFile,
+ unsigned *otherKeyDataLen)
+{
+ cFileInst *cfinst = (cFileInst *)cipherFile;
+
+ if(cfinst->header.otherKeyDataLen) {
+ *otherKeyDataLen = cfinst->header.otherKeyDataLen;
+ return (unsigned char*) fmallocWithData(cfinst->dataRep +
+ cfinst->header.otherKeyDataOffset, *otherKeyDataLen);
+ }
+ else {
+ *otherKeyDataLen = 0;
+ return NULL;
+ }
+}
+
+unsigned char *feeCFileSigData(feeCipherFile cipherFile,
+ unsigned *sigDataLen)
+{
+ cFileInst *cfinst = (cFileInst *)cipherFile;
+
+ if(cfinst->header.sigDataLen) {
+ *sigDataLen = cfinst->header.sigDataLen;
+ return (unsigned char*) fmallocWithData(cfinst->dataRep +
+ cfinst->header.sigDataOffset, *sigDataLen);
+ }
+ else {
+ /*
+ * Not an error
+ */
+ *sigDataLen = 0;
+ return NULL;
+ }
+}
+
+unsigned feeCFileUserData(feeCipherFile cipherFile)
+{
+ cFileInst *cfinst = (cFileInst *)cipherFile;
+
+ return cfinst->header.userData;
+}
+
+/*
+ * Convert between cFileHeader and portable byte representation.
+ */
+
+/*
+ * Return size of byte rep of cFileHeader. We just happen to know that
+ * this is the same size as the header....
+ */
+static unsigned lengthOfByteRepCfileHdr(void)
+{
+ return sizeof(cFileHeader);
+}
+
+static unsigned cfileHdrToByteRep(cFileHeader *hdr,
+ unsigned char *s)
+{
+ s += intToByteRep(hdr->magic, s);
+ s += intToByteRep(hdr->version, s);
+ s += intToByteRep(hdr->minVersion, s);
+ s += intToByteRep(hdr->totalLength, s);
+ s += intToByteRep(hdr->encrType, s);
+ s += intToByteRep(hdr->cipherTextOffset, s);
+ s += intToByteRep(hdr->cipherTextLen, s);
+ s += intToByteRep(hdr->sendPubKeyDataOffset, s);
+ s += intToByteRep(hdr->sendPubKeyDataLen, s);
+ s += intToByteRep(hdr->otherKeyDataOffset, s);
+ s += intToByteRep(hdr->otherKeyDataLen, s);
+ s += intToByteRep(hdr->sigDataOffset, s);
+ s += intToByteRep(hdr->sigDataLen, s);
+ s += intToByteRep(hdr->userData, s);
+ return sizeof(cFileHeader);
+}
+
+#define DEC_INT(n, b) \
+ n = byteRepToInt(b); \
+ b += sizeof(int);
+
+static void byteRepToCfileHdr(const unsigned char *s,
+ cFileHeader *hdr)
+{
+ DEC_INT(hdr->magic, s);
+ DEC_INT(hdr->version, s);
+ DEC_INT(hdr->minVersion, s);
+ DEC_INT(hdr->totalLength, s);
+// DEC_INT(hdr->encrType, s);
+ hdr->encrType = (cipherFileEncrType) byteRepToInt(s);
+ s += sizeof(int);
+ DEC_INT(hdr->cipherTextOffset, s);
+ DEC_INT(hdr->cipherTextLen, s);
+ DEC_INT(hdr->sendPubKeyDataOffset, s);
+ DEC_INT(hdr->sendPubKeyDataLen, s);
+ DEC_INT(hdr->otherKeyDataOffset, s);
+ DEC_INT(hdr->otherKeyDataLen, s);
+ DEC_INT(hdr->sigDataOffset, s);
+ DEC_INT(hdr->sigDataLen, s);
+ DEC_INT(hdr->userData, s);
+}