2 * ascContext.cpp - glue between BlockCrytpor and ComCryption (a.k.a. Apple
4 * Written by Doug Mitchell 4/4/2001
9 #include "ascContext.h"
10 #include "ascFactory.h"
11 #include <Security/debugging.h>
12 #include <Security/logging.h>
13 #include <Security/debugging.h>
15 #define abprintf(args...) debug("ascBuf", ## args) /* buffer sizes */
16 #define aioprintf(args...) debug("ascIo", ## args) /* all I/O */
18 static CssmAllocator
*ascAllocator
;
21 * Comcryption-style memory allocator callbacks
23 static void *ccMalloc(unsigned size
)
25 return ascAllocator
->malloc(size
);
27 static void ccFree(void *data
)
29 ascAllocator
->free(data
);
32 /* Given a ComCryption error, throw appropriate CssmError */
33 static void throwComcrypt(
35 const char *op
) /* optional */
37 CSSM_RETURN cerr
= CSSM_OK
;
38 const char *errStr
= "Bad Error String";
42 errStr
= "CCR_SUCCESS";
44 case CCR_OUTBUFFER_TOO_SMALL
:
45 errStr
= "CCR_OUTBUFFER_TOO_SMALL";
46 cerr
= CSSMERR_CSP_OUTPUT_LENGTH_ERROR
;
48 case CCR_MEMORY_ERROR
:
49 errStr
= "CCR_MEMORY_ERROR";
50 cerr
= CSSMERR_CSP_MEMORY_ERROR
;
52 case CCR_WRONG_VERSION
:
53 errStr
= "CCR_WRONG_VERSION";
54 cerr
= CSSMERR_CSP_INVALID_DATA
;
56 case CCR_BAD_CIPHERTEXT
:
57 errStr
= "CCR_BAD_CIPHERTEXT";
58 cerr
= CSSMERR_CSP_INVALID_DATA
;
62 errStr
= "CCR_INTERNAL";
63 cerr
= CSSMERR_CSP_INTERNAL_ERROR
;
67 Security::Syslog::error("Apple CSP %s: %s", op
, errStr
);
70 CssmError::throwMe(cerr
);
78 AscAlgFactory::AscAlgFactory(
79 CssmAllocator
*normAlloc
,
80 CssmAllocator
*privAlloc
)
82 /* once-per-address-space init */
83 ascAllocator
= privAlloc
;
84 comMallocRegister(ccMalloc
, ccFree
);
87 bool AscAlgFactory::setup(
88 AppleCSPSession
&session
,
89 CSPFullPluginSession::CSPContext
* &cspCtx
,
90 const Context
&context
)
92 if(context
.algorithm() != CSSM_ALGID_ASC
) {
96 /* reusing one of ours; OK */
99 switch(context
.type()) {
100 case CSSM_ALGCLASS_KEYGEN
:
101 cspCtx
= new AppleSymmKeyGenerator(session
,
103 COMCRYPT_MAX_KEYLENGTH
* 8,
104 true); // must be byte size
106 case CSSM_ALGCLASS_SYMMETRIC
:
107 cspCtx
= new ASCContext(session
);
116 ASCContext::~ASCContext()
119 comcryptObjFree(mCcObj
);
124 * Standard CSPContext init, called from CSPFullPluginSession::init().
125 * Reusable, e.g., query followed by en/decrypt.
127 void ASCContext::init(
128 const Context
&context
,
132 UInt8
*keyData
= NULL
;
135 /* obtain key from context */
136 symmetricKeyBits(context
, CSSM_ALGID_ASC
,
137 encrypting
? CSSM_KEYUSE_ENCRYPT
: CSSM_KEYUSE_DECRYPT
,
139 if((keyLen
< 1) || (keyLen
> COMCRYPT_MAX_KEYLENGTH
)) {
140 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY
);
142 mDecryptBufValid
= false;
144 /* All other context attributes ignored */
145 /* init the low-level state */
147 /* note we allow for context reuse */
148 mCcObj
= comcryptAlloc();
150 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
);
154 crtn
= comcryptInit(mCcObj
, keyData
, keyLen
, CCO_DEFAULT
);
156 throwComcrypt(crtn
, "comcryptInit");
161 * All of these functions are called by CSPFullPluginSession.
163 void ASCContext::update(
165 size_t &inSize
, // in/out
167 size_t &outSize
) // in/out
171 unsigned char *inText
= (unsigned char *)inp
;
172 unsigned char *outText
= (unsigned char *)outp
;
176 crtn
= comcryptData(mCcObj
,
181 CCE_MORE_TO_COME
); // not used on encrypt
183 throwComcrypt(crtn
, "comcryptData");
188 * Deal with 1-byte buffer hack. First decrypt the existing buffer...
191 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR
);
194 unsigned partialOutLen
= 0;
195 if(mDecryptBufValid
) {
196 thisOutLen
= outSize
;
197 crtn
= deComcryptData(mCcObj
,
203 mDecryptBufValid
= false;
205 throwComcrypt(crtn
, "deComcryptData (1)");
207 partialOutLen
= thisOutLen
;
208 outText
+= thisOutLen
;
212 * Now decrypt remaining, less one byte (which is stored in the
215 thisOutLen
= outSize
- partialOutLen
;
216 crtn
= deComcryptData(mCcObj
,
223 throwComcrypt(crtn
, "deComcryptData (2)");
225 outLen
= partialOutLen
+ thisOutLen
;
226 mDecryptBuf
= inText
[inSize
- 1];
227 mDecryptBufValid
= true;
230 aioprintf("=== ASC::update encrypt %d inSize %ld outSize %ld",
231 encoding() ? 1 : 0, inSize
, outSize
);
234 void ASCContext::final(
241 /* decrypt buffer hack */
242 if(!mDecryptBufValid
) {
243 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR
);
246 unsigned outLen
= out
.Length
;
247 crtn
= deComcryptData(mCcObj
,
250 (unsigned char *)out
.Data
,
253 mDecryptBufValid
= false;
255 throwComcrypt(crtn
, "deComcryptData (3)");
259 aioprintf("=== ASC::final encrypt %d outSize %ld",
260 encoding() ? 1 : 0, out
.Length
);
263 size_t ASCContext::inputSize(
264 size_t outSize
) // input for given output size
266 size_t rtn
= comcryptMaxInBufSize(mCcObj
,
268 encoding() ? CCOP_COMCRYPT
: CCOP_DECOMCRYPT
);
269 abprintf("--- ASCContext::inputSize inSize %ld outSize %ld",
275 * ComCryption's buffer size calculation really does not lend itself to the
276 * requirements here. For example, there is no guarantee that
277 * inputSize(outputSize(x)) == x. We're just going to fudge it and make
278 * apps (or CSPFullPluginSession) alloc plenty more than they need.
280 #define ASC_OUTSIZE_FUDGE 1
281 #define ASC_OUTSIZE_FUDGE_FACTOR 1.2
283 size_t ASCContext::outputSize(
285 size_t inSize
) // output for given input size
287 unsigned effectiveInSize
= inSize
;
290 rtn
= comcryptMaxOutBufSize(mCcObj
,
294 #if ASC_OUTSIZE_FUDGE
295 float newOutSize
= rtn
;
296 newOutSize
*= ASC_OUTSIZE_FUDGE_FACTOR
;
297 rtn
= static_cast<size_t>(newOutSize
);
298 #endif /* ASC_OUTSIZE_FUDGE */
302 if(mDecryptBufValid
) {
306 else if(inSize
&& !mDecryptBufValid
) {
307 /* not final and nothing buffered yet - lop off one */
310 rtn
= comcryptMaxOutBufSize(mCcObj
,
315 abprintf("--- ASCContext::outputSize inSize %ld outSize %ld final %d ",
320 void ASCContext::minimumProgress(
322 size_t &out
) // minimum progress chunks
326 out
= comcryptMaxOutBufSize(mCcObj
,
332 if(mDecryptBufValid
) {
333 /* use "everything" */
339 out
= comcryptMaxOutBufSize(mCcObj
,
344 abprintf("--- ASCContext::minProgres in %ld out %ld", in
, out
);
347 #endif /* ASC_CSP_ENABLE */