feeCipherFileAtom.c   [plain text]


/* Copyright (c) 1998 Apple Computer, 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 COMPUTER, INC. AND THE
 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE COMPUTER,
 * 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	Doug Mitchell at Apple
 *	Modified to use portable byte representation.
 * 23 Oct 96	Doug Mitchell 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);
}