]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/feeDES.c
Security-57740.51.3.tar.gz
[apple/security.git] / OSX / libsecurity_cryptkit / lib / feeDES.c
1 /* Copyright (c) 1998,2011,2014 Apple 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, 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 ***************************************************************************
10 *
11 * FeeDES.c - generic, portable DES encryption object
12 *
13 * Revision History
14 * ----------------
15 * 10/06/98 ap
16 * Changed to compile with C++.
17 * 05 Jan 98 at Apple
18 * Avoid a bcopy() on encrypt/decrypt of each block
19 * 31 Mar 97 at Apple
20 * New per-instance API for DES.c
21 * 26 Aug 96 at NeXT
22 * Created.
23 */
24
25 #include "ckconfig.h"
26
27 #if CRYPTKIT_SYMMETRIC_ENABLE
28
29 #include "feeDES.h"
30 #include "feeTypes.h"
31 #include "ckDES.h"
32 #include "falloc.h"
33 #include "feeDebug.h"
34 #include "feeFunctions.h"
35 #include "platform.h"
36 #include <stdlib.h>
37
38 #ifndef NULL
39 #define NULL ((void *)0)
40 #endif /* NULL */
41
42 typedef struct {
43 int blockMode; /* default = 0 */
44 unsigned char lastBlock[DES_BLOCK_SIZE_BYTES]; /* for CBC */
45 struct _desInst dinst;
46 } fdesInst;
47
48 static void feeDESInit(desInst dinst)
49 {
50 desinit(dinst, DES_MODE_STD); // detects redundant calls
51 }
52
53 /*
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
56 * MSB of each bytes.
57 */
58 feeDES feeDESNewWithState(const unsigned char *state,
59 unsigned stateLen)
60 {
61 fdesInst *fdinst;
62
63 if(stateLen < FEE_DES_MIN_STATE_SIZE) {
64 return NULL;
65 }
66 fdinst = (fdesInst*) fmalloc(sizeof(fdesInst));
67 bzero(fdinst, sizeof(fdesInst));
68 feeDESInit(&fdinst->dinst);
69 feeDESSetState((feeDES)fdinst, state, stateLen);
70 return fdinst;
71 }
72
73 void feeDESFree(feeDES des)
74 {
75 memset(des, 0, sizeof(fdesInst));
76 ffree(des);
77 }
78
79 /*
80 * Set new initial state.
81 */
82 feeReturn feeDESSetState(feeDES des,
83 const unsigned char *state,
84 unsigned stateLen)
85 {
86 fdesInst *fdinst = (fdesInst*) des;
87 char Key[DES_KEY_SIZE_BYTES_EXTERNAL];
88 // 'key' causes problems with
89 // some weird Unix header
90 unsigned byte;
91
92 if(stateLen < (DES_KEY_SIZE_BYTES_EXTERNAL)) {
93 return FR_IllegalArg;
94 }
95 bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES);
96 bcopy(state, Key, DES_KEY_SIZE_BYTES_EXTERNAL);
97
98 /*
99 * Set up parity bits
100 */
101 for(byte=0; byte<DES_KEY_SIZE_BYTES_EXTERNAL; byte++){
102 int i;
103 unsigned p;
104
105 p = 0;
106 for(i=0;i<7;i++) {
107 if(Key[byte] & (1 << i)) {
108 p++;
109 }
110 }
111 if((p & 1) == 0) {
112 Key[byte] |= 0x80;
113 }
114 else {
115 Key[byte] &= ~0x80;
116 }
117 }
118 dessetkey(&fdinst->dinst, Key);
119 return FR_Success;
120 }
121
122 void feeDESSetBlockMode(feeDES des)
123 {
124 fdesInst *fdinst = (fdesInst*) des;
125
126 fdinst->blockMode = 1;
127 }
128
129 void feeDESSetChainMode(feeDES des)
130 {
131 fdesInst *fdinst = (fdesInst*) des;
132
133 fdinst->blockMode = 0;
134 }
135
136 unsigned feeDESPlainBlockSize(feeDES des)
137 {
138 return DES_BLOCK_SIZE_BYTES;
139 }
140
141 unsigned feeDESCipherBlockSize(feeDES des)
142 {
143 return DES_BLOCK_SIZE_BYTES;
144 }
145
146 unsigned feeDESCipherBufSize(feeDES des)
147 {
148 /*
149 * Normally DES_BLOCK_SIZE, two blocks for finalBlock
150 */
151 return 2 * DES_BLOCK_SIZE_BYTES;
152 }
153
154 /*
155
156 * Return the size of ciphertext to hold specified size of plaintext.
157
158 */
159
160 unsigned feeDESCipherTextSize(feeDES des, unsigned plainTextSize)
161
162 {
163
164 unsigned blocks = (plainTextSize + DES_BLOCK_SIZE_BYTES - 1) /
165 DES_BLOCK_SIZE_BYTES;
166
167 if((plainTextSize % DES_BLOCK_SIZE_BYTES) == 0) {
168 /*
169 * One more block for resid count
170 */
171 blocks++;
172 }
173
174 return blocks * DES_BLOCK_SIZE_BYTES;
175
176 }
177
178
179 /*
180 * Key size in bits.
181 */
182 unsigned feeDESKeySize(feeDES des)
183 {
184 return DES_KEY_SIZE_BITS;
185 }
186
187 /*
188 * Encrypt a block or less of data. Caller malloc's cipherText.
189 */
190 feeReturn feeDESEncryptBlock(feeDES des,
191 const unsigned char *plainText,
192 unsigned plainTextLen,
193 unsigned char *cipherText,
194 unsigned *cipherTextLen, // RETURNED
195 int finalBlock)
196 {
197 fdesInst *fdinst = (fdesInst*) des;
198 feeReturn frtn = FR_Success;
199 unsigned cipherLen;
200
201 if(plainTextLen > DES_BLOCK_SIZE_BYTES) {
202 return FR_IllegalArg;
203 }
204 if(plainTextLen) {
205 /*
206 * We're called with plainTextLen = 0 and finalBlock
207 * recursively to clean up last block.
208 */
209 bcopy(plainText, cipherText, plainTextLen);
210 }
211 if(plainTextLen < DES_BLOCK_SIZE_BYTES) {
212 if(!finalBlock) {
213 /*
214 * odd-size block only legal last time thru
215 */
216 return FR_IllegalArg;
217 }
218
219 /*
220 * Last block, final byte = residual length.
221 */
222 cipherText[DES_BLOCK_SIZE_BYTES - 1] = plainTextLen;
223 }
224
225 if(!fdinst->blockMode) {
226 /*
227 * CBC mode; chain in last cipher word
228 */
229 unsigned char *cp = cipherText;
230 unsigned char *cp1 = fdinst->lastBlock;
231 int i;
232
233 for(i=0; i<DES_BLOCK_SIZE_BYTES; i++) {
234 *cp++ ^= *cp1++;
235 }
236 }
237 endes(&fdinst->dinst, (char *)cipherText); /* Encrypt block */
238 if(!fdinst->blockMode){
239 /*
240 * Save outgoing ciphertext for chain
241 */
242 bcopy(cipherText, fdinst->lastBlock, DES_BLOCK_SIZE_BYTES);
243 }
244 cipherLen = DES_BLOCK_SIZE_BYTES;
245
246 if(finalBlock) {
247 if(plainTextLen == DES_BLOCK_SIZE_BYTES) {
248 /*
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.
252 */
253 unsigned moreCipher; // additional cipherLen
254
255 frtn = feeDESEncryptBlock(des,
256 NULL, // plainText not used
257 0, // resid
258 cipherText + DES_BLOCK_SIZE_BYTES, // append...
259 &moreCipher,
260 1);
261 if(frtn == FR_Success) {
262 cipherLen += moreCipher;
263 }
264
265 }
266 if(plainTextLen != 0) {
267 /*
268 * Reset internal state in prep for next encrypt/decrypt.
269 * Note we avoid this in the recursive call (plainTextLen = 0).
270 */
271 bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES);
272 }
273 }
274
275 if(frtn == FR_Success) {
276 *cipherTextLen = cipherLen;
277 }
278 return frtn;
279 }
280
281 /*
282 * Decrypt a block of data. Caller malloc's plainText. Always
283 * generates DES_BLOCK_SIZE_BYTES bytes or less of plainText.
284 */
285 feeReturn feeDESDecryptBlock(feeDES des,
286 const unsigned char *cipherText,
287 unsigned cipherTextLen,
288 unsigned char *plainText,
289 unsigned *plainTextLen, // RETURNED
290 int finalBlock)
291 {
292 fdesInst *fdinst = (fdesInst*) des;
293 unsigned char work[DES_BLOCK_SIZE_BYTES];
294 unsigned char ivtmp[DES_BLOCK_SIZE_BYTES];
295
296 if(cipherTextLen != DES_BLOCK_SIZE_BYTES) {
297 /*
298 * We always generate ciphertext in multiples of block size.
299 */
300 return FR_IllegalArg;
301 }
302
303 bcopy(cipherText, work, DES_BLOCK_SIZE_BYTES);
304 if(!fdinst->blockMode && !finalBlock) {
305 /*
306 * Save incoming ciphertext for chain
307 */
308 bcopy(cipherText, ivtmp, DES_BLOCK_SIZE_BYTES);
309 }
310 dedes(&fdinst->dinst, (char *)work);
311 if(!fdinst->blockMode){
312 /*
313 * Unchain block using previous block's ciphertext;
314 * save current ciphertext for next
315 */
316 char *cp = (char *)work;
317 char *cp1 = (char*)fdinst->lastBlock;
318 int i;
319
320 for(i=0; i<DES_BLOCK_SIZE_BYTES; i++) {
321 *cp++ ^= *cp1++;
322 }
323 if(!finalBlock) {
324 bcopy(ivtmp, fdinst->lastBlock, DES_BLOCK_SIZE_BYTES);
325 }
326 }
327 if(finalBlock) {
328 /*
329 * deal with residual block; its size is in last byte of
330 * work[]
331 */
332 unsigned resid = work[DES_BLOCK_SIZE_BYTES-1];
333
334 if(resid > (DES_BLOCK_SIZE_BYTES-1)) {
335 return FR_BadCipherText;
336 }
337 if(resid > 0) {
338 bcopy(work, plainText, resid);
339 }
340 *plainTextLen = resid;
341
342 /*
343 * Reset internal state in prep for next encrypt/decrypt.
344 */
345 bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES);
346 }
347 else {
348 bcopy(work, plainText, DES_BLOCK_SIZE_BYTES);
349 *plainTextLen = DES_BLOCK_SIZE_BYTES;
350 }
351 return FR_Success;
352 }
353
354 /*
355 * Convenience routines to encrypt & decrypt multi-block data.
356 */
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
362 {
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
370 feeReturn frtn;
371 int finalBlock;
372 unsigned ctextMallocd;
373
374 if(plainTextLen == 0) {
375 dbgLog(("feeDESDecrypt: NULL plainText\n"));
376 return FR_IllegalArg;
377 }
378
379 ptext = plainText;
380 ptextLen = plainTextLen;
381 ctextMallocd = feeDESCipherTextSize(des, plainTextLen);
382 ctextResult = (unsigned char*) fmalloc(ctextMallocd);
383 ctextPtr = ctextResult;
384 ctextLenTotal = 0;
385
386 while(1) {
387 if(ptextLen <= DES_BLOCK_SIZE_BYTES) {
388 finalBlock = 1;
389 thisPtextLen = ptextLen;
390 }
391 else {
392 finalBlock = 0;
393 thisPtextLen = DES_BLOCK_SIZE_BYTES;
394 }
395 frtn = feeDESEncryptBlock(des,
396 ptext,
397 thisPtextLen,
398 ctextPtr,
399 &ctextLen,
400 finalBlock);
401 if(frtn) {
402 dbgLog(("feeDESEncrypt: encrypt error: %s\n",
403 feeReturnString(frtn)));
404 break;
405 }
406 if(ctextLen == 0) {
407 dbgLog(("feeDESEncrypt: null ciphertext\n"));
408 frtn = FR_Internal;
409 break;
410 }
411 ctextLenTotal += ctextLen;
412 if(ctextLenTotal > (plainTextLen + DES_BLOCK_SIZE_BYTES)) {
413 dbgLog(("feeDESEncrypt: ciphertext overflow\n"));
414 frtn = FR_Internal;
415 break;
416 }
417 if(finalBlock) {
418 break;
419 }
420 ctextPtr += ctextLen;
421 ptext += thisPtextLen;
422 ptextLen -= thisPtextLen;
423 }
424 if(frtn) {
425 ffree(ctextResult);
426 *cipherText = NULL;
427 *cipherTextLen = 0;
428 }
429 else {
430 #if FEE_DEBUG
431 if(ctextLenTotal != ctextMallocd) {
432 dbgLog(("feeDESEncrypt: ctextLen error\n"));
433 }
434 #endif /* FEE_DEBUG */
435 *cipherText = ctextResult;
436 *cipherTextLen = ctextLenTotal;
437 }
438 return frtn;
439
440 }
441
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
447 {
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;
455 int finalBlock;
456
457 if(cipherTextLen % DES_BLOCK_SIZE_BYTES) {
458 dbgLog(("feeDESDecrypt: unaligned cipherText\n"));
459 return FR_BadCipherText;
460 }
461 if(cipherTextLen == 0) {
462 dbgLog(("feeDESDecrypt: NULL cipherText\n"));
463 return FR_BadCipherText;
464 }
465
466 ctext = cipherText;
467 ctextLen = cipherTextLen;
468
469 /*
470 * Plaintext length always <= cipherTextLen
471 */
472 ptextResult = (unsigned char*) fmalloc(cipherTextLen);
473 ptextPtr = ptextResult;
474 ptextLenTotal = 0;
475
476 while(ctextLen) {
477 if(ctextLen == DES_BLOCK_SIZE_BYTES) {
478 finalBlock = 1;
479 }
480 else {
481 finalBlock = 0;
482 }
483 frtn = feeDESDecryptBlock(des,
484 ctext,
485 DES_BLOCK_SIZE_BYTES,
486 ptextPtr,
487 &ptextLen,
488 finalBlock);
489 if(frtn) {
490 dbgLog(("feeDESDecrypt decrypt: %s\n",
491 feeReturnString(frtn)));
492 break;
493 }
494 if(ptextLen == 0) {
495 /*
496 * Normal termination case for
497 * plainTextLen % DES_BLOCK_SIZE_BYTES == 0
498 */
499 if(!finalBlock) {
500 dbgLog(("feeDESDecrypt: decrypt sync"
501 " error!\n"));
502 frtn = FR_BadCipherText;
503 break;
504 }
505 else {
506 break;
507 }
508 }
509 else {
510 ptextPtr += ptextLen;
511 ptextLenTotal += ptextLen;
512 }
513 ctext += DES_BLOCK_SIZE_BYTES;
514 ctextLen -= DES_BLOCK_SIZE_BYTES;
515 }
516
517 if(frtn) {
518 ffree(ptextResult);
519 *plainText = NULL;
520 *plainTextLen = 0;
521 }
522 else {
523 *plainText = ptextResult;
524 *plainTextLen = ptextLenTotal;
525 }
526 return frtn;
527 }
528
529 #endif /* CRYPTKIT_SYMMETRIC_ENABLE */