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