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...) secdebug("BSafeBuf", ## args) 28 29#define VERBOSE_DEBUG 0 30#if VERBOSE_DEBUG 31static 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 63void 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. 77void 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 219void 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 228void 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 250size_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 257size_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 283void 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 */ 290