]> git.saurik.com Git - apple/security.git/blob - libsecurity_apple_csp/lib/ascContext.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_apple_csp / lib / ascContext.cpp
1 /*
2 * ascContext.cpp - glue between BlockCrytpor and ComCryption (a.k.a. Apple
3 * Secure Compression).
4 * Written by Doug Mitchell 4/4/2001
5 */
6
7 #ifdef ASC_CSP_ENABLE
8
9 #include "ascContext.h"
10 #include "ascFactory.h"
11 #include <security_utilities/debugging.h>
12 #include <security_utilities/logging.h>
13 #include <Security/cssmapple.h>
14
15 #define abprintf(args...) secdebug("ascBuf", ## args) /* buffer sizes */
16 #define aioprintf(args...) secdebug("ascIo", ## args) /* all I/O */
17
18 static Allocator *ascAllocator;
19
20 /*
21 * Comcryption-style memory allocator callbacks
22 */
23 static void *ccMalloc(unsigned size)
24 {
25 return ascAllocator->malloc(size);
26 }
27 static void ccFree(void *data)
28 {
29 ascAllocator->free(data);
30 }
31
32 /* Given a ComCryption error, throw appropriate CssmError */
33 static void throwComcrypt(
34 comcryptReturn crtn,
35 const char *op) /* optional */
36 {
37 CSSM_RETURN cerr = CSSM_OK;
38 const char *errStr = "Bad Error String";
39
40 switch(crtn) {
41 case CCR_SUCCESS:
42 errStr = "CCR_SUCCESS";
43 break;
44 case CCR_OUTBUFFER_TOO_SMALL:
45 errStr = "CCR_OUTBUFFER_TOO_SMALL";
46 cerr = CSSMERR_CSP_OUTPUT_LENGTH_ERROR;
47 break;
48 case CCR_MEMORY_ERROR:
49 errStr = "CCR_MEMORY_ERROR";
50 cerr = CSSMERR_CSP_MEMORY_ERROR;
51 break;
52 case CCR_WRONG_VERSION:
53 errStr = "CCR_WRONG_VERSION";
54 cerr = CSSMERR_CSP_INVALID_DATA;
55 break;
56 case CCR_BAD_CIPHERTEXT:
57 errStr = "CCR_BAD_CIPHERTEXT";
58 cerr = CSSMERR_CSP_INVALID_DATA;
59 break;
60 case CCR_INTERNAL:
61 default:
62 errStr = "CCR_INTERNAL";
63 cerr = CSSMERR_CSP_INTERNAL_ERROR;
64 break;
65 }
66 if(op) {
67 Security::Syslog::error("Apple CSP %s: %s", op, errStr);
68 }
69 if(cerr) {
70 CssmError::throwMe(cerr);
71 }
72 }
73
74 /*
75 * Algorithm factory.
76 */
77
78 AscAlgFactory::AscAlgFactory(
79 Allocator *normAlloc,
80 Allocator *privAlloc)
81 {
82 /* once-per-address-space init */
83 ascAllocator = privAlloc;
84 comMallocRegister(ccMalloc, ccFree);
85 }
86
87 bool AscAlgFactory::setup(
88 AppleCSPSession &session,
89 CSPFullPluginSession::CSPContext * &cspCtx,
90 const Context &context)
91 {
92 if(context.algorithm() != CSSM_ALGID_ASC) {
93 return false;
94 }
95 if(cspCtx != NULL) {
96 /* reusing one of ours; OK */
97 return true;
98 }
99 switch(context.type()) {
100 case CSSM_ALGCLASS_KEYGEN:
101 cspCtx = new AppleSymmKeyGenerator(session,
102 8,
103 COMCRYPT_MAX_KEYLENGTH * 8,
104 true); // must be byte size
105 return true;
106 case CSSM_ALGCLASS_SYMMETRIC:
107 cspCtx = new ASCContext(session);
108 return true;
109 default:
110 break;
111 }
112 /* not ours */
113 return false;
114 }
115
116 ASCContext::~ASCContext()
117 {
118 if(mCcObj != NULL) {
119 comcryptObjFree(mCcObj);
120 }
121 }
122
123 /*
124 * Standard CSPContext init, called from CSPFullPluginSession::init().
125 * Reusable, e.g., query followed by en/decrypt.
126 */
127 void ASCContext::init(
128 const Context &context,
129 bool encrypting)
130 {
131 CSSM_SIZE keyLen;
132 uint8 *keyData = NULL;
133 comcryptReturn crtn;
134
135 /* obtain key from context */
136 symmetricKeyBits(context, session(), CSSM_ALGID_ASC,
137 encrypting ? CSSM_KEYUSE_ENCRYPT : CSSM_KEYUSE_DECRYPT,
138 keyData, keyLen);
139 if((keyLen < 1) || (keyLen > COMCRYPT_MAX_KEYLENGTH)) {
140 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
141 }
142 mDecryptBufValid = false;
143
144 /* optional optimization attribute */
145 comcryptOptimize optimize = CCO_DEFAULT;
146 uint32 opt = context.getInt(CSSM_ATTRIBUTE_ASC_OPTIMIZATION);
147 switch(opt) {
148 case CSSM_ASC_OPTIMIZE_DEFAULT:
149 optimize = CCO_DEFAULT;
150 break;
151 case CSSM_ASC_OPTIMIZE_SIZE:
152 optimize = CCO_SIZE;
153 break;
154 case CSSM_ASC_OPTIMIZE_SECURITY:
155 optimize = CCO_SECURITY;
156 break;
157 case CSSM_ASC_OPTIMIZE_TIME:
158 optimize = CCO_TIME;
159 break;
160 case CSSM_ASC_OPTIMIZE_TIME_SIZE:
161 optimize = CCO_TIME_SIZE;
162 break;
163 case CSSM_ASC_OPTIMIZE_ASCII:
164 optimize = CCO_ASCII;
165 break;
166 default:
167 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS);
168 }
169
170 /* All other context attributes ignored */
171 /* init the low-level state */
172 if(mCcObj == NULL) {
173 /* note we allow for context reuse */
174 mCcObj = comcryptAlloc();
175 if(mCcObj == NULL) {
176 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
177 }
178 }
179
180 crtn = comcryptInit(mCcObj, keyData, keyLen, optimize);
181 if(crtn) {
182 throwComcrypt(crtn, "comcryptInit");
183 }
184 }
185
186 /*
187 * All of these functions are called by CSPFullPluginSession.
188 */
189 void ASCContext::update(
190 void *inp,
191 size_t &inSize, // in/out
192 void *outp,
193 size_t &outSize) // in/out
194 {
195 comcryptReturn crtn;
196 unsigned outLen;
197 unsigned char *inText = (unsigned char *)inp;
198 unsigned char *outText = (unsigned char *)outp;
199
200 if(encoding()) {
201 outLen = outSize;
202 crtn = comcryptData(mCcObj,
203 inText,
204 inSize,
205 outText,
206 &outLen,
207 CCE_MORE_TO_COME); // not used on encrypt
208 if(crtn) {
209 throwComcrypt(crtn, "comcryptData");
210 }
211 }
212 else {
213 /*
214 * Deal with 1-byte buffer hack. First decrypt the existing buffer...
215 */
216 if(inSize == 0) {
217 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR);
218 }
219 unsigned thisOutLen;
220 unsigned partialOutLen = 0;
221 if(mDecryptBufValid) {
222 thisOutLen = outSize;
223 crtn = deComcryptData(mCcObj,
224 &mDecryptBuf,
225 1,
226 outText,
227 &thisOutLen,
228 CCE_MORE_TO_COME);
229 mDecryptBufValid = false;
230 if(crtn) {
231 throwComcrypt(crtn, "deComcryptData (1)");
232 }
233 partialOutLen = thisOutLen;
234 outText += thisOutLen;
235 }
236
237 /*
238 * Now decrypt remaining, less one byte (which is stored in the
239 * buffer).
240 */
241 thisOutLen = outSize - partialOutLen;
242 crtn = deComcryptData(mCcObj,
243 inText,
244 inSize - 1,
245 outText,
246 &thisOutLen,
247 CCE_MORE_TO_COME);
248 if(crtn) {
249 throwComcrypt(crtn, "deComcryptData (2)");
250 }
251 outLen = partialOutLen + thisOutLen;
252 mDecryptBuf = inText[inSize - 1];
253 mDecryptBufValid = true;
254 }
255 outSize = outLen;
256 aioprintf("=== ASC::update encrypt %d inSize %ld outSize %ld",
257 encoding() ? 1 : 0, inSize, outSize);
258 }
259
260 void ASCContext::final(
261 CssmData &out)
262 {
263 if(encoding()) {
264 out.length(0);
265 }
266 else {
267 /* decrypt buffer hack */
268 if(!mDecryptBufValid) {
269 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR);
270 }
271 comcryptReturn crtn;
272 unsigned outLen = out.Length;
273 crtn = deComcryptData(mCcObj,
274 &mDecryptBuf,
275 1,
276 (unsigned char *)out.Data,
277 &outLen,
278 CCE_END_OF_STREAM);
279 mDecryptBufValid = false;
280 if(crtn) {
281 throwComcrypt(crtn, "deComcryptData (3)");
282 }
283 out.length(outLen);
284 }
285 aioprintf("=== ASC::final encrypt %d outSize %ld",
286 encoding() ? 1 : 0, out.Length);
287 }
288
289 size_t ASCContext::inputSize(
290 size_t outSize) // input for given output size
291 {
292 size_t rtn = comcryptMaxInBufSize(mCcObj,
293 outSize,
294 encoding() ? CCOP_COMCRYPT : CCOP_DECOMCRYPT);
295 abprintf("--- ASCContext::inputSize inSize %ld outSize %ld",
296 rtn, outSize);
297 return rtn;
298 }
299
300 /*
301 * ComCryption's buffer size calculation really does not lend itself to the
302 * requirements here. For example, there is no guarantee that
303 * inputSize(outputSize(x)) == x. We're just going to fudge it and make
304 * apps (or CSPFullPluginSession) alloc plenty more than they need.
305 */
306 #define ASC_OUTSIZE_FUDGE 1
307 #define ASC_OUTSIZE_FUDGE_FACTOR 1.2
308
309 size_t ASCContext::outputSize(
310 bool final,
311 size_t inSize) // output for given input size
312 {
313 unsigned effectiveInSize = inSize;
314 size_t rtn;
315 if(encoding()) {
316 rtn = comcryptMaxOutBufSize(mCcObj,
317 effectiveInSize,
318 CCOP_COMCRYPT,
319 final);
320 #if ASC_OUTSIZE_FUDGE
321 float newOutSize = rtn;
322 newOutSize *= ASC_OUTSIZE_FUDGE_FACTOR;
323 rtn = static_cast<size_t>(newOutSize);
324 #endif /* ASC_OUTSIZE_FUDGE */
325 }
326 else {
327 if(final) {
328 if(mDecryptBufValid) {
329 effectiveInSize++;
330 }
331 }
332 else if(inSize && !mDecryptBufValid) {
333 /* not final and nothing buffered yet - lop off one */
334 effectiveInSize--;
335 }
336 rtn = comcryptMaxOutBufSize(mCcObj,
337 effectiveInSize,
338 CCOP_DECOMCRYPT,
339 final);
340 }
341 abprintf("--- ASCContext::outputSize inSize %ld outSize %ld final %d ",
342 inSize, rtn, final);
343 return rtn;
344 }
345
346 void ASCContext::minimumProgress(
347 size_t &in,
348 size_t &out) // minimum progress chunks
349 {
350 if(encoding()) {
351 in = 1;
352 out = comcryptMaxOutBufSize(mCcObj,
353 1,
354 CCOP_COMCRYPT,
355 0);
356 }
357 else {
358 if(mDecryptBufValid) {
359 /* use "everything" */
360 in = 1;
361 }
362 else {
363 in = 0;
364 }
365 out = comcryptMaxOutBufSize(mCcObj,
366 in,
367 CCOP_DECOMCRYPT,
368 0);
369 }
370 abprintf("--- ASCContext::minProgres in %ld out %ld", in, out);
371 }
372
373 #endif /* ASC_CSP_ENABLE */