CipherFileDES.c   [plain text]


/* 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.
 ***************************************************************************
 *
 * CipherFileDES.c - DES-related cipherfile support
 *
 * Revision History
 * ----------------
 * 24 Jun 97 at Apple
 *	Fixed memory leaks via sigData
 * 18 Feb 97 at Apple
 *	Split off from feeCipherFile.c
 */

#include "ckconfig.h"

#if	CRYPTKIT_CIPHERFILE_ENABLE

#include "Crypt.h"
#include "CipherFileDES.h"
#include "falloc.h"
#include "feeDebug.h"
#include <string.h>

/*
 * These functions are only called from feeCipherFile.c.
 */
feeReturn createRandDES(feePubKey sendPrivKey,	// for sig only
	feePubKey recvPubKey,
	const unsigned char *plainText,
	unsigned plainTextLen,
	int genSig,				// 1 ==> generate signature
	unsigned userData,			// for caller's convenience
	feeCipherFile *cipherFile)		// RETURNED if successful
{
	feeRand		frand = NULL;
	feeReturn	frtn;
	unsigned char	desKey[FEE_DES_MIN_STATE_SIZE];
	unsigned char	*encrDesKey = NULL;	// FEED encrypted desKey
	unsigned	encrDesKeyLen;
	feeDES		des = NULL;
	feeFEEDExp	feed = NULL;
	unsigned char	*cipherText = NULL;
	unsigned	cipherTextLen;
	unsigned char	*sigData = NULL;
	unsigned	sigDataLen = 0;
	feeCipherFile	cfile = NULL;
	unsigned char	*pubKeyString = NULL;	// of sendPrivKey
	unsigned	pubKeyStringLen = 0;

	if(recvPubKey == NULL) {
		return FR_BadPubKey;
	}

	/*
	 * Cons up random DES key and a feeDES object with it
	 */
	frand = feeRandAlloc();
	if(frand == NULL) {
		frtn = FR_Internal;
		goto out;
	}
	feeRandBytes(frand, desKey, FEE_DES_MIN_STATE_SIZE);
	des = feeDESNewWithState(desKey, FEE_DES_MIN_STATE_SIZE);
	if(des == NULL) {
		frtn = FR_Internal;
		goto out;
	}

	/*
	 * Encrypt the DES key via FEEDExp
	 */
	feed = feeFEEDExpNewWithPubKey(recvPubKey, NULL, NULL);
	if(feed == NULL) {
		frtn = FR_BadPubKey;
		goto out;
	}
	frtn = feeFEEDExpEncrypt(feed,
		desKey,
		FEE_DES_MIN_STATE_SIZE,
		&encrDesKey,
		&encrDesKeyLen);
	if(frtn) {
		goto out;
	}

	/*
	 * Encrypt the plaintext via DES
	 */
	frtn = feeDESEncrypt(des,
		plainText,
		plainTextLen,
		&cipherText,
		&cipherTextLen);
	if(frtn) {
		goto out;
	}

	if(genSig) {
		/*
		 * We generate signature on ciphertext by convention.
		 */
		if(sendPrivKey == NULL) {
			frtn = FR_BadPubKey;
			goto out;
		}
		frtn = feePubKeyCreateSignature(sendPrivKey,
			cipherText,
			cipherTextLen,
			&sigData,
			&sigDataLen);
		if(frtn) {
			goto out;
		}
		/*
		 * Sender's public key string
		 */
		frtn = feePubKeyCreateKeyString(sendPrivKey,
			(char **)&pubKeyString,
			&pubKeyStringLen);
		if(frtn) {
			/*
			 * Huh?
			 */
			frtn = FR_BadPubKey;
			goto out;
		}
	}

	/*
	 * Cons up a cipherfile
	 */
	cfile = feeCFileNewFromCipherText(CFE_RandDES,
		cipherText,
		cipherTextLen,
		pubKeyString,
		pubKeyStringLen,
		encrDesKey,
		encrDesKeyLen,
		sigData,
		sigDataLen,
		userData);
	if(cfile == NULL) {
		frtn = FR_Internal;
		goto out;
	}

out:
	/* free alloc'd stuff */

	if(cipherText) {
		ffree(cipherText);
	}
	if(feed) {
		feeFEEDExpFree(feed);
	}
	if(frand) {
		feeRandFree(frand);
	}
	if(des) {
		feeDESFree(des);
	}
	if(sigData) {
		ffree(sigData);
	}
	if(encrDesKey) {
		ffree(encrDesKey);
	}
	if(pubKeyString) {
		ffree(pubKeyString);
	}
	memset(desKey, 0, FEE_DES_MIN_STATE_SIZE);
	*cipherFile = cfile;
	return frtn;

}

feeReturn decryptRandDES(feeCipherFile cipherFile,
	feePubKey recvPrivKey,
	feePubKey sendPubKey,				// optional
	unsigned char **plainText,			// RETURNED
	unsigned *plainTextLen,				// RETURNED
	feeSigStatus *sigStatus)			// RETURNED
{
	feeReturn 	frtn = FR_Success;
	unsigned char	*cipherText = NULL;
	unsigned	cipherTextLen;
	feeFEEDExp	feed = NULL;		// to decrypt desKey
	feeDES		des = NULL;		// to decrypt cipherText
	unsigned char	*desKey;
	unsigned	desKeyLen;
	unsigned char	*encrDesKey = NULL;	// FEED encrypted desKey
	unsigned	encrDesKeyLen;
	unsigned char	*sigData = NULL;
	unsigned	sigDataLen;
	unsigned char	*sendPubKeyStr = NULL;
	unsigned	sendPubKeyStrLen = 0;
	feePubKey 	parsedSendPubKey = NULL;

	if(feeCFileEncrType(cipherFile) != CFE_RandDES) {
		frtn = FR_Internal;
		goto out;
	}

	/*
	 * Get ciphertext and encrypted DES key from cipherFile
	 */
	cipherText = feeCFileCipherText(cipherFile, &cipherTextLen);
	if(cipherText == NULL) {
		frtn = FR_BadCipherFile;
		goto out;
	}
	encrDesKey = feeCFileOtherKeyData(cipherFile, &encrDesKeyLen);
	if(encrDesKey == NULL) {
		frtn = FR_BadCipherFile;
		goto out;
	}

	/*
	 * FEED decrypt to get DES key
	 */
	feed = feeFEEDExpNewWithPubKey(recvPrivKey, NULL, NULL);
	if(feed == NULL) {
		frtn = FR_BadPubKey;
		goto out;
	}
	frtn = feeFEEDExpDecrypt(feed,
		encrDesKey,
		encrDesKeyLen,
		&desKey,
		&desKeyLen);
	if(frtn) {
		goto out;
	}

	/*
	 * Now DES decrypt the ciphertext
	 */
	if(desKeyLen != FEE_DES_MIN_STATE_SIZE) {
		frtn = FR_BadCipherFile;
		goto out;
	}
	des = feeDESNewWithState(desKey, desKeyLen);
	if(des == NULL) {
		frtn = FR_Internal;
		goto out;
	}
	frtn = feeDESDecrypt(des,
		cipherText,
		cipherTextLen,
		plainText,
		plainTextLen);
	if(frtn) {
		goto out;
	}

	sigData = feeCFileSigData(cipherFile, &sigDataLen);
	if(sigData) {
		feeReturn sigFrtn;

		if(sendPubKey == NULL) {
			/*
			 * Obtain sender's public key from cipherfile
			 */
			sendPubKeyStr = feeCFileSendPubKeyData(cipherFile,
				&sendPubKeyStrLen);
			if(sendPubKeyStr == NULL) {
			    /*
			     * Hmm..shouldn't really happen, but let's
			     * press on.
			     */
			    *sigStatus = SS_PresentNoKey;
			    goto out;
			}
			parsedSendPubKey = feePubKeyAlloc();
			frtn = feePubKeyInitFromKeyString(parsedSendPubKey,
				(char *)sendPubKeyStr, sendPubKeyStrLen);
			if(frtn) {
			    dbgLog(("parseRandDES: bad sendPubKeyStr\n"));
			    *sigStatus = SS_PresentNoKey;
			    goto out;
			}
			sendPubKey = parsedSendPubKey;
		}
		sigFrtn = feePubKeyVerifySignature(sendPubKey,
			cipherText,
			cipherTextLen,
			sigData,
			sigDataLen);
		switch(sigFrtn) {
		    case FR_Success:
		    	*sigStatus = SS_PresentValid;
			break;
		    default:
		    	*sigStatus = SS_PresentInvalid;
			break;
		}
	}
	else {
		*sigStatus = SS_NotPresent;
	}
out:
	if(cipherText) {
		ffree(cipherText);
	}
	if(feed) {
		feeFEEDExpFree(feed);
	}
	if(des) {
		feeDESFree(des);
	}
	if(desKey) {
		memset(desKey, 0, desKeyLen);
		ffree(desKey);
	}
	if(encrDesKey) {
		ffree(encrDesKey);
	}
	if(sigData) {
		ffree(sigData);
	}
	if(parsedSendPubKey) {
		feePubKeyFree(parsedSendPubKey);
	}
	if(sendPubKeyStr) {
		ffree(sendPubKeyStr);
	}
	return frtn;
}

feeReturn createPubDES(feePubKey sendPrivKey,	// required
	feePubKey recvPubKey,
	const unsigned char *plainText,
	unsigned plainTextLen,
	int genSig,				// 1 ==> generate signature
	unsigned userData,			// for caller's convenience
	feeCipherFile *cipherFile)		// RETURNED if successful
{
	feeRand		frand = NULL;
	feeReturn	frtn;
	unsigned char	*desKey;
	unsigned	desKeyLen;
	feeDES		des = NULL;
	unsigned char	*cipherText = NULL;
	unsigned	cipherTextLen;
	unsigned char	*sigData = NULL;
	unsigned	sigDataLen = 0;
	feeCipherFile	cfile = NULL;
	unsigned char	*pubKeyString = NULL;
	unsigned	pubKeyStringLen;

	if((sendPrivKey == NULL) || (recvPubKey == NULL)) {
		return FR_BadPubKey;
	}

	/*
	 * Get the public string version of sendPrivKey for embedding in
	 * cipherfile
	 */
	frtn = feePubKeyCreateKeyString(sendPrivKey,
		(char **)&pubKeyString,
		&pubKeyStringLen);
	if(frtn) {
		goto out;
	}

	/*
	 * Obtain DES key via key exchange and get a feeDES object with it
	 */
	frtn = feePubKeyCreatePad(sendPrivKey,
		recvPubKey,
		&desKey,
		&desKeyLen);
	if(frtn) {
		goto out;
	}
	des = feeDESNewWithState(desKey, desKeyLen);
	if(des == NULL) {
		frtn = FR_Internal;
		goto out;
	}

	/*
	 * Encrypt the plaintext via DES
	 */
	frtn = feeDESEncrypt(des,
		plainText,
		plainTextLen,
		&cipherText,
		&cipherTextLen);
	if(frtn) {
		goto out;
	}

	if(genSig) {
		/*
		 * We generate signature on ciphertext by convention.
		 */
		frtn = feePubKeyCreateSignature(sendPrivKey,
			cipherText,
			cipherTextLen,
			&sigData,
			&sigDataLen);
		if(frtn) {
			goto out;
		}
	}

	/*
	 * Cons up a cipherfile
	 */
	cfile = feeCFileNewFromCipherText(CFE_PublicDES,
		cipherText,
		cipherTextLen,
		pubKeyString,
		pubKeyStringLen,
		NULL,			// otherKey
		0,
		sigData,
		sigDataLen,
		userData);
	if(cfile == NULL) {
		frtn = FR_Internal;
		goto out;
	}

out:
	/* free alloc'd stuff */

	if(cipherText) {
		ffree(cipherText);
	}
	if(frand) {
		feeRandFree(frand);
	}
	if(des) {
		feeDESFree(des);
	}
	if(desKey) {
		ffree(desKey);
	}
	if(sigData) {
		ffree(sigData);
	}
	if(pubKeyString) {
		ffree(pubKeyString);
	}
	*cipherFile = cfile;
	return frtn;

}

feeReturn decryptPubDES(feeCipherFile cipherFile,
	feePubKey recvPrivKey,
	feePubKey sendPubKey,
	unsigned char **plainText,			// RETURNED
	unsigned *plainTextLen,				// RETURNED
	feeSigStatus *sigStatus)			// RETURNED
{
	feeReturn 	frtn = FR_Success;
	unsigned char	*cipherText = NULL;
	unsigned	cipherTextLen;
	feeDES		des = NULL;		// to decrypt cipherText
	unsigned char	*desKey;
	unsigned	desKeyLen;
	unsigned char	*sigData = NULL;
	unsigned	sigDataLen;
	unsigned char	*pubKeyString = NULL;
	unsigned	pubKeyStringLen;
	feePubKey	decryptPubKey = NULL;	// from cipherfile

	if(feeCFileEncrType(cipherFile) != CFE_PublicDES) {
		frtn = FR_Internal;
		goto out;
	}

	/*
	 * Get ciphertext and sender's public key from cipherFile
	 */
	cipherText = feeCFileCipherText(cipherFile, &cipherTextLen);
	if(cipherText == NULL) {
		frtn = FR_BadCipherFile;
		goto out;
	}
	pubKeyString = feeCFileSendPubKeyData(cipherFile, &pubKeyStringLen);
	if(pubKeyString == NULL) {
		frtn = FR_BadCipherFile;
		goto out;
	}
	decryptPubKey = feePubKeyAlloc();
	frtn = feePubKeyInitFromKeyString(decryptPubKey,
		(char *)pubKeyString,
		pubKeyStringLen);
	if(frtn) {
		goto out;
	}

	/*
	 * key exchange to get DES key
	 */
	frtn = feePubKeyCreatePad(recvPrivKey,
		decryptPubKey,
		&desKey,
		&desKeyLen);
	if(frtn) {
		goto out;
	}

	/*
	 * Now DES decrypt the ciphertext
	 */
	if(desKeyLen < FEE_DES_MIN_STATE_SIZE) {
		frtn = FR_BadCipherFile;
		goto out;
	}
	des = feeDESNewWithState(desKey, desKeyLen);
	if(des == NULL) {
		frtn = FR_Internal;
		goto out;
	}
	frtn = feeDESDecrypt(des,
		cipherText,
		cipherTextLen,
		plainText,
		plainTextLen);
	if(frtn) {
		goto out;
	}

	sigData = feeCFileSigData(cipherFile, &sigDataLen);
	if(sigData) {
		feeReturn sigFrtn;

		if(sendPubKey == NULL) {
			/*
			 * Use key embedded in cipherfile
			 */
			sendPubKey = decryptPubKey;
		}
		sigFrtn = feePubKeyVerifySignature(sendPubKey,
			cipherText,
			cipherTextLen,
			sigData,
			sigDataLen);
		switch(sigFrtn) {
		    case FR_Success:
		    	*sigStatus = SS_PresentValid;
			break;
		    default:
		    	*sigStatus = SS_PresentInvalid;
			break;
		}
	}
	else {
		*sigStatus = SS_NotPresent;
	}
out:
	if(cipherText) {
		ffree(cipherText);
	}
	if(des) {
		feeDESFree(des);
	}
	if(desKey) {
		ffree(desKey);
	}
	if(pubKeyString) {
		ffree(pubKeyString);
	}
	if(sigData) {
		ffree(sigData);
	}
	if(decryptPubKey) {
		feePubKeyFree(decryptPubKey);
	}
	return frtn;
}

#endif	/* CRYPTKIT_CIPHERFILE_ENABLE */