]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/bsafeSymmetric.cpp
Security-58286.270.3.0.1.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / bsafeSymmetric.cpp
1 /*
2 * Copyright (c) 2000-2001,2011,2014 Apple 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 #ifdef BSAFE_CSP_ENABLE
19
20
21 //
22 // bsafeSymmetric.cpp - symmetric encryption contexts and algorithms
23 //
24 #include "bsafecspi.h"
25 #include <security_utilities/debugging.h>
26
27 #define bbprintf(args...) secinfo("BSafeBuf", ## args)
28
29 #define VERBOSE_DEBUG 0
30 #if VERBOSE_DEBUG
31 static void dumpBuf(
32 char *title,
33 const CSSM_DATA *d,
34 uint32 maxLen)
35 {
36 unsigned i;
37 uint32 len;
38
39 if(title) {
40 printf("%s: ", title);
41 }
42 if(d == NULL) {
43 printf("NO DATA\n");
44 return;
45 }
46 printf("Total Length: %d\n ", d->Length);
47 len = maxLen;
48 if(d->Length < len) {
49 len = d->Length;
50 }
51 for(i=0; i<len; i++) {
52 printf("%02X ", d->Data[i]);
53 if((i % 16) == 15) {
54 printf("\n ");
55 }
56 }
57 printf("\n");
58 }
59 #else
60 #define dumpBuf(t, d, m)
61 #endif /* VERBOSE_DEBUG */
62
63 void BSafe::SymmetricKeyGenContext::generate(
64 const Context &context,
65 CssmKey &symKey,
66 CssmKey &dummyKey)
67 {
68 AppleSymmKeyGenContext::generateSymKey(
69 context,
70 session(),
71 symKey);
72 }
73
74 // FIXME:
75 // We really should match the key algorithm to the en/decrypt
76 // algorithm. Also: verify key usage bits.
77 void BSafe::BlockCipherContext::init(
78 const Context &context,
79 bool encrypting)
80 {
81 bool hasIV = false;
82 bool requirePad = false;
83
84 if (reusing(encrypting))
85 return; // all set to go
86
87 cssmAlg = context.algorithm();
88 switch(cssmAlg) {
89 // most are handled below; break here to special cases
90 case CSSM_ALGID_RC4:
91 RC4init(context);
92 return;
93 case CSSM_ALGID_DES:
94 case CSSM_ALGID_DESX:
95 case CSSM_ALGID_3DES_3KEY_EDE:
96 case CSSM_ALGID_RC5:
97 case CSSM_ALGID_RC2:
98 break;
99
100 /* others here... */
101 default:
102 // Should never have gotten this far
103 assert(0);
104 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
105 }
106
107
108 // these variables are used in the switch below and need to
109 // live until after setAlgorithm()
110 BSafeItem iv;
111 B_BLK_CIPHER_W_FEEDBACK_PARAMS spec;
112 A_RC5_PARAMS rc5Params;
113 A_RC2_PARAMS rc2Params;
114
115 // crypto algorithm
116 spec.encryptionParams = NULL_PTR; // default, may change
117 switch (cssmAlg) {
118 case CSSM_ALGID_DES:
119 spec.encryptionMethodName = POINTER("des");
120 break;
121 case CSSM_ALGID_DESX:
122 spec.encryptionMethodName = POINTER("desx");
123 break;
124 case CSSM_ALGID_3DES_3KEY_EDE:
125 spec.encryptionMethodName = POINTER("des_ede");
126 break;
127 case CSSM_ALGID_RC5:
128 spec.encryptionMethodName = POINTER("rc5");
129 spec.encryptionParams = POINTER(&rc5Params);
130 rc5Params.version = 0x10;
131 // FIXME - get this from context attr
132 rc5Params.rounds = 1;
133 rc5Params.wordSizeInBits = 32;
134 break;
135 case CSSM_ALGID_RC2:
136 {
137 spec.encryptionMethodName = POINTER("rc2");
138 spec.encryptionParams = POINTER(&rc2Params);
139 // effective key size in bits - either from Context,
140 // or the key
141 uint32 bits = context.getInt(CSSM_ATTRIBUTE_EFFECTIVE_BITS);
142 if(bits == 0) {
143 // OK, try the key
144 CssmKey &key = context.get<CssmKey>(CSSM_ATTRIBUTE_KEY,
145 CSSMERR_CSP_MISSING_ATTR_KEY);
146 bits = key.KeyHeader.LogicalKeySizeInBits;
147 }
148 rc2Params.effectiveKeyBits = bits;
149 break;
150 }
151 }
152
153 // feedback mode
154 cssmMode = context.getInt(CSSM_ATTRIBUTE_MODE);
155 switch (cssmMode) {
156 /* no mode attr --> 0 == CSSM_ALGMODE_NONE, not currently supported */
157 case CSSM_ALGMODE_CBCPadIV8:
158 requirePad = true;
159 // and fall thru
160 case CSSM_ALGMODE_CBC_IV8:
161 {
162 iv = context.get<CssmData>(CSSM_ATTRIBUTE_INIT_VECTOR,
163 CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR);
164 spec.feedbackMethodName = POINTER("cbc");
165 spec.feedbackParams = POINTER(&iv);
166 hasIV = true;
167 break;
168 }
169 case CSSM_ALGMODE_OFB_IV8: {
170 iv = context.get<CssmData>(CSSM_ATTRIBUTE_INIT_VECTOR,
171 CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR);
172 spec.feedbackMethodName = POINTER("ofb");
173 spec.feedbackParams = POINTER(&iv);
174 hasIV = true;
175 break;
176 }
177 case CSSM_ALGMODE_ECB: {
178 spec.feedbackMethodName = POINTER("ecb");
179 spec.feedbackParams = POINTER(&blockSize);
180 break;
181 }
182 default:
183 errorLog1("BSafe symmetric init: illegal mode (%d)\n", (int)cssmMode);
184 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE);
185 }
186
187 // padding
188 spec.paddingParams = NULL_PTR;
189 /* no padding attr --> 0 == PADDING_NONE */
190 padEnable = false;
191 uint32 cssmPadding = context.getInt(CSSM_ATTRIBUTE_PADDING);
192 if(requirePad) {
193 switch(cssmPadding) {
194 case CSSM_PADDING_PKCS1: // for backwards compatibility
195 case CSSM_PADDING_PKCS5:
196 case CSSM_PADDING_PKCS7:
197 spec.paddingMethodName = POINTER("pad");
198 padEnable = true;
199 break;
200 default:
201 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING);
202 }
203 }
204 else {
205 if(cssmPadding != CSSM_PADDING_NONE) {
206 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING);
207 }
208 else {
209 spec.paddingMethodName = POINTER("nopad");
210 }
211 }
212
213 // put it all together
214 setAlgorithm(AI_FeedbackCipher, &spec); // set BSafe algorithm
215 setKeyFromContext(context); // set BSafe key
216 cipherInit(); // common cryption init
217 }
218
219 void BSafe::BlockCipherContext::RC4init(
220 const Context &context)
221 {
222 setAlgorithm(AI_RC4, NULL); // set BSafe algorithm
223 setKeyFromContext(context); // set BSafe key
224 padEnable = false;
225 cipherInit(); // common cryption init
226 }
227
228 void BSafe::BlockCipherContext::trackUpdate(size_t inSize, size_t outSize)
229 {
230 size_t newPending = pending + inSize;
231 pending = newPending % blockSize;
232
233 /*
234 * Most of the time, the max size buffered by BSAFE is
235 * blockSize - 1 bytes. When decrypting and padding is enabled,
236 * BSAFE buffers up to a full block.
237 */
238 if(!mDirection && //Êdecrypting
239 padEnable && // padding
240 (pending == 0) && // mod result was 0
241 (newPending > 0)) { // but nonzero total
242 /* BSAFE is holding a whole block in its buffer */
243 pending = blockSize;
244 }
245 bbprintf("===trackUpdte: %s; inSize=%d newPending=%d pending=%d",
246 (mDirection ? "encrypt" : "decrypt"),
247 inSize, newPending, pending);
248 }
249
250 size_t BSafe::BlockCipherContext::inputSize(size_t outSize)
251 {
252 // if we have an 'outSize' output buffer, how many input bytes may we feed in?
253 size_t wholeBlocks = outSize / blockSize;
254 return wholeBlocks * blockSize - pending + (blockSize - 1);
255 }
256
257 size_t BSafe::BlockCipherContext::outputSize(bool final, size_t inSize)
258 {
259 // how much output buffer will we need for 'size' input bytes?
260
261 size_t totalToGo = inSize + pending;
262 // total to go, rounded up to next block
263 size_t numBlocks = (totalToGo + blockSize - 1) / blockSize;
264 size_t outSize;
265
266 /*
267 * encrypting: may get one additional block on final() if padding
268 * decrypting: outsize always <= insize
269 */
270 if(mDirection && // encrypting
271 final && // last time
272 padEnable && // padding enabled
273 ((totalToGo % blockSize) == 0)) { // even ptext len
274 numBlocks++; // extra pad block
275 }
276 outSize = numBlocks * blockSize;
277 bbprintf("===outputSize: %s; final=%d inSize=%d pending=%d outSize=%d",
278 (mDirection ? "encrypt" : "decrypt"),
279 final, inSize, pending, outSize);
280 return outSize;
281 }
282
283 void BSafe::BlockCipherContext::minimumProgress(size_t &inSize, size_t &outSize)
284 {
285 // eat up buffer, proceed one full block
286 inSize = blockSize - pending;
287 outSize = blockSize;
288 }
289 #endif /* BSAFE_CSP_ENABLE */