2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 * BlockCryptor.cpp - common context for block-oriented encryption algorithms
24 #include "BlockCryptor.h"
25 #include "BinaryKey.h"
26 #include "AppleCSPSession.h"
27 #include <security_utilities/alloc.h>
28 #include <Security/cssmerr.h>
30 #include <security_utilities/debugging.h>
31 #include <security_cdsa_utilities/cssmdata.h>
33 #define BlockCryptDebug(args...) secinfo("blockCrypt", ## args)
34 #define bprintf(args...) secinfo("blockCryptBuf", ## args)
35 #define ioprintf(args...) secinfo("blockCryptIo", ## args)
37 BlockCryptor::~BlockCryptor()
40 memset(mInBuf
, 0, mInBlockSize
);
41 session().free(mInBuf
);
45 memset(mChainBuf
, 0, mInBlockSize
);
46 session().free(mChainBuf
);
53 * Reusable setup functions called from subclass's init.
54 * This is the general purpose one....
56 void BlockCryptor::setup(
57 size_t blockSizeIn
, // block size of input
58 size_t blockSizeOut
, // block size of output
59 bool pkcsPad
, // this class performs PKCS{5,7} padding
60 bool needsFinal
, // needs final update with valid data
61 BC_Mode mode
, // ECB, CBC
62 const CssmData
*iv
) // init vector, required for CBC
63 //Ê must be at least blockSizeIn bytes
65 if(pkcsPad
&& needsFinal
) {
66 BlockCryptDebug("BlockCryptor::setup pkcsPad && needsFinal");
67 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
69 mPkcsPadding
= pkcsPad
;
71 mNeedFinalData
= needsFinal
;
73 /* set up inBuf, all configurations */
75 /* only reuse if same size */
76 if(mInBlockSize
!= blockSizeIn
) {
77 session().free(mInBuf
);
82 mInBuf
= (uint8
*)session().malloc(blockSizeIn
);
85 /* set up chain buf, decrypt/CBC only; skip if algorithm does its own chaining */
86 if((mMode
== BCM_CBC
) && !encoding() && !mCbcCapable
) {
87 if(mChainBuf
!= NULL
) {
88 /* only reuse if same size */
89 if(mInBlockSize
!= blockSizeIn
) {
90 session().free(mChainBuf
);
94 if(mChainBuf
== NULL
) {
95 mChainBuf
= (uint8
*)session().malloc(blockSizeIn
);
99 /* IV iff CBC mode, and ensure IV is big enough */
103 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_INIT_VECTOR
);
108 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR
);
110 if(blockSizeIn
!= blockSizeOut
) {
111 /* no can do, must be same block sizes */
112 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE
);
114 if(iv
->Length
< blockSizeIn
) {
116 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_INIT_VECTOR
);
118 /* save IV as appropriate */
121 memmove(mInBuf
, iv
->Data
, blockSizeIn
);
124 assert(mChainBuf
!= NULL
);
125 memmove(mChainBuf
, iv
->Data
, blockSizeIn
);
131 mInBlockSize
= blockSizeIn
;
133 mOutBlockSize
= blockSizeOut
;
138 * This one is used by simple, well-behaved algorithms which don't do their own
139 * padding and which rely on us to do everything but one-block-at-a-time
140 * encrypt and decrypt.
142 void BlockCryptor::setup(
143 size_t blockSize
, // block size of input and output
144 const Context
&context
)
146 bool padEnable
= false;
147 bool chainEnable
= false;
148 bool ivEnable
= false;
153 * IV optional per mode
154 * pad optional per mode
155 * Currently we ignore extraneous attributes (e.g., it's OK to pass in
156 * an IV if the mode doesn't specify it), mainly for simplifying test routines.
158 CSSM_ENCRYPT_MODE cssmMode
= context
.getInt(CSSM_ATTRIBUTE_MODE
);
161 /* no mode attr --> 0 == CSSM_ALGMODE_NONE, not currently supported */
162 case CSSM_ALGMODE_CBCPadIV8
:
168 case CSSM_ALGMODE_CBC_IV8
:
173 case CSSM_ALGMODE_ECB
:
176 case CSSM_ALGMODE_ECBPad
:
181 errorLog1("DESContext::init: illegal mode (%d)\n", (int)cssmMode
);
182 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE
);
186 /* validate padding type */
187 uint32 padding
= context
.getInt(CSSM_ATTRIBUTE_PADDING
); // 0 ==> PADDING_NONE
190 /* backwards compatibility - used to be PKCS1, should be PKCS5 or 7 */
191 case CSSM_PADDING_PKCS7
:
192 case CSSM_PADDING_PKCS5
:
193 case CSSM_PADDING_PKCS1
: //Êthis goes away soon
197 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING
);
202 case CSSM_PADDING_PKCS5
: // this goes away soon
203 case CSSM_PADDING_PKCS7
:
207 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING
);
212 /* make sure there's an IV in the context of sufficient length */
213 iv
= context
.get
<CssmData
>(CSSM_ATTRIBUTE_INIT_VECTOR
);
215 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR
);
217 if(iv
->Length
< blockSize
) {
218 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_INIT_VECTOR
);
225 chainEnable
? BCM_CBC
: BCM_ECB
,
230 * Update always leaves some data in mInBuf if:
231 * mNeedsFinalData is true, or
232 * decrypting and mPkcsPadding true.
233 * Also, we always process all of the input (except on error).
235 void BlockCryptor::update(
237 size_t &inSize
, // in/out
239 size_t &outSize
) // in/out
241 uint8
*uInp
= (UInt8
*)inp
;
242 uint8
*uOutp
= (UInt8
*)outp
;
243 size_t uInSize
= inSize
; // input bytes to go
244 size_t uOutSize
= 0; // ouput bytes generated
245 size_t uOutLeft
= outSize
; // bytes remaining in outp
249 bool needLeftOver
= mNeedFinalData
|| (!encoding() && mPkcsPadding
);
250 bool doCbc
= (mMode
== BCM_CBC
) && !mCbcCapable
;
252 assert(mInBuf
!= NULL
);
256 /* attempt to fill mInBuf from inp */
257 toMove
= mInBlockSize
- mInBufSize
;
258 if(toMove
> uInSize
) {
261 if(encoding() && doCbc
) {
262 /* xor into last cipherblock or IV */
263 for(i
=0; i
<toMove
; i
++) {
264 mInBuf
[mInBufSize
+ i
] ^= *uInp
++;
268 /* use incoming data as is */
269 memmove(mInBuf
+mInBufSize
, uInp
, toMove
);
273 mInBufSize
+= toMove
;
275 * Process inBuf if it's full, but skip if no more data in uInp and
276 * inBuf might be needed (by us for unpadding on decrypt, or by
277 * subclass for anything) for a final call
279 if((mInBufSize
== mInBlockSize
) && !((uInSize
== 0) && needLeftOver
)) {
282 encryptBlock(mInBuf
, mInBlockSize
, uOutp
, actMoved
, false);
284 /* save ciphertext for chaining next block */
285 assert(mInBlockSize
== actMoved
);
286 memmove(mInBuf
, uOutp
, mInBlockSize
);
290 decryptBlock(mInBuf
, mInBlockSize
, uOutp
, actMoved
, false);
292 /* xor in last ciphertext */
293 assert(mInBlockSize
== actMoved
);
294 for(i
=0; i
<mInBlockSize
; i
++) {
295 uOutp
[i
] ^= mChainBuf
[i
];
297 /* save this ciphertext for next chain */
298 memmove(mChainBuf
, mInBuf
, mInBlockSize
);
301 uOutSize
+= actMoved
;
303 uOutLeft
-= actMoved
;
305 assert(uOutSize
<= outSize
);
307 } /* processing mInBuf */
311 ioprintf("=== BlockCryptor::update encrypt %d inSize 0x%lx outSize 0x%lx",
312 encoding() ? 1 : 0, inSize
, outSize
);
318 * en/decrypt even blocks in (remaining) inp.
320 size_t leftOver
= (mInBlockSize
> 0) ? uInSize
% mInBlockSize
: 0;
321 if((leftOver
== 0) && needLeftOver
) {
323 * Even blocks coming in, but we really need to leave some data
324 * in the buffer (because the subclass asked for it, or we're decrypting
325 * with PKCS padding). Save one block for mInBuf.
327 leftOver
= mInBlockSize
;
329 toMove
= uInSize
- leftOver
;
330 size_t blocks
= (mInBlockSize
> 0) ? toMove
/ mInBlockSize
: 0;
331 if(mMultiBlockCapable
&& !doCbc
&& (blocks
!= 0)) {
333 * Optimization for algorithms that are multi-block capable and that
334 * can do their own CBC (if necessary).
336 size_t thisMove
= blocks
* mInBlockSize
;
339 encryptBlock(uInp
, thisMove
, uOutp
, actMoved
, false);
342 decryptBlock(uInp
, thisMove
, uOutp
, actMoved
, false);
344 uOutSize
+= actMoved
;
347 uOutLeft
-= actMoved
;
349 assert(uOutSize
<= outSize
);
351 else if(encoding()) {
355 /* encrypt directly from input to output */
356 encryptBlock(uInp
, mInBlockSize
, uOutp
, actMoved
, false);
359 /* xor into last ciphertext, encrypt the result */
360 for(i
=0; i
<mInBlockSize
; i
++) {
361 mInBuf
[i
] ^= uInp
[i
];
363 encryptBlock(mInBuf
, mInBlockSize
, uOutp
, actMoved
, false);
365 /* save new ciphertext for next chain */
366 assert(actMoved
== mInBlockSize
);
367 memmove(mInBuf
, uOutp
, mInBlockSize
);
369 uOutSize
+= actMoved
;
371 uInp
+= mInBlockSize
;
372 uOutLeft
-= actMoved
;
373 toMove
-= mInBlockSize
;
374 assert(uOutSize
<= outSize
);
375 } /* main encrypt loop */
383 /* save this ciphertext for chain; don't assume in != out */
384 memmove(mInBuf
, uInp
, mInBlockSize
);
385 decryptBlock(uInp
, mInBlockSize
, uOutp
, actMoved
, false);
387 /* chain in previous ciphertext */
388 assert(mInBlockSize
== actMoved
);
389 for(i
=0; i
<mInBlockSize
; i
++) {
390 uOutp
[i
] ^= mChainBuf
[i
];
393 /* save current ciphertext for next block */
394 memmove(mChainBuf
, mInBuf
, mInBlockSize
);
398 decryptBlock(uInp
, mInBlockSize
, uOutp
, actMoved
, false);
400 uOutSize
+= actMoved
;
402 uInp
+= mInBlockSize
;
403 uOutLeft
-= actMoved
;
404 toMove
-= mInBlockSize
;
405 assert(uOutSize
<= outSize
);
406 } /* main decrypt loop */
410 /* leftover bytes from inp --> mInBuf */
412 if(encoding() && doCbc
) {
413 /* xor into last cipherblock or IV */
414 for(i
=0; i
<leftOver
; i
++) {
415 mInBuf
[i
] ^= *uInp
++;
419 if(mInBuf
&& uInp
&& leftOver
) memmove(mInBuf
, uInp
, leftOver
);
423 mInBufSize
= leftOver
;
425 ioprintf("=== BlockCryptor::update encrypt %d inSize 0x%lx outSize 0x%lx",
426 encoding() ? 1 : 0, inSize
, outSize
);
429 void BlockCryptor::final(
432 size_t uOutSize
= 0; // ouput bytes generated
434 size_t uOutLeft
= out
.Length
; // bytes remaining in out
436 bool doCbc
= (mMode
== BCM_CBC
) && !mCbcCapable
;
438 assert(mInBuf
!= NULL
);
440 if((mInBufSize
== 0) && mNeedFinalData
) {
441 /* only way this could happen: no update() called (at least not with
442 * non-zero input data sizes) */
443 BlockCryptDebug("BlockCryptor::final with no mInBuf data");
444 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR
);
447 uint8
*ctext
= out
.Data
;
451 * PKCS5/7 padding: pad byte = size of padding.
452 * This assertion courtesy of the limitation on the mutual
453 * exclusivity of mPkcsPadding and mNeedFinalData.
455 assert(mInBufSize
< mInBlockSize
);
456 size_t padSize
= mInBlockSize
- mInBufSize
;
457 uint8
*padPtr
= mInBuf
+ mInBufSize
;
459 for(i
=0; i
<padSize
; i
++) {
464 for(i
=0; i
<padSize
; i
++) {
465 *padPtr
++ ^= padSize
;
468 mInBufSize
= mInBlockSize
;
472 * Encrypt final mInBuf. If it's not full, the BlockCryptObject better know
477 encryptBlock(mInBuf
, mInBufSize
, ctext
, actMoved
, true);
478 uOutSize
+= actMoved
;
480 assert(uOutSize
<= out
.length());
482 out
.length(uOutSize
);
486 if(mInBufSize
== 0) {
488 BlockCryptDebug("BlockCryptor::final decrypt/pad with no mInBuf data");
489 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR
);
492 /* simple decrypt op complete */
493 ioprintf("=== BlockCryptor::final encrypt 0 outSize 0");
500 * Decrypt - must have exactly one block of ciphertext.
501 * We trust CSPContext, and our own outputSize(), to have set up
502 * the current output buffer with enough space to handle the
503 * full size of the decrypt, even though - due to padding - we
504 * might actually pass less than that amount back to caller.
506 if(mInBufSize
!= mInBlockSize
) {
507 BlockCryptDebug("BlockCryptor::final unaligned ciphertext");
508 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR
);
511 uint8
*ptext
= out
.Data
;
513 decryptBlock(mInBuf
, mInBlockSize
, ptext
, actMoved
, true);
515 /* chain in previous ciphertext one more time */
516 assert(mInBlockSize
== actMoved
);
517 for(i
=0; i
<mInBlockSize
; i
++) {
518 ptext
[i
] ^= mChainBuf
[i
];
522 assert(actMoved
== mOutBlockSize
);
524 /* ensure integrity of padding byte(s) */
525 unsigned padSize
= ptext
[mOutBlockSize
- 1];
526 if(padSize
> mOutBlockSize
) {
527 BlockCryptDebug("BlockCryptor::final malformed ciphertext (1)");
528 CssmError::throwMe(CSSM_ERRCODE_INVALID_DATA
);
530 uint8
*padPtr
= ptext
+ mOutBlockSize
- padSize
;
531 for(unsigned i
=0; i
<padSize
; i
++) {
532 if(*padPtr
++ != padSize
) {
533 BlockCryptDebug("BlockCryptor::final malformed ciphertext "
535 CssmError::throwMe(CSSM_ERRCODE_INVALID_DATA
);
540 assert(actMoved
<= out
.length());
541 out
.length(actMoved
);
543 ioprintf("=== BlockCryptor::final encrypt %d outSize 0x%lx",
544 encoding() ? 1 : 0, out
.Length
);
548 * These three are only valid for algorithms for which encrypting one block
549 * of plaintext always yields exactly one block of ciphertext, and vice versa
550 * for decrypt. The block sizes for plaintext and ciphertext do NOT have to be
551 * the same. Subclasses (e.g. FEED) which do not meet this criterion will have
555 void BlockCryptor::minimumProgress(
559 /* each size = one block (including buffered input) */
560 inSize
= mInBlockSize
- mInBufSize
;
562 /* i.e., we're holding a whole buffer */
565 outSize
= mOutBlockSize
;
566 bprintf("--- BlockCryptor::minProgres inSize 0x%lx outSize 0x%lx mInBufSize 0x%lx",
567 inSize
, outSize
, mInBufSize
);
570 size_t BlockCryptor::inputSize(
571 size_t outSize
) // input for given output size
575 if(outSize
< mOutBlockSize
) {
577 * Sometimes CSPFullPluginSession calls us like this....in this
578 * case the legal inSize is just the remainder of the input buffer,
579 * less one byte (in other words, the max we we gobble up without
580 * producing any output).
582 inSize
= mInBlockSize
- mInBufSize
;
584 /* we have a full input buffer! How can this happen!? */
585 BlockCryptDebug("BlockCryptor::inputSize: HELP! zero inSize and outSize!\n");
589 /* more-or-less normal case */
590 size_t wholeBlocks
= outSize
/ mOutBlockSize
;
591 assert(wholeBlocks
>= 1);
592 inSize
= (wholeBlocks
* mInBlockSize
) - mInBufSize
;
594 /* i.e., we're holding a whole buffer */
598 bprintf("--- BlockCryptor::inputSize inSize 0x%lx outSize 0x%lx mInBufSize 0x%lx",
599 inSize
, outSize
, mInBufSize
);
603 size_t BlockCryptor::outputSize(
605 size_t inSize
/*= 0*/) // output for given input size
607 size_t rawBytes
= inSize
+ mInBufSize
;
608 // huh?Êdon't round this up!
609 //size_t rawBlocks = (rawBytes + mInBlockSize - 1) / mInBlockSize;
610 size_t rawBlocks
= rawBytes
/ mInBlockSize
;
613 * encrypting: always get one additional block on final() if we're padding
614 * or (we presume) the subclass is padding. Note that we
615 * truncated when calculating rawBlocks; to finish out on the
616 * final block, we (or our subclass) will either have to pad
617 * out the current partial block, or cook up a full pad block if
618 * mInBufSize is currently zero. Subclasses which pad some other
619 * way need to override this method.
621 * decrypting: outsize always <= insize
623 if(encoding() && final
&& (mPkcsPadding
|| mNeedFinalData
)) {
627 /* FIXME - optimize for needFinalData? (can squeak by with smaller outSize) */
628 size_t rtn
= rawBlocks
* mOutBlockSize
;
629 bprintf("--- BlockCryptor::outputSize inSize 0x%lx outSize 0x%lx final %d "
630 "inBufSize 0x%lx", inSize
, rtn
, final
, mInBufSize
);