+#include "cipherSpecs.h"
+#include "SSLRecordInternal.h"
+
+#ifdef KERNEL
+
+#include <corecrypto/ccaes.h>
+#include <corecrypto/ccdes.h>
+#include <corecrypto/ccmode.h>
+
+#include <AssertMacros.h>
+
+struct SymCipherContext {
+ const struct ccmode_cbc *cbc;
+ cccbc_ctx u[]; /* this will have the key and iv */
+};
+
+/* Macros for accessing the content of a SymCipherContext */
+
+/*
+ SymCipherContext looks like this in memory:
+
+ {
+ const struct ccmode_cbc *cbc;
+ cccbc_ctx key[n];
+ cccbc_iv iv[m];
+ }
+
+ cccbc_ctx and cccbc_iv are typedef-ined as aligned opaque struct, the actual contexts are arrays
+ of those types normally declared with a cc_ctx_decl macro.
+ The cc_ctx_n macros gives the number of elements in those arrays that are needed to store the
+ contexts.
+ The size of the context depends on the actual cbc implementation used.
+*/
+
+
+/* CTX_SIZE: Total size of the SymCipherContext struct for a cbc implementation */
+static inline
+size_t CTX_SIZE(const struct ccmode_cbc *cbc)
+{
+#ifdef __CC_HAS_FIX_FOR_11468135__
+ return (sizeof(SymCipherContext) + (sizeof(cccbc_ctx) * (cc_ctx_n(cccbc_ctx, cbc->size) + cc_ctx_n(cccbc_iv, cbc->block_size))));
+#else
+ /* This is approximate, but will work in that case, this code will go away after we transition */
+ return (sizeof(SymCipherContext) + sizeof(cccbc_ctx) + cbc->size);
+#endif
+}
+
+/* CTX_KEY: Address of the key context in the SymCipherContext struct */
+static inline
+cccbc_ctx *CTX_KEY(struct SymCipherContext *ctx)
+{
+ return &ctx->u[0];
+}
+
+
+/* CTX_IV: Address of the iv context in the SymCipherContext struct */
+#ifdef __CC_HAS_FIX_FOR_11468135__
+static inline
+cccbc_iv *CTX_IV(struct SymCipherContext *ctx)
+{
+ return (cccbc_iv *)&ctx->u[cc_ctx_n(cccbc_ctx, ctx->cbc->size)];
+}
+#endif
+
+static
+const void *ccmode(SSL_CipherAlgorithm alg, int enc)
+{
+ switch(alg) {
+ case SSL_CipherAlgorithmAES_128_CBC:
+ case SSL_CipherAlgorithmAES_256_CBC:
+ return enc?ccaes_cbc_encrypt_mode():ccaes_cbc_decrypt_mode();
+ case SSL_CipherAlgorithm3DES_CBC:
+ return enc?ccdes3_cbc_encrypt_mode():ccdes3_cbc_decrypt_mode();
+ case SSL_CipherAlgorithmAES_128_GCM:
+ case SSL_CipherAlgorithmAES_256_GCM:
+ case SSL_CipherAlgorithmRC4_128:
+ /* TODO: we should do RC4 for TLS, but we dont need it for DTLS */
+ default:
+ check(0);
+ return NULL; /* This will cause CCCryptorCreate to return an error */
+ }
+}
+
+static
+int CCSymmInit(
+ const SSLSymmetricCipherParams *params,
+ int encrypting,
+ uint8_t *key,
+ uint8_t* iv,
+ SymCipherContext *cipherCtx)
+{
+ check(cipherCtx!=NULL);
+ check(params);
+ SymCipherContext ctx = *cipherCtx;
+
+ /*
+ * Cook up a cccbx_ctx object. Assumes:
+ * cipherCtx->symCipher.keyAlg
+ * cipherCtx->encrypting
+ * key (raw key bytes)
+ * iv (raw bytes)
+ * On successful exit:
+ * Resulting ccmode --> cipherCtx
+ */
+
+ /* FIXME: this should not be needed as long as CCSymFinish is called */
+ if(ctx) {
+ sslFree(ctx);
+ ctx = NULL;
+ }
+
+ const struct ccmode_cbc *cbc = ccmode(params->keyAlg, encrypting);
+
+ ctx = sslMalloc(CTX_SIZE(cbc));
+
+ if(ctx==NULL) {
+ sslErrorLog("CCSymmInit: Can't allocate context\n");
+ return errSSLRecordInternal;
+ }
+
+ ctx->cbc = cbc;
+
+#ifdef __CC_HAS_FIX_FOR_11468135__
+ cccbc_init(cbc, CTX_KEY(ctx), params->keySize, key);
+ cccbc_set_iv(cbc, CTX_IV(ctx), iv);
+#else
+ cccbc_init(cbc, CTX_KEY(ctx), params->keySize, key, iv);
+#endif
+
+ *cipherCtx = ctx;
+ return 0;
+}
+
+/* same for en/decrypt */
+static
+int CCSymmEncryptDecrypt(
+ const uint8_t *src,
+ uint8_t *dest,
+ size_t len,
+ SymCipherContext cipherCtx)
+{
+
+ ASSERT(cipherCtx != NULL);
+ ASSERT(cipherCtx->cbc != NULL);
+
+ if(cipherCtx == NULL || cipherCtx->cbc == NULL) {
+ sslErrorLog("CCSymmEncryptDecrypt: NULL cipherCtx\n");
+ return errSSLRecordInternal;
+ }
+
+ ASSERT((len%cipherCtx->cbc->block_size)==0);
+
+ if(len%cipherCtx->cbc->block_size) {
+ sslErrorLog("CCSymmEncryptDecrypt: Invalid size\n");
+ return errSSLRecordInternal;
+ }
+
+ unsigned long nblocks = len/cipherCtx->cbc->block_size;
+
+#ifdef __CC_HAS_FIX_FOR_11468135__
+ cccbc_update(cipherCtx->cbc, CTX_KEY(cipherCtx), CTX_IV(cipherCtx), nblocks, src, dest);
+#else
+ cipherCtx->cbc->cbc(CTX_KEY(cipherCtx), nblocks, src, dest);
+#endif
+ return 0;
+}
+
+static
+int CCSymmFinish(
+ SymCipherContext cipherCtx)
+{
+ if(cipherCtx) {
+ sslFree(cipherCtx);
+ }
+ return 0;
+}
+
+
+#else
+
+#define ENABLE_RC4 1
+#define ENABLE_3DES 1
+#define ENABLE_AES 1
+#define ENABLE_AES256 1