]> git.saurik.com Git - apple/security.git/blob - AppleCSP/CryptKitCSP/FEEAsymmetricContext.cpp
Security-54.1.tar.gz
[apple/security.git] / AppleCSP / CryptKitCSP / FEEAsymmetricContext.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 /*
20 * FEEAsymmetricContext.cpp - CSPContexts for FEE asymmetric encryption
21 *
22 * Created March 8 2001 by dmitch.
23 */
24
25 #ifdef CRYPTKIT_CSP_ENABLE
26
27 #include "FEEAsymmetricContext.h"
28 #include "FEECSPUtils.h"
29 #include <Security/utilities.h>
30
31 /* validate context for FEED and FEEDExp - no unexpected attributes allowed */
32 static void validateFeedContext(
33 const Context &context)
34 {
35 /* Note we cannot distinguish between zero and "not there" */
36 uint32 blockSize = context.getInt(CSSM_ATTRIBUTE_BLOCK_SIZE);
37 if(blockSize != 0) {
38 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_BLOCK_SIZE);
39 }
40 CSSM_ENCRYPT_MODE cssmMode = context.getInt(CSSM_ATTRIBUTE_MODE);
41 if(cssmMode != 0) {
42 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE);
43 }
44 #if 0
45 /* we allow this for CMS wrapping */
46 CssmData *iv = context.get<CssmData>(CSSM_ATTRIBUTE_INIT_VECTOR);
47 if(iv != NULL) {
48 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_INIT_VECTOR);
49 }
50 #endif
51 CSSM_PADDING padding = context.getInt(CSSM_ATTRIBUTE_PADDING);
52 if(padding != 0) {
53 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING);
54 }
55 }
56
57 /***
58 *** FEED - 1:1 FEED - encrypt n bytes of plaintext, get (roughly) n bytes
59 *** of ciphertext. Ciphertext is smaller than with FEED, but this is slower.
60 ***/
61 CryptKit::FEEDContext::~FEEDContext()
62 {
63 if(mFeeFeed) {
64 feeFEEDFree(mFeeFeed);
65 mFeeFeed = NULL;
66 }
67 if(mPrivKey && mAllocdPrivKey) {
68 feePubKeyFree(mPrivKey);
69 }
70 if(mPubKey && mAllocdPubKey) {
71 feePubKeyFree(mPubKey);
72 }
73 mPrivKey = NULL;
74 mPubKey = NULL;
75 mInitFlag = false;
76 }
77
78 // called by CSPFullPluginSession; reusable
79 void CryptKit::FEEDContext::init(
80 const Context &context,
81 bool encoding)
82 {
83 if(mInitFlag && !opStarted()) {
84 /* reusing - e.g. query followed by encrypt */
85 return;
86 }
87
88 /*
89 * Fetch FEE keys from context. This is an unusual algorithm - it requires
90 * two keys, one public and one private. The public key MUST be stored in
91 * the context with attribute type CSSM_ATTRIBUTE_PUBLIC_KEY, and the private
92 * key with CSSM_ATTRIBUTE_KEY.
93 *
94 * For now, we require CSSM_KEYUSE_ANY for FEE keys used for this algorithm.
95 * Otherwise we'd have to allow both KEYUSE_ENCRYPT and KEYUSE_DECRYPT for
96 * both keys, and that would require some algorithm-specific hack in
97 * cspValidateKeyUsageBits() which I really don't want to do.
98 */
99 if(mPrivKey == NULL) {
100 assert(!opStarted());
101 mPrivKey = contextToFeeKey(context,
102 session(),
103 CSSM_ATTRIBUTE_KEY,
104 CSSM_KEYCLASS_PRIVATE_KEY,
105 CSSM_KEYUSE_ANY,
106 mAllocdPrivKey);
107 }
108 else {
109 assert(opStarted());
110 }
111 if(mPubKey == NULL) {
112 assert(!opStarted());
113 mPubKey = contextToFeeKey(context,
114 session(),
115 CSSM_ATTRIBUTE_PUBLIC_KEY,
116 CSSM_KEYCLASS_PUBLIC_KEY,
117 CSSM_KEYUSE_ANY,
118 mAllocdPubKey);
119 }
120 else {
121 assert(opStarted());
122 }
123
124 /* validate context - no other attributes allowed */
125 validateFeedContext(context);
126
127 if(mFeeFeed != NULL) {
128 /* not reusable */
129 assert(opStarted());
130 feeFEEDFree(mFeeFeed);
131 mFeeFeed = NULL;
132 }
133
134 /* OK, looks good. Cook up a feeFEED object. */
135 mFeeFeed = feeFEEDNewWithPubKey(mPrivKey,
136 mPubKey,
137 encoding ? 1 : 0,
138 feeRandCallback,
139 &session());
140 if(mFeeFeed == NULL) {
141 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
142 }
143
144 /* finally, have BlockCryptor set up its stuff. */
145 unsigned plainBlockSize = feeFEEDPlainBlockSize(mFeeFeed);
146 unsigned cipherBlockSize = feeFEEDCipherBlockSize(mFeeFeed);
147 setup(encoding ? plainBlockSize : cipherBlockSize, // blockSizeIn
148 encoding ? cipherBlockSize : plainBlockSize, // blockSizeOut
149 false, // pkcsPad
150 true, // needsFinal
151 BCM_ECB,
152 NULL); // IV
153 mInitFlag = true;
154 }
155
156 // called by BlockCryptor
157 void CryptKit::FEEDContext::encryptBlock(
158 const void *plainText, // length implied (one block)
159 size_t plainTextLen,
160 void *cipherText,
161 size_t &cipherTextLen, // in/out, throws on overflow
162 bool final)
163 {
164 feeReturn frtn;
165 unsigned actMoved;
166
167 assert(mFeeFeed != NULL);
168 frtn = feeFEEDEncryptBlock(mFeeFeed,
169 (unsigned char *)plainText,
170 plainTextLen,
171 (unsigned char *)cipherText,
172 &actMoved,
173 final ? 1 : 0);
174 if(frtn) {
175 throwCryptKit(frtn, "feeFEEDEncryptBlock");
176 }
177 if(actMoved > cipherTextLen) {
178 /* Overflow already occurred! */
179 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
180 }
181 cipherTextLen = actMoved;
182 }
183
184 void CryptKit::FEEDContext::decryptBlock(
185 const void *cipherText, // length implied (one cipher block)
186 void *plainText,
187 size_t &plainTextLen, // in/out, throws on overflow
188 bool final)
189 {
190 feeReturn frtn;
191 unsigned actMoved;
192
193 assert(mFeeFeed != NULL);
194 frtn = feeFEEDDecryptBlock(mFeeFeed,
195 (unsigned char *)cipherText,
196 inBlockSize(),
197 (unsigned char *)plainText,
198 &actMoved,
199 final ? 1 : 0);
200 if(frtn) {
201 throwCryptKit(frtn, "feeFEEDDecryptBlock");
202 }
203 if(actMoved > plainTextLen) {
204 /* Overflow already occurred! */
205 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
206 }
207 plainTextLen = actMoved;
208 }
209
210 /*
211 * Additional query size support, necessary because we don't conform to
212 * BlockCryptor's standard one-to-one block scheme
213 */
214
215 #define BUFFER_DEBUG 0
216 #if BUFFER_DEBUG
217 #define bprintf(s) printf s
218 #else
219 #define bprintf(s)
220 #endif
221
222 size_t CryptKit::FEEDContext::inputSize(
223 size_t outSize) // input for given output size
224 {
225 /*
226 * We've been assured that this is NOT called for the final() op...
227 */
228 unsigned inSize;
229 if(encoding()) {
230 inSize = feeFEEDPlainTextSize(mFeeFeed, outSize, 0);
231 }
232 else {
233 inSize = feeFEEDCipherTextSize(mFeeFeed, outSize, 0);
234 }
235
236 /* account for possible pending buffered input */
237 if(inSize >= inBufSize()) {
238 inSize -= inBufSize();
239 }
240
241 /* round up to next block size, then lop off one...anything from
242 * blockSize*n to (blockSize*n)-1 has same effect */
243 unsigned inBlocks = ((inSize + inBlockSize()) / inBlockSize());
244 inSize = (inBlocks * inBlockSize()) - 1;
245 bprintf(("--- FEEDContext::inputSize inSize 0x%x outSize 0x%x\n",
246 inSize, outSize));
247 return inSize;
248 }
249
250 size_t CryptKit::FEEDContext::outputSize(
251 bool final,
252 size_t inSize) // output for given input size
253 {
254 size_t rtn;
255 if(encoding()) {
256 rtn = feeFEEDCipherTextSize(mFeeFeed, inSize + inBufSize(), final ? 1 : 0);
257 }
258 else {
259 rtn = feeFEEDPlainTextSize(mFeeFeed, inSize + inBufSize(), final ? 1 : 0);
260 }
261 bprintf(("--- FEEDContext::outputSize inSize 0x%x outSize 0x%x final %d\n",
262 inSize, rtn, final));
263 return rtn;
264 }
265
266 void CryptKit::FEEDContext::minimumProgress(
267 size_t &in,
268 size_t &out) // minimum progress chunks
269 {
270 if(encoding()) {
271 /*
272 * -- in := one block plaintext
273 * -- out := current cipher size for one block plaintext
274 */
275 in = inBlockSize();
276 out = feeFEEDCipherBufSize(mFeeFeed, 0);
277 }
278 else {
279 /*
280 * -- in := current cipher size for one block plaintext
281 * -- out := one block plaintext
282 */
283 in = feeFEEDCipherBufSize(mFeeFeed, 0);
284 out = outBlockSize();
285 }
286
287 /*
288 * Either case - input adjusted for pending. Note inBufSize can be up to one
289 * input block size, leaving the temp result zero here....
290 */
291 assert(in >= inBufSize());
292 in -= inBufSize();
293
294 /* if it is zero, bump it up so caller can make something happen */
295 if(in == 0) {
296 in++;
297 }
298 bprintf(("--- FEEDContext::minProgres inSize 0x%x outSize 0x%x\n",
299 in, out));
300 }
301
302 /***
303 *** FEEDExp - 2:1 FEED - encrypt n bytes of plaintext, get (roughly) 2n bytes
304 *** of ciphertext. Ciphertext is larger than with FEED, but this is faster.
305 ***/
306 CryptKit::FEEDExpContext::~FEEDExpContext()
307 {
308 if(mFeeFeedExp) {
309 feeFEEDExpFree(mFeeFeedExp);
310 mFeeFeedExp = NULL;
311 }
312 if(mFeeKey && mAllocdFeeKey) {
313 feePubKeyFree(mFeeKey);
314 }
315 mFeeKey = NULL;
316 mInitFlag = false;
317 }
318
319 // called by CSPFullPluginSession; reusable
320 void CryptKit::FEEDExpContext::init(
321 const Context &context,
322 bool encoding)
323 {
324 if(mInitFlag && !opStarted()) {
325 /* reusing - e.g. query followed by encrypt */
326 return;
327 }
328
329 /* fetch FEE key from context */
330 CSSM_KEYCLASS keyClass;
331 CSSM_KEYUSE keyUse;
332
333 if(encoding) {
334 /* encrypting to public key */
335 keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
336 keyUse = CSSM_KEYUSE_ENCRYPT;
337 }
338 else {
339 /* decrypting with private key */
340 keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
341 keyUse = CSSM_KEYUSE_DECRYPT;
342 }
343 if(mFeeKey == NULL) {
344 assert(!opStarted());
345 mFeeKey = contextToFeeKey(context,
346 session(),
347 CSSM_ATTRIBUTE_KEY,
348 keyClass,
349 keyUse,
350 mAllocdFeeKey);
351 }
352 else {
353 assert(opStarted());
354 }
355
356 /* validate context - no other attributes allowed */
357 validateFeedContext(context);
358
359 /* OK, looks good. Cook up a feeFEEDExp object. */
360 if(mFeeFeedExp != NULL) {
361 /* not reusable */
362 assert(opStarted());
363 feeFEEDExpFree(mFeeFeedExp);
364 mFeeFeedExp = NULL;
365 }
366 mFeeFeedExp = feeFEEDExpNewWithPubKey(mFeeKey,
367 feeRandCallback,
368 &session());
369 if(mFeeFeedExp == NULL) {
370 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
371 }
372
373 /* finally, have BlockCryptor set up its stuff. */
374 unsigned plainBlockSize = feeFEEDExpPlainBlockSize(mFeeFeedExp);
375 unsigned cipherBlockSize = feeFEEDExpCipherBlockSize(mFeeFeedExp);
376 setup(encoding ? plainBlockSize : cipherBlockSize, // blockSizeIn
377 encoding ? cipherBlockSize : plainBlockSize, // blockSizeOut
378 false, // pkcs5Pad
379 true, // needsFinal
380 BCM_ECB,
381 NULL); // IV
382 mInitFlag = true;
383 }
384
385 // called by BlockCryptor
386 void CryptKit::FEEDExpContext::encryptBlock(
387 const void *plainText, // length implied (one block)
388 size_t plainTextLen,
389 void *cipherText,
390 size_t &cipherTextLen, // in/out, throws on overflow
391 bool final)
392 {
393 feeReturn frtn;
394 unsigned actMoved;
395
396 assert(mFeeFeedExp != NULL);
397 frtn = feeFEEDExpEncryptBlock(mFeeFeedExp,
398 (unsigned char *)plainText,
399 plainTextLen,
400 (unsigned char *)cipherText,
401 &actMoved,
402 final ? 1 : 0);
403 if(frtn) {
404 throwCryptKit(frtn, "feeFEEDExpEncryptBlock");
405 }
406 if(actMoved > cipherTextLen) {
407 /* Overflow already occurred! */
408 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
409 }
410 cipherTextLen = actMoved;
411 }
412
413 void CryptKit::FEEDExpContext::decryptBlock(
414 const void *cipherText, // length implied (one cipher block)
415 void *plainText,
416 size_t &plainTextLen, // in/out, throws on overflow
417 bool final)
418 {
419 feeReturn frtn;
420 unsigned actMoved;
421
422 assert(mFeeFeedExp != NULL);
423 frtn = feeFEEDExpDecryptBlock(mFeeFeedExp,
424 (unsigned char *)cipherText,
425 inBlockSize(),
426 (unsigned char *)plainText,
427 &actMoved,
428 final ? 1 : 0);
429 if(frtn) {
430 throwCryptKit(frtn, "feeFEEDExpDecryptBlock");
431 }
432 if(actMoved > plainTextLen) {
433 /* Overflow already occurred! */
434 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
435 }
436 plainTextLen = actMoved;
437 }
438
439 #endif /* CRYPTKIT_CSP_ENABLE */