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 * aescsp.cpp - glue between BlockCryptor and AES implementation 21 * Written by Doug Mitchell 10/3/2000 22 */ 23 24#include "aescspi.h" 25#include "rijndaelApi.h" 26#include "rijndael-alg-ref.h" 27#include "cspdebugging.h" 28 29#define DEFAULT_BLOCK_SIZE (MIN_AES_BLOCK_BITS / 8) 30 31/* 32 * AES symmetric key generation. 33 * This algorithm has key size restrictions which don't fit with the 34 * standard AppleSymmKeyGenContext model so we have to do some addditional 35 * checking. 36 */ 37void AESKeyGenContext::generate( 38 const Context &context, 39 CssmKey &symKey, 40 CssmKey &dummyKey) 41{ 42 uint32 reqKeySize = context.getInt( 43 CSSM_ATTRIBUTE_KEY_LENGTH, 44 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH); 45 switch(reqKeySize) { 46 case MIN_AES_KEY_BITS: 47 case MID_AES_KEY_BITS: 48 case MAX_AES_KEY_BITS: 49 break; 50 default: 51 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE); 52 } 53 AppleSymmKeyGenContext::generateSymKey( 54 context, 55 session(), 56 symKey); 57} 58 59/* 60 * AES encrypt/decrypt. 61 */ 62AESContext::~AESContext() 63{ 64 deleteKey(); 65 memset(mRawKey, 0, MAX_AES_KEY_BITS / 8); 66 mInitFlag = false; 67} 68 69void AESContext::aesError( 70 int artn, 71 const char *errStr) 72{ 73 CSSM_RETURN crtn; 74 errorLog2("AESContext: %s : %d\n", errStr, artn); 75 switch(artn) { 76 case BAD_KEY_INSTANCE: 77 default: 78 crtn = CSSMERR_CSP_INTERNAL_ERROR; 79 break; 80 case BAD_KEY_MAT: 81 crtn = CSSMERR_CSP_INVALID_KEY; 82 break; 83 } 84 CssmError::throwMe(crtn); 85} 86 87void AESContext::deleteKey() 88{ 89 if(mAesKey) { 90 memset(mAesKey, 0, sizeof(keyInstance)); 91 session().free(mAesKey); 92 mAesKey = NULL; 93 } 94} 95 96/* 97 * Standard CSPContext init, called from CSPFullPluginSession::init(). 98 * Reusable, e.g., query followed by en/decrypt. Even reusable after context 99 * changed (i.e., new IV in Encrypted File System). 100 */ 101void AESContext::init( 102 const Context &context, 103 bool encrypting) 104{ 105 if(mInitFlag && !opStarted()) { 106 return; 107 } 108 109 CSSM_SIZE keyLen; 110 uint8 *keyData = NULL; 111 unsigned lastBlockSize = mBlockSize; // may be 0 (first time thru) 112 bool sameKeyAndBlockSizes = false; 113 114 /* obtain key from context */ 115 symmetricKeyBits(context, session(), CSSM_ALGID_AES, 116 encrypting ? CSSM_KEYUSE_ENCRYPT : CSSM_KEYUSE_DECRYPT, 117 keyData, keyLen); 118 119 switch(keyLen) { 120 case MIN_AES_KEY_BITS / 8: 121 case MID_AES_KEY_BITS / 8: 122 case MAX_AES_KEY_BITS / 8: 123 break; 124 default: 125 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY); 126 } 127 128 /* 129 * Validate context 130 * block size is optional 131 */ 132 mBlockSize = context.getInt(CSSM_ATTRIBUTE_BLOCK_SIZE); 133 if(mBlockSize == 0) { 134 mBlockSize = DEFAULT_BLOCK_SIZE; 135 } 136 137 138 /* 139 * Delete existing key if key size or block size changed 140 */ 141 if((lastBlockSize == mBlockSize) && (mRawKeySize == keyLen)) { 142 sameKeyAndBlockSizes = true; 143 } 144 if((mAesKey != NULL) && !sameKeyAndBlockSizes) { 145 deleteKey(); 146 } 147 148 int opt128 = 0; 149#if !GLADMAN_AES_128_ENABLE 150 if((mBlockSize == (MIN_AES_BLOCK_BITS/8)) && 151 (keyLen == (MIN_AES_KEY_BITS/8)) && 152 doAES128) { 153 opt128 = 1; 154 } 155#endif /* !GLADMAN_AES_128_ENABLE */ 156 157 /* create new key if needed */ 158 if(mAesKey == NULL) { 159 mAesKey = (keyInstance *)session().malloc(sizeof(keyInstance)); 160 } 161 162 /* init key only if key size, block size, or key bits have changed */ 163 if(!sameKeyAndBlockSizes || memcmp(mRawKey, keyData, mRawKeySize)) { 164 int artn = makeKey((keyInstance *)mAesKey, 165 (int)keyLen * 8, 166 mBlockSize * 8, 167 (word8 *)keyData, 168 opt128); 169 if(artn < 0) { 170 aesError(artn, "makeKey"); 171 } 172 173 /* save this raw key data */ 174 memmove(mRawKey, keyData, mRawKeySize); 175 mRawKeySize = (uint32)keyLen; 176 } 177 178#if !GLADMAN_AES_128_ENABLE 179 if(opt128) { 180 /* optimized path */ 181 mEncryptFcn = rijndaelBlockEncrypt128; 182 mDecryptFcn = rijndaelBlockDecrypt128; 183 } 184 else { 185 /* common standard path */ 186 mEncryptFcn = rijndaelBlockEncrypt; 187 mDecryptFcn = rijndaelBlockDecrypt; 188 } 189#else 190 /* common standard path */ 191 mEncryptFcn = rijndaelBlockEncrypt; 192 mDecryptFcn = rijndaelBlockDecrypt; 193#endif /* !GLADMAN_AES_128_ENABLE */ 194 195 /* Finally, have BlockCryptor do its setup */ 196 setup(mBlockSize, context); 197 mInitFlag = true; 198} 199 200/* 201 * Functions called by BlockCryptor 202 */ 203void AESContext::encryptBlock( 204 const void *plainText, // length implied (one block) 205 size_t plainTextLen, 206 void *cipherText, 207 size_t &cipherTextLen, // in/out, throws on overflow 208 bool final) // ignored 209{ 210 if(plainTextLen != mBlockSize) { 211 CssmError::throwMe(CSSMERR_CSP_INPUT_LENGTH_ERROR); 212 } 213 if(cipherTextLen < mBlockSize) { 214 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); 215 } 216 int artn = mEncryptFcn(mAesKey, 217 (word8 *)plainText, 218 (word8 *)cipherText); 219 if(artn < 0) { 220 aesError(artn, "rijndaelBlockEncrypt"); 221 } 222 cipherTextLen = mBlockSize; 223} 224 225void AESContext::decryptBlock( 226 const void *cipherText, // length implied (one cipher block) 227 size_t cipherTextLen, 228 void *plainText, 229 size_t &plainTextLen, // in/out, throws on overflow 230 bool final) // ignored 231{ 232 if(plainTextLen < mBlockSize) { 233 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); 234 } 235 int artn = mDecryptFcn(mAesKey, 236 (word8 *)cipherText, 237 (word8 *)plainText); 238 if(artn < 0) { 239 aesError(artn, "rijndaelBlockDecrypt"); 240 } 241 plainTextLen = mBlockSize; 242} 243 244