1/* Copyright (c) 1998 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 * CipherFileDES.c - DES-related cipherfile support
12 *
13 * Revision History
14 * ----------------
15 * 24 Jun 97	Doug Mitchell at Apple
16 *	Fixed memory leaks via sigData
17 * 18 Feb 97	Doug Mitchell at Apple
18 *	Split off from feeCipherFile.c
19 */
20
21#include "ckconfig.h"
22
23#if	CRYPTKIT_CIPHERFILE_ENABLE
24
25#include "Crypt.h"
26#include "CipherFileDES.h"
27#include "falloc.h"
28#include "feeDebug.h"
29#include <string.h>
30
31/*
32 * These functions are only called from feeCipherFile.c.
33 */
34feeReturn createRandDES(feePubKey sendPrivKey,	// for sig only
35	feePubKey recvPubKey,
36	const unsigned char *plainText,
37	unsigned plainTextLen,
38	int genSig,				// 1 ==> generate signature
39	unsigned userData,			// for caller's convenience
40	feeCipherFile *cipherFile)		// RETURNED if successful
41{
42	feeRand		frand = NULL;
43	feeReturn	frtn;
44	unsigned char	desKey[FEE_DES_MIN_STATE_SIZE];
45	unsigned char	*encrDesKey = NULL;	// FEED encrypted desKey
46	unsigned	encrDesKeyLen;
47	feeDES		des = NULL;
48	feeFEEDExp	feed = NULL;
49	unsigned char	*cipherText = NULL;
50	unsigned	cipherTextLen;
51	unsigned char	*sigData = NULL;
52	unsigned	sigDataLen = 0;
53	feeCipherFile	cfile = NULL;
54	unsigned char	*pubKeyString = NULL;	// of sendPrivKey
55	unsigned	pubKeyStringLen = 0;
56
57	if(recvPubKey == NULL) {
58		return FR_BadPubKey;
59	}
60
61	/*
62	 * Cons up random DES key and a feeDES object with it
63	 */
64	frand = feeRandAlloc();
65	if(frand == NULL) {
66		frtn = FR_Internal;
67		goto out;
68	}
69	feeRandBytes(frand, desKey, FEE_DES_MIN_STATE_SIZE);
70	des = feeDESNewWithState(desKey, FEE_DES_MIN_STATE_SIZE);
71	if(des == NULL) {
72		frtn = FR_Internal;
73		goto out;
74	}
75
76	/*
77	 * Encrypt the DES key via FEEDExp
78	 */
79	feed = feeFEEDExpNewWithPubKey(recvPubKey, NULL, NULL);
80	if(feed == NULL) {
81		frtn = FR_BadPubKey;
82		goto out;
83	}
84	frtn = feeFEEDExpEncrypt(feed,
85		desKey,
86		FEE_DES_MIN_STATE_SIZE,
87		&encrDesKey,
88		&encrDesKeyLen);
89	if(frtn) {
90		goto out;
91	}
92
93	/*
94	 * Encrypt the plaintext via DES
95	 */
96	frtn = feeDESEncrypt(des,
97		plainText,
98		plainTextLen,
99		&cipherText,
100		&cipherTextLen);
101	if(frtn) {
102		goto out;
103	}
104
105	if(genSig) {
106		/*
107		 * We generate signature on ciphertext by convention.
108		 */
109		if(sendPrivKey == NULL) {
110			frtn = FR_BadPubKey;
111			goto out;
112		}
113		frtn = feePubKeyCreateSignature(sendPrivKey,
114			cipherText,
115			cipherTextLen,
116			&sigData,
117			&sigDataLen);
118		if(frtn) {
119			goto out;
120		}
121		/*
122		 * Sender's public key string
123		 */
124		frtn = feePubKeyCreateKeyString(sendPrivKey,
125			(char **)&pubKeyString,
126			&pubKeyStringLen);
127		if(frtn) {
128			/*
129			 * Huh?
130			 */
131			frtn = FR_BadPubKey;
132			goto out;
133		}
134	}
135
136	/*
137	 * Cons up a cipherfile
138	 */
139	cfile = feeCFileNewFromCipherText(CFE_RandDES,
140		cipherText,
141		cipherTextLen,
142		pubKeyString,
143		pubKeyStringLen,
144		encrDesKey,
145		encrDesKeyLen,
146		sigData,
147		sigDataLen,
148		userData);
149	if(cfile == NULL) {
150		frtn = FR_Internal;
151		goto out;
152	}
153
154out:
155	/* free alloc'd stuff */
156
157	if(cipherText) {
158		ffree(cipherText);
159	}
160	if(feed) {
161		feeFEEDExpFree(feed);
162	}
163	if(frand) {
164		feeRandFree(frand);
165	}
166	if(des) {
167		feeDESFree(des);
168	}
169	if(sigData) {
170		ffree(sigData);
171	}
172	if(encrDesKey) {
173		ffree(encrDesKey);
174	}
175	if(pubKeyString) {
176		ffree(pubKeyString);
177	}
178	memset(desKey, 0, FEE_DES_MIN_STATE_SIZE);
179	*cipherFile = cfile;
180	return frtn;
181
182}
183
184feeReturn decryptRandDES(feeCipherFile cipherFile,
185	feePubKey recvPrivKey,
186	feePubKey sendPubKey,				// optional
187	unsigned char **plainText,			// RETURNED
188	unsigned *plainTextLen,				// RETURNED
189	feeSigStatus *sigStatus)			// RETURNED
190{
191	feeReturn 	frtn = FR_Success;
192	unsigned char	*cipherText = NULL;
193	unsigned	cipherTextLen;
194	feeFEEDExp	feed = NULL;		// to decrypt desKey
195	feeDES		des = NULL;		// to decrypt cipherText
196	unsigned char	*desKey;
197	unsigned	desKeyLen;
198	unsigned char	*encrDesKey = NULL;	// FEED encrypted desKey
199	unsigned	encrDesKeyLen;
200	unsigned char	*sigData = NULL;
201	unsigned	sigDataLen;
202	unsigned char	*sendPubKeyStr = NULL;
203	unsigned	sendPubKeyStrLen = 0;
204	feePubKey 	parsedSendPubKey = NULL;
205
206	if(feeCFileEncrType(cipherFile) != CFE_RandDES) {
207		frtn = FR_Internal;
208		goto out;
209	}
210
211	/*
212	 * Get ciphertext and encrypted DES key from cipherFile
213	 */
214	cipherText = feeCFileCipherText(cipherFile, &cipherTextLen);
215	if(cipherText == NULL) {
216		frtn = FR_BadCipherFile;
217		goto out;
218	}
219	encrDesKey = feeCFileOtherKeyData(cipherFile, &encrDesKeyLen);
220	if(encrDesKey == NULL) {
221		frtn = FR_BadCipherFile;
222		goto out;
223	}
224
225	/*
226	 * FEED decrypt to get DES key
227	 */
228	feed = feeFEEDExpNewWithPubKey(recvPrivKey, NULL, NULL);
229	if(feed == NULL) {
230		frtn = FR_BadPubKey;
231		goto out;
232	}
233	frtn = feeFEEDExpDecrypt(feed,
234		encrDesKey,
235		encrDesKeyLen,
236		&desKey,
237		&desKeyLen);
238	if(frtn) {
239		goto out;
240	}
241
242	/*
243	 * Now DES decrypt the ciphertext
244	 */
245	if(desKeyLen != FEE_DES_MIN_STATE_SIZE) {
246		frtn = FR_BadCipherFile;
247		goto out;
248	}
249	des = feeDESNewWithState(desKey, desKeyLen);
250	if(des == NULL) {
251		frtn = FR_Internal;
252		goto out;
253	}
254	frtn = feeDESDecrypt(des,
255		cipherText,
256		cipherTextLen,
257		plainText,
258		plainTextLen);
259	if(frtn) {
260		goto out;
261	}
262
263	sigData = feeCFileSigData(cipherFile, &sigDataLen);
264	if(sigData) {
265		feeReturn sigFrtn;
266
267		if(sendPubKey == NULL) {
268			/*
269			 * Obtain sender's public key from cipherfile
270			 */
271			sendPubKeyStr = feeCFileSendPubKeyData(cipherFile,
272				&sendPubKeyStrLen);
273			if(sendPubKeyStr == NULL) {
274			    /*
275			     * Hmm..shouldn't really happen, but let's
276			     * press on.
277			     */
278			    *sigStatus = SS_PresentNoKey;
279			    goto out;
280			}
281			parsedSendPubKey = feePubKeyAlloc();
282			frtn = feePubKeyInitFromKeyString(parsedSendPubKey,
283				(char *)sendPubKeyStr, sendPubKeyStrLen);
284			if(frtn) {
285			    dbgLog(("parseRandDES: bad sendPubKeyStr\n"));
286			    *sigStatus = SS_PresentNoKey;
287			    goto out;
288			}
289			sendPubKey = parsedSendPubKey;
290		}
291		sigFrtn = feePubKeyVerifySignature(sendPubKey,
292			cipherText,
293			cipherTextLen,
294			sigData,
295			sigDataLen);
296		switch(sigFrtn) {
297		    case FR_Success:
298		    	*sigStatus = SS_PresentValid;
299			break;
300		    default:
301		    	*sigStatus = SS_PresentInvalid;
302			break;
303		}
304	}
305	else {
306		*sigStatus = SS_NotPresent;
307	}
308out:
309	if(cipherText) {
310		ffree(cipherText);
311	}
312	if(feed) {
313		feeFEEDExpFree(feed);
314	}
315	if(des) {
316		feeDESFree(des);
317	}
318	if(desKey) {
319		memset(desKey, 0, desKeyLen);
320		ffree(desKey);
321	}
322	if(encrDesKey) {
323		ffree(encrDesKey);
324	}
325	if(sigData) {
326		ffree(sigData);
327	}
328	if(parsedSendPubKey) {
329		feePubKeyFree(parsedSendPubKey);
330	}
331	if(sendPubKeyStr) {
332		ffree(sendPubKeyStr);
333	}
334	return frtn;
335}
336
337feeReturn createPubDES(feePubKey sendPrivKey,	// required
338	feePubKey recvPubKey,
339	const unsigned char *plainText,
340	unsigned plainTextLen,
341	int genSig,				// 1 ==> generate signature
342	unsigned userData,			// for caller's convenience
343	feeCipherFile *cipherFile)		// RETURNED if successful
344{
345	feeRand		frand = NULL;
346	feeReturn	frtn;
347	unsigned char	*desKey;
348	unsigned	desKeyLen;
349	feeDES		des = NULL;
350	unsigned char	*cipherText = NULL;
351	unsigned	cipherTextLen;
352	unsigned char	*sigData = NULL;
353	unsigned	sigDataLen = 0;
354	feeCipherFile	cfile = NULL;
355	unsigned char	*pubKeyString = NULL;
356	unsigned	pubKeyStringLen;
357
358	if((sendPrivKey == NULL) || (recvPubKey == NULL)) {
359		return FR_BadPubKey;
360	}
361
362	/*
363	 * Get the public string version of sendPrivKey for embedding in
364	 * cipherfile
365	 */
366	frtn = feePubKeyCreateKeyString(sendPrivKey,
367		(char **)&pubKeyString,
368		&pubKeyStringLen);
369	if(frtn) {
370		goto out;
371	}
372
373	/*
374	 * Obtain DES key via key exchange and get a feeDES object with it
375	 */
376	frtn = feePubKeyCreatePad(sendPrivKey,
377		recvPubKey,
378		&desKey,
379		&desKeyLen);
380	if(frtn) {
381		goto out;
382	}
383	des = feeDESNewWithState(desKey, desKeyLen);
384	if(des == NULL) {
385		frtn = FR_Internal;
386		goto out;
387	}
388
389	/*
390	 * Encrypt the plaintext via DES
391	 */
392	frtn = feeDESEncrypt(des,
393		plainText,
394		plainTextLen,
395		&cipherText,
396		&cipherTextLen);
397	if(frtn) {
398		goto out;
399	}
400
401	if(genSig) {
402		/*
403		 * We generate signature on ciphertext by convention.
404		 */
405		frtn = feePubKeyCreateSignature(sendPrivKey,
406			cipherText,
407			cipherTextLen,
408			&sigData,
409			&sigDataLen);
410		if(frtn) {
411			goto out;
412		}
413	}
414
415	/*
416	 * Cons up a cipherfile
417	 */
418	cfile = feeCFileNewFromCipherText(CFE_PublicDES,
419		cipherText,
420		cipherTextLen,
421		pubKeyString,
422		pubKeyStringLen,
423		NULL,			// otherKey
424		0,
425		sigData,
426		sigDataLen,
427		userData);
428	if(cfile == NULL) {
429		frtn = FR_Internal;
430		goto out;
431	}
432
433out:
434	/* free alloc'd stuff */
435
436	if(cipherText) {
437		ffree(cipherText);
438	}
439	if(frand) {
440		feeRandFree(frand);
441	}
442	if(des) {
443		feeDESFree(des);
444	}
445	if(desKey) {
446		ffree(desKey);
447	}
448	if(sigData) {
449		ffree(sigData);
450	}
451	if(pubKeyString) {
452		ffree(pubKeyString);
453	}
454	*cipherFile = cfile;
455	return frtn;
456
457}
458
459feeReturn decryptPubDES(feeCipherFile cipherFile,
460	feePubKey recvPrivKey,
461	feePubKey sendPubKey,
462	unsigned char **plainText,			// RETURNED
463	unsigned *plainTextLen,				// RETURNED
464	feeSigStatus *sigStatus)			// RETURNED
465{
466	feeReturn 	frtn = FR_Success;
467	unsigned char	*cipherText = NULL;
468	unsigned	cipherTextLen;
469	feeDES		des = NULL;		// to decrypt cipherText
470	unsigned char	*desKey;
471	unsigned	desKeyLen;
472	unsigned char	*sigData = NULL;
473	unsigned	sigDataLen;
474	unsigned char	*pubKeyString = NULL;
475	unsigned	pubKeyStringLen;
476	feePubKey	decryptPubKey = NULL;	// from cipherfile
477
478	if(feeCFileEncrType(cipherFile) != CFE_PublicDES) {
479		frtn = FR_Internal;
480		goto out;
481	}
482
483	/*
484	 * Get ciphertext and sender's public key from cipherFile
485	 */
486	cipherText = feeCFileCipherText(cipherFile, &cipherTextLen);
487	if(cipherText == NULL) {
488		frtn = FR_BadCipherFile;
489		goto out;
490	}
491	pubKeyString = feeCFileSendPubKeyData(cipherFile, &pubKeyStringLen);
492	if(pubKeyString == NULL) {
493		frtn = FR_BadCipherFile;
494		goto out;
495	}
496	decryptPubKey = feePubKeyAlloc();
497	frtn = feePubKeyInitFromKeyString(decryptPubKey,
498		(char *)pubKeyString,
499		pubKeyStringLen);
500	if(frtn) {
501		goto out;
502	}
503
504	/*
505	 * key exchange to get DES key
506	 */
507	frtn = feePubKeyCreatePad(recvPrivKey,
508		decryptPubKey,
509		&desKey,
510		&desKeyLen);
511	if(frtn) {
512		goto out;
513	}
514
515	/*
516	 * Now DES decrypt the ciphertext
517	 */
518	if(desKeyLen < FEE_DES_MIN_STATE_SIZE) {
519		frtn = FR_BadCipherFile;
520		goto out;
521	}
522	des = feeDESNewWithState(desKey, desKeyLen);
523	if(des == NULL) {
524		frtn = FR_Internal;
525		goto out;
526	}
527	frtn = feeDESDecrypt(des,
528		cipherText,
529		cipherTextLen,
530		plainText,
531		plainTextLen);
532	if(frtn) {
533		goto out;
534	}
535
536	sigData = feeCFileSigData(cipherFile, &sigDataLen);
537	if(sigData) {
538		feeReturn sigFrtn;
539
540		if(sendPubKey == NULL) {
541			/*
542			 * Use key embedded in cipherfile
543			 */
544			sendPubKey = decryptPubKey;
545		}
546		sigFrtn = feePubKeyVerifySignature(sendPubKey,
547			cipherText,
548			cipherTextLen,
549			sigData,
550			sigDataLen);
551		switch(sigFrtn) {
552		    case FR_Success:
553		    	*sigStatus = SS_PresentValid;
554			break;
555		    default:
556		    	*sigStatus = SS_PresentInvalid;
557			break;
558		}
559	}
560	else {
561		*sigStatus = SS_NotPresent;
562	}
563out:
564	if(cipherText) {
565		ffree(cipherText);
566	}
567	if(des) {
568		feeDESFree(des);
569	}
570	if(desKey) {
571		ffree(desKey);
572	}
573	if(pubKeyString) {
574		ffree(pubKeyString);
575	}
576	if(sigData) {
577		ffree(sigData);
578	}
579	if(decryptPubKey) {
580		feePubKeyFree(decryptPubKey);
581	}
582	return frtn;
583}
584
585#endif	/* CRYPTKIT_CIPHERFILE_ENABLE */
586
587