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