1 /* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved.
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, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
7 * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
8 * EXPOSE YOU TO LIABILITY.
9 ***************************************************************************
11 * FeeDES.c - generic, portable DES encryption object
16 * Changed to compile with C++.
18 * Avoid a bcopy() on encrypt/decrypt of each block
20 * New per-instance API for DES.c
27 #if CRYPTKIT_SYMMETRIC_ENABLE
34 #include "feeFunctions.h"
39 #define NULL ((void *)0)
43 int blockMode
; /* default = 0 */
44 unsigned char lastBlock
[DES_BLOCK_SIZE_BYTES
]; /* for CBC */
45 struct _desInst dinst
;
48 static void feeDESInit(desInst dinst
)
50 desinit(dinst
, DES_MODE_STD
); // detects redundant calls
54 * Alloc and init a feeDES object with specified initial state.
55 * State must be at least 8 bytes; only 8 bytes are used, ignoring
58 feeDES
feeDESNewWithState(const unsigned char *state
,
63 if(stateLen
< FEE_DES_MIN_STATE_SIZE
) {
66 fdinst
= (fdesInst
*) fmalloc(sizeof(fdesInst
));
67 bzero(fdinst
, sizeof(fdesInst
));
68 feeDESInit(&fdinst
->dinst
);
69 feeDESSetState((feeDES
)fdinst
, state
, stateLen
);
73 void feeDESFree(feeDES des
)
75 memset(des
, 0, sizeof(fdesInst
));
80 * Set new initial state.
82 feeReturn
feeDESSetState(feeDES des
,
83 const unsigned char *state
,
86 fdesInst
*fdinst
= (fdesInst
*) des
;
87 char Key
[DES_KEY_SIZE_BYTES_EXTERNAL
];
88 // 'key' causes problems with
89 // some weird Unix header
92 if(stateLen
< (DES_KEY_SIZE_BYTES_EXTERNAL
)) {
95 bzero(fdinst
->lastBlock
, DES_BLOCK_SIZE_BYTES
);
96 bcopy(state
, Key
, DES_KEY_SIZE_BYTES_EXTERNAL
);
101 for(byte
=0; byte
<DES_KEY_SIZE_BYTES_EXTERNAL
; byte
++){
107 if(Key
[byte
] & (1 << i
)) {
118 dessetkey(&fdinst
->dinst
, Key
);
122 void feeDESSetBlockMode(feeDES des
)
124 fdesInst
*fdinst
= (fdesInst
*) des
;
126 fdinst
->blockMode
= 1;
129 void feeDESSetChainMode(feeDES des
)
131 fdesInst
*fdinst
= (fdesInst
*) des
;
133 fdinst
->blockMode
= 0;
136 unsigned feeDESPlainBlockSize(feeDES des
)
138 return DES_BLOCK_SIZE_BYTES
;
141 unsigned feeDESCipherBlockSize(feeDES des
)
143 return DES_BLOCK_SIZE_BYTES
;
146 unsigned feeDESCipherBufSize(feeDES des
)
149 * Normally DES_BLOCK_SIZE, two blocks for finalBlock
151 return 2 * DES_BLOCK_SIZE_BYTES
;
156 * Return the size of ciphertext to hold specified size of plaintext.
160 unsigned feeDESCipherTextSize(feeDES des
, unsigned plainTextSize
)
164 unsigned blocks
= (plainTextSize
+ DES_BLOCK_SIZE_BYTES
- 1) /
165 DES_BLOCK_SIZE_BYTES
;
167 if((plainTextSize
% DES_BLOCK_SIZE_BYTES
) == 0) {
169 * One more block for resid count
174 return blocks
* DES_BLOCK_SIZE_BYTES
;
182 unsigned feeDESKeySize(feeDES des
)
184 return DES_KEY_SIZE_BITS
;
188 * Encrypt a block or less of data. Caller malloc's cipherText.
190 feeReturn
feeDESEncryptBlock(feeDES des
,
191 const unsigned char *plainText
,
192 unsigned plainTextLen
,
193 unsigned char *cipherText
,
194 unsigned *cipherTextLen
, // RETURNED
197 fdesInst
*fdinst
= (fdesInst
*) des
;
198 feeReturn frtn
= FR_Success
;
201 if(plainTextLen
> DES_BLOCK_SIZE_BYTES
) {
202 return FR_IllegalArg
;
206 * We're called with plainTextLen = 0 and finalBlock
207 * recursively to clean up last block.
209 bcopy(plainText
, cipherText
, plainTextLen
);
211 if(plainTextLen
< DES_BLOCK_SIZE_BYTES
) {
214 * odd-size block only legal last time thru
216 return FR_IllegalArg
;
220 * Last block, final byte = residual length.
222 cipherText
[DES_BLOCK_SIZE_BYTES
- 1] = plainTextLen
;
225 if(!fdinst
->blockMode
) {
227 * CBC mode; chain in last cipher word
229 unsigned char *cp
= cipherText
;
230 unsigned char *cp1
= fdinst
->lastBlock
;
233 for(i
=0; i
<DES_BLOCK_SIZE_BYTES
; i
++) {
237 endes(&fdinst
->dinst
, (char *)cipherText
); /* Encrypt block */
238 if(!fdinst
->blockMode
){
240 * Save outgoing ciphertext for chain
242 bcopy(cipherText
, fdinst
->lastBlock
, DES_BLOCK_SIZE_BYTES
);
244 cipherLen
= DES_BLOCK_SIZE_BYTES
;
247 if(plainTextLen
== DES_BLOCK_SIZE_BYTES
) {
249 * Special case: finalBlock true, plainTextLen == blockSize.
250 * In this case we generate one more block of ciphertext,
251 * with a resid length of zero.
253 unsigned moreCipher
; // additional cipherLen
255 frtn
= feeDESEncryptBlock(des
,
256 NULL
, // plainText not used
258 cipherText
+ DES_BLOCK_SIZE_BYTES
, // append...
261 if(frtn
== FR_Success
) {
262 cipherLen
+= moreCipher
;
266 if(plainTextLen
!= 0) {
268 * Reset internal state in prep for next encrypt/decrypt.
269 * Note we avoid this in the recursive call (plainTextLen = 0).
271 bzero(fdinst
->lastBlock
, DES_BLOCK_SIZE_BYTES
);
275 if(frtn
== FR_Success
) {
276 *cipherTextLen
= cipherLen
;
282 * Decrypt a block of data. Caller malloc's plainText. Always
283 * generates DES_BLOCK_SIZE_BYTES bytes or less of plainText.
285 feeReturn
feeDESDecryptBlock(feeDES des
,
286 const unsigned char *cipherText
,
287 unsigned cipherTextLen
,
288 unsigned char *plainText
,
289 unsigned *plainTextLen
, // RETURNED
292 fdesInst
*fdinst
= (fdesInst
*) des
;
293 unsigned char work
[DES_BLOCK_SIZE_BYTES
];
294 unsigned char ivtmp
[DES_BLOCK_SIZE_BYTES
];
296 if(cipherTextLen
!= DES_BLOCK_SIZE_BYTES
) {
298 * We always generate ciphertext in multiples of block size.
300 return FR_IllegalArg
;
303 bcopy(cipherText
, work
, DES_BLOCK_SIZE_BYTES
);
304 if(!fdinst
->blockMode
&& !finalBlock
) {
306 * Save incoming ciphertext for chain
308 bcopy(cipherText
, ivtmp
, DES_BLOCK_SIZE_BYTES
);
310 dedes(&fdinst
->dinst
, (char *)work
);
311 if(!fdinst
->blockMode
){
313 * Unchain block using previous block's ciphertext;
314 * save current ciphertext for next
316 char *cp
= (char *)work
;
317 char *cp1
= (char*)fdinst
->lastBlock
;
320 for(i
=0; i
<DES_BLOCK_SIZE_BYTES
; i
++) {
324 bcopy(ivtmp
, fdinst
->lastBlock
, DES_BLOCK_SIZE_BYTES
);
329 * deal with residual block; its size is in last byte of
332 unsigned resid
= work
[DES_BLOCK_SIZE_BYTES
-1];
334 if(resid
> (DES_BLOCK_SIZE_BYTES
-1)) {
335 return FR_BadCipherText
;
338 bcopy(work
, plainText
, resid
);
340 *plainTextLen
= resid
;
343 * Reset internal state in prep for next encrypt/decrypt.
345 bzero(fdinst
->lastBlock
, DES_BLOCK_SIZE_BYTES
);
348 bcopy(work
, plainText
, DES_BLOCK_SIZE_BYTES
);
349 *plainTextLen
= DES_BLOCK_SIZE_BYTES
;
355 * Convenience routines to encrypt & decrypt multi-block data.
357 feeReturn
feeDESEncrypt(feeDES des
,
358 const unsigned char *plainText
,
359 unsigned plainTextLen
,
360 unsigned char **cipherText
, // malloc'd and RETURNED
361 unsigned *cipherTextLen
) // RETURNED
363 const unsigned char *ptext
; // per block
364 unsigned ptextLen
; // total to go
365 unsigned thisPtextLen
; // per block
366 unsigned ctextLen
; // per block
367 unsigned char *ctextResult
; // to return
368 unsigned char *ctextPtr
;
369 unsigned ctextLenTotal
; // running total
372 unsigned ctextMallocd
;
374 if(plainTextLen
== 0) {
375 dbgLog(("feeDESDecrypt: NULL plainText\n"));
376 return FR_IllegalArg
;
380 ptextLen
= plainTextLen
;
381 ctextMallocd
= feeDESCipherTextSize(des
, plainTextLen
);
382 ctextResult
= (unsigned char*) fmalloc(ctextMallocd
);
383 ctextPtr
= ctextResult
;
387 if(ptextLen
<= DES_BLOCK_SIZE_BYTES
) {
389 thisPtextLen
= ptextLen
;
393 thisPtextLen
= DES_BLOCK_SIZE_BYTES
;
395 frtn
= feeDESEncryptBlock(des
,
402 dbgLog(("feeDESEncrypt: encrypt error: %s\n",
403 feeReturnString(frtn
)));
407 dbgLog(("feeDESEncrypt: null ciphertext\n"));
411 ctextLenTotal
+= ctextLen
;
412 if(ctextLenTotal
> (plainTextLen
+ DES_BLOCK_SIZE_BYTES
)) {
413 dbgLog(("feeDESEncrypt: ciphertext overflow\n"));
420 ctextPtr
+= ctextLen
;
421 ptext
+= thisPtextLen
;
422 ptextLen
-= thisPtextLen
;
431 if(ctextLenTotal
!= ctextMallocd
) {
432 dbgLog(("feeDESEncrypt: ctextLen error\n"));
434 #endif /* FEE_DEBUG */
435 *cipherText
= ctextResult
;
436 *cipherTextLen
= ctextLenTotal
;
442 feeReturn
feeDESDecrypt(feeDES des
,
443 const unsigned char *cipherText
,
444 unsigned cipherTextLen
,
445 unsigned char **plainText
, // malloc'd and RETURNED
446 unsigned *plainTextLen
) // RETURNED
448 const unsigned char *ctext
;
449 unsigned ctextLen
; // total to go
450 unsigned ptextLen
; // per block
451 unsigned char *ptextResult
; // to return
452 unsigned char *ptextPtr
;
453 unsigned ptextLenTotal
; // running total
454 feeReturn frtn
= FR_Success
;
457 if(cipherTextLen
% DES_BLOCK_SIZE_BYTES
) {
458 dbgLog(("feeDESDecrypt: unaligned cipherText\n"));
459 return FR_BadCipherText
;
461 if(cipherTextLen
== 0) {
462 dbgLog(("feeDESDecrypt: NULL cipherText\n"));
463 return FR_BadCipherText
;
467 ctextLen
= cipherTextLen
;
470 * Plaintext length always <= cipherTextLen
472 ptextResult
= (unsigned char*) fmalloc(cipherTextLen
);
473 ptextPtr
= ptextResult
;
477 if(ctextLen
== DES_BLOCK_SIZE_BYTES
) {
483 frtn
= feeDESDecryptBlock(des
,
485 DES_BLOCK_SIZE_BYTES
,
490 dbgLog(("feeDESDecrypt decrypt: %s\n",
491 feeReturnString(frtn
)));
496 * Normal termination case for
497 * plainTextLen % DES_BLOCK_SIZE_BYTES == 0
500 dbgLog(("feeDESDecrypt: decrypt sync"
502 frtn
= FR_BadCipherText
;
510 ptextPtr
+= ptextLen
;
511 ptextLenTotal
+= ptextLen
;
513 ctext
+= DES_BLOCK_SIZE_BYTES
;
514 ctextLen
-= DES_BLOCK_SIZE_BYTES
;
523 *plainText
= ptextResult
;
524 *plainTextLen
= ptextLenTotal
;
529 #endif /* CRYPTKIT_SYMMETRIC_ENABLE */