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