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 * gladmanContext.cpp - glue between BlockCryptor and Gladman AES implementation
21 */
22
23#include "gladmanContext.h"
24#include "cspdebugging.h"
25#include <CommonCrypto/CommonCryptor.h>
26
27/*
28 * AES encrypt/decrypt.
29 */
30GAESContext::GAESContext(AppleCSPSession &session) :
31    BlockCryptor(session),
32	mAesKey(NULL),
33	mInitFlag(false),
34	mRawKeySize(0),
35	mWasEncrypting(false)
36{
37	cbcCapable(false);
38	multiBlockCapable(false);
39}
40
41GAESContext::~GAESContext()
42{
43    if(mAesKey) {
44        CCCryptorFinal(mAesKey,NULL,0,NULL);
45        CCCryptorRelease(mAesKey);
46        mAesKey = NULL;
47    }
48
49	deleteKey();
50	memset(mRawKey, 0, MAX_AES_KEY_BITS / 8);
51	mInitFlag = false;
52}
53
54void GAESContext::deleteKey()
55{
56	mRawKeySize = 0;
57}
58
59/*
60 * Standard CSPContext init, called from CSPFullPluginSession::init().
61 * Reusable, e.g., query followed by en/decrypt. Even reusable after context
62 * changed (i.e., new IV in Encrypted File System).
63 */
64void GAESContext::init(
65	const Context &context,
66	bool encrypting)
67{
68	if(mInitFlag && !opStarted()) {
69		return;
70	}
71
72	CSSM_SIZE	keyLen;
73	uint8 		*keyData = NULL;
74	bool		sameKeySize = false;
75
76	/* obtain key from context */
77	symmetricKeyBits(context, session(), CSSM_ALGID_AES,
78		encrypting ? CSSM_KEYUSE_ENCRYPT : CSSM_KEYUSE_DECRYPT,
79		keyData, keyLen);
80
81	switch(keyLen) {
82		case kCCKeySizeAES128:
83		case kCCKeySizeAES192:
84		case kCCKeySizeAES256:
85			break;
86		default:
87			CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
88	}
89
90	/*
91	 * Delete existing key if key size changed
92	 */
93	if(mRawKeySize == keyLen) {
94		sameKeySize = true;
95	}
96	else {
97		deleteKey();
98	}
99
100	/*
101	 * Init key only if key size or key bits have changed, or
102	 * we're doing a different operation than the previous key
103	 * was scheduled for.
104	 */
105	if(!sameKeySize || (mWasEncrypting != encrypting) ||
106		memcmp(mRawKey, keyData, mRawKeySize)) {
107        (void) CCCryptorCreateWithMode(0, kCCModeECB, kCCAlgorithmAES128, ccDefaultPadding, NULL, keyData, keyLen, NULL, 0, 0, 0, &mAesKey);
108
109		/* save this raw key data */
110		memmove(mRawKey, keyData, keyLen);
111		mRawKeySize = (uint32)keyLen;
112		mWasEncrypting = encrypting;
113	}
114
115	/* we handle CBC, and hence the IV, ourselves */
116	CSSM_ENCRYPT_MODE cssmMode = context.getInt(CSSM_ATTRIBUTE_MODE);
117    switch (cssmMode) {
118		/* no mode attr --> 0 == CSSM_ALGMODE_NONE, not currently supported */
119 		case CSSM_ALGMODE_CBCPadIV8:
120		case CSSM_ALGMODE_CBC_IV8:
121		{
122			CssmData *iv = context.get<CssmData>(CSSM_ATTRIBUTE_INIT_VECTOR);
123			if(iv == NULL) {
124				CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR);
125			}
126			if(iv->Length != kCCBlockSizeAES128) {
127				CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_INIT_VECTOR);
128			}
129		}
130		break;
131		default:
132		break;
133	}
134
135	/* Finally, have BlockCryptor do its setup */
136	setup(GLADMAN_BLOCK_SIZE_BYTES, context);
137	mInitFlag = true;
138}
139
140/*
141 * Functions called by BlockCryptor
142 * FIXME make this multi-block capabl3e
143 */
144void GAESContext::encryptBlock(
145	const void		*plainText,			// length implied (one block)
146	size_t			plainTextLen,
147	void 			*cipherText,
148	size_t			&cipherTextLen,		// in/out, throws on overflow
149	bool			final)				// ignored
150{
151	if(cipherTextLen < plainTextLen) {
152		CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
153	}
154    (void) CCCryptorEncryptDataBlock(mAesKey, NULL, plainText, plainTextLen, cipherText);
155
156	cipherTextLen = plainTextLen;
157}
158
159void GAESContext::decryptBlock(
160	const void		*cipherText,		// length implied (one cipher block)
161	size_t			cipherTextLen,
162	void			*plainText,
163	size_t			&plainTextLen,		// in/out, throws on overflow
164	bool			final)				// ignored
165{
166	if(plainTextLen < cipherTextLen) {
167		CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
168	}
169    (void) CCCryptorDecryptDataBlock(mAesKey, NULL, cipherText, cipherTextLen, plainText);
170	plainTextLen = cipherTextLen;
171}
172
173