]> git.saurik.com Git - apple/security.git/blob - AppleCSP/ComCryption/ascContext.cpp
Security-29.tar.gz
[apple/security.git] / AppleCSP / ComCryption / 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/debugging.h>
12 #include <Security/logging.h>
13 #include <Security/debugging.h>
14
15 #define abprintf(args...) debug("ascBuf", ## args) /* buffer sizes */
16 #define aioprintf(args...) debug("ascIo", ## args) /* all I/O */
17
18 static CssmAllocator *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 CssmAllocator *normAlloc,
80 CssmAllocator *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 UInt32 keyLen;
132 UInt8 *keyData = NULL;
133 comcryptReturn crtn;
134
135 /* obtain key from context */
136 symmetricKeyBits(context, 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 /* All other context attributes ignored */
145 /* init the low-level state */
146 if(mCcObj == NULL) {
147 /* note we allow for context reuse */
148 mCcObj = comcryptAlloc();
149 if(mCcObj == NULL) {
150 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
151 }
152 }
153
154 crtn = comcryptInit(mCcObj, keyData, keyLen, CCO_DEFAULT);
155 if(crtn) {
156 throwComcrypt(crtn, "comcryptInit");
157 }
158 }
159
160 /*
161 * All of these functions are called by CSPFullPluginSession.
162 */
163 void ASCContext::update(
164 void *inp,
165 size_t &inSize, // in/out
166 void *outp,
167 size_t &outSize) // in/out
168 {
169 comcryptReturn crtn;
170 unsigned outLen;
171 unsigned char *inText = (unsigned char *)inp;
172 unsigned char *outText = (unsigned char *)outp;
173
174 if(encoding()) {
175 outLen = outSize;
176 crtn = comcryptData(mCcObj,
177 inText,
178 inSize,
179 outText,
180 &outLen,
181 CCE_MORE_TO_COME); // not used on encrypt
182 if(crtn) {
183 throwComcrypt(crtn, "comcryptData");
184 }
185 }
186 else {
187 /*
188 * Deal with 1-byte buffer hack. First decrypt the existing buffer...
189 */
190 if(inSize == 0) {
191 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR);
192 }
193 unsigned thisOutLen;
194 unsigned partialOutLen = 0;
195 if(mDecryptBufValid) {
196 thisOutLen = outSize;
197 crtn = deComcryptData(mCcObj,
198 &mDecryptBuf,
199 1,
200 outText,
201 &thisOutLen,
202 CCE_MORE_TO_COME);
203 mDecryptBufValid = false;
204 if(crtn) {
205 throwComcrypt(crtn, "deComcryptData (1)");
206 }
207 partialOutLen = thisOutLen;
208 outText += thisOutLen;
209 }
210
211 /*
212 * Now decrypt remaining, less one byte (which is stored in the
213 * buffer).
214 */
215 thisOutLen = outSize - partialOutLen;
216 crtn = deComcryptData(mCcObj,
217 inText,
218 inSize - 1,
219 outText,
220 &thisOutLen,
221 CCE_MORE_TO_COME);
222 if(crtn) {
223 throwComcrypt(crtn, "deComcryptData (2)");
224 }
225 outLen = partialOutLen + thisOutLen;
226 mDecryptBuf = inText[inSize - 1];
227 mDecryptBufValid = true;
228 }
229 outSize = outLen;
230 aioprintf("=== ASC::update encrypt %d inSize %ld outSize %ld",
231 encoding() ? 1 : 0, inSize, outSize);
232 }
233
234 void ASCContext::final(
235 CssmData &out)
236 {
237 if(encoding()) {
238 out.length(0);
239 }
240 else {
241 /* decrypt buffer hack */
242 if(!mDecryptBufValid) {
243 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR);
244 }
245 comcryptReturn crtn;
246 unsigned outLen = out.Length;
247 crtn = deComcryptData(mCcObj,
248 &mDecryptBuf,
249 1,
250 (unsigned char *)out.Data,
251 &outLen,
252 CCE_END_OF_STREAM);
253 mDecryptBufValid = false;
254 if(crtn) {
255 throwComcrypt(crtn, "deComcryptData (3)");
256 }
257 out.length(outLen);
258 }
259 aioprintf("=== ASC::final encrypt %d outSize %ld",
260 encoding() ? 1 : 0, out.Length);
261 }
262
263 size_t ASCContext::inputSize(
264 size_t outSize) // input for given output size
265 {
266 size_t rtn = comcryptMaxInBufSize(mCcObj,
267 outSize,
268 encoding() ? CCOP_COMCRYPT : CCOP_DECOMCRYPT);
269 abprintf("--- ASCContext::inputSize inSize %ld outSize %ld",
270 rtn, outSize);
271 return rtn;
272 }
273
274 /*
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.
279 */
280 #define ASC_OUTSIZE_FUDGE 1
281 #define ASC_OUTSIZE_FUDGE_FACTOR 1.2
282
283 size_t ASCContext::outputSize(
284 bool final,
285 size_t inSize) // output for given input size
286 {
287 unsigned effectiveInSize = inSize;
288 size_t rtn;
289 if(encoding()) {
290 rtn = comcryptMaxOutBufSize(mCcObj,
291 effectiveInSize,
292 CCOP_COMCRYPT,
293 final);
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 */
299 }
300 else {
301 if(final) {
302 if(mDecryptBufValid) {
303 effectiveInSize++;
304 }
305 }
306 else if(inSize && !mDecryptBufValid) {
307 /* not final and nothing buffered yet - lop off one */
308 effectiveInSize--;
309 }
310 rtn = comcryptMaxOutBufSize(mCcObj,
311 effectiveInSize,
312 CCOP_DECOMCRYPT,
313 final);
314 }
315 abprintf("--- ASCContext::outputSize inSize %ld outSize %ld final %d ",
316 inSize, rtn, final);
317 return rtn;
318 }
319
320 void ASCContext::minimumProgress(
321 size_t &in,
322 size_t &out) // minimum progress chunks
323 {
324 if(encoding()) {
325 in = 1;
326 out = comcryptMaxOutBufSize(mCcObj,
327 1,
328 CCOP_COMCRYPT,
329 0);
330 }
331 else {
332 if(mDecryptBufValid) {
333 /* use "everything" */
334 in = 1;
335 }
336 else {
337 in = 0;
338 }
339 out = comcryptMaxOutBufSize(mCcObj,
340 in,
341 CCOP_DECOMCRYPT,
342 0);
343 }
344 abprintf("--- ASCContext::minProgres in %ld out %ld", in, out);
345 }
346
347 #endif /* ASC_CSP_ENABLE */