468 lines
17 KiB
C
468 lines
17 KiB
C
/* Copyright (c) (2012,2014-2016,2018-2020) Apple Inc. All rights reserved.
|
||
*
|
||
* corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which
|
||
* is contained in the License.txt file distributed with corecrypto) and only to
|
||
* people who accept that license. IMPORTANT: Any license rights granted to you by
|
||
* Apple Inc. (if any) are limited to internal use within your organization only on
|
||
* devices and computers you own or control, for the sole purpose of verifying the
|
||
* security characteristics and correct functioning of the Apple Software. You may
|
||
* not, directly or indirectly, redistribute the Apple Software or any portions thereof.
|
||
*/
|
||
|
||
#include <stdbool.h>
|
||
#include "ccsymmetric.h"
|
||
#include "testmore.h"
|
||
|
||
int cc_get_ciphermode(cc_cipher_select cipher, cc_mode_select mode, cc_direction direction, cc_ciphermode_descriptor desc)
|
||
{
|
||
desc->cipher = cipher;
|
||
desc->mode = mode;
|
||
desc->direction = direction;
|
||
desc->ciphermode.data = NULL;
|
||
int op = direction == cc_Encrypt; // save editting flip-flop logic
|
||
switch (cipher) {
|
||
case cc_cipherAES:
|
||
switch (mode) {
|
||
case cc_ModeECB:
|
||
desc->ciphermode.ecb = (op) ? ccaes_ecb_encrypt_mode() : ccaes_ecb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCBC:
|
||
desc->ciphermode.cbc = (op) ? ccaes_cbc_encrypt_mode() : ccaes_cbc_decrypt_mode();
|
||
break;
|
||
case cc_ModeCFB:
|
||
desc->ciphermode.cfb = (op) ? ccaes_cfb_encrypt_mode() : ccaes_cfb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCTR:
|
||
desc->ciphermode.ctr = ccaes_ctr_crypt_mode();
|
||
break;
|
||
case cc_ModeOFB:
|
||
desc->ciphermode.ofb = ccaes_ofb_crypt_mode();
|
||
break;
|
||
case cc_ModeXTS:
|
||
desc->ciphermode.xts = (op) ? ccaes_xts_encrypt_mode() : ccaes_xts_decrypt_mode();
|
||
break;
|
||
case cc_ModeCFB8:
|
||
desc->ciphermode.cfb8 = (op) ? ccaes_cfb8_encrypt_mode() : ccaes_cfb8_decrypt_mode();
|
||
break;
|
||
case cc_ModeGCM:
|
||
desc->ciphermode.gcm = (op) ? ccaes_gcm_encrypt_mode() : ccaes_gcm_decrypt_mode();
|
||
break;
|
||
case cc_ModeCCM:
|
||
desc->ciphermode.ccm = (op) ? ccaes_ccm_encrypt_mode() : ccaes_ccm_decrypt_mode();
|
||
break;
|
||
}
|
||
break;
|
||
case cc_cipherDES:
|
||
switch (mode) {
|
||
case cc_ModeECB:
|
||
desc->ciphermode.ecb = (op) ? ccdes_ecb_encrypt_mode() : ccdes_ecb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCBC:
|
||
desc->ciphermode.cbc = (op) ? ccdes_cbc_encrypt_mode() : ccdes_cbc_decrypt_mode();
|
||
break;
|
||
case cc_ModeCFB:
|
||
desc->ciphermode.cfb = (op) ? ccdes_cfb_encrypt_mode() : ccdes_cfb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCTR:
|
||
desc->ciphermode.ctr = ccdes_ctr_crypt_mode();
|
||
break;
|
||
case cc_ModeOFB:
|
||
desc->ciphermode.ofb = ccdes_ofb_crypt_mode();
|
||
break;
|
||
case cc_ModeCFB8:
|
||
desc->ciphermode.cfb8 = (op) ? ccdes_cfb8_encrypt_mode() : ccdes_cfb8_decrypt_mode();
|
||
break;
|
||
}
|
||
break;
|
||
case cc_cipher3DES:
|
||
switch (mode) {
|
||
case cc_ModeECB:
|
||
desc->ciphermode.ecb = (op) ? ccdes3_ecb_encrypt_mode() : ccdes3_ecb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCBC:
|
||
desc->ciphermode.cbc = (op) ? ccdes3_cbc_encrypt_mode() : ccdes3_cbc_decrypt_mode();
|
||
break;
|
||
case cc_ModeCFB:
|
||
desc->ciphermode.cfb = (op) ? ccdes3_cfb_encrypt_mode() : ccdes3_cfb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCTR:
|
||
desc->ciphermode.ctr = ccdes3_ctr_crypt_mode();
|
||
break;
|
||
case cc_ModeOFB:
|
||
desc->ciphermode.ofb = ccdes3_ofb_crypt_mode();
|
||
break;
|
||
case cc_ModeCFB8:
|
||
desc->ciphermode.cfb8 = (op) ? ccdes3_cfb8_encrypt_mode() : ccdes3_cfb8_decrypt_mode();
|
||
break;
|
||
}
|
||
break;
|
||
case cc_cipherCAST:
|
||
switch (mode) {
|
||
case cc_ModeECB:
|
||
desc->ciphermode.ecb = (op) ? cccast_ecb_encrypt_mode() : cccast_ecb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCBC:
|
||
desc->ciphermode.cbc = (op) ? cccast_cbc_encrypt_mode() : cccast_cbc_decrypt_mode();
|
||
break;
|
||
case cc_ModeCFB:
|
||
desc->ciphermode.cfb = (op) ? cccast_cfb_encrypt_mode() : cccast_cfb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCTR:
|
||
desc->ciphermode.ctr = cccast_ctr_crypt_mode();
|
||
break;
|
||
case cc_ModeOFB:
|
||
desc->ciphermode.ofb = cccast_ofb_crypt_mode();
|
||
break;
|
||
case cc_ModeCFB8:
|
||
desc->ciphermode.cfb8 = (op) ? cccast_cfb8_encrypt_mode() : cccast_cfb8_decrypt_mode();
|
||
break;
|
||
}
|
||
break;
|
||
case cc_cipherRC2:
|
||
switch (mode) {
|
||
case cc_ModeECB:
|
||
desc->ciphermode.ecb = (op) ? ccrc2_ecb_encrypt_mode() : ccrc2_ecb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCBC:
|
||
desc->ciphermode.cbc = (op) ? ccrc2_cbc_encrypt_mode() : ccrc2_cbc_decrypt_mode();
|
||
break;
|
||
case cc_ModeCFB:
|
||
desc->ciphermode.cfb = (op) ? ccrc2_cfb_encrypt_mode() : ccrc2_cfb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCTR:
|
||
desc->ciphermode.ctr = ccrc2_ctr_crypt_mode();
|
||
break;
|
||
case cc_ModeOFB:
|
||
desc->ciphermode.ofb = ccrc2_ofb_crypt_mode();
|
||
break;
|
||
case cc_ModeCFB8:
|
||
desc->ciphermode.cfb8 = (op) ? ccrc2_cfb8_encrypt_mode() : ccrc2_cfb8_decrypt_mode();
|
||
break;
|
||
}
|
||
break;
|
||
case cc_cipherBlowfish:
|
||
switch (mode) {
|
||
case cc_ModeECB:
|
||
desc->ciphermode.ecb = (op) ? ccblowfish_ecb_encrypt_mode() : ccblowfish_ecb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCBC:
|
||
desc->ciphermode.cbc = (op) ? ccblowfish_cbc_encrypt_mode() : ccblowfish_cbc_decrypt_mode();
|
||
break;
|
||
case cc_ModeCFB:
|
||
desc->ciphermode.cfb = (op) ? ccblowfish_cfb_encrypt_mode() : ccblowfish_cfb_decrypt_mode();
|
||
break;
|
||
case cc_ModeCTR:
|
||
desc->ciphermode.ctr = ccblowfish_ctr_crypt_mode();
|
||
break;
|
||
case cc_ModeOFB:
|
||
desc->ciphermode.ofb = ccblowfish_ofb_crypt_mode();
|
||
break;
|
||
case cc_ModeCFB8:
|
||
desc->ciphermode.cfb8 = (op) ? ccblowfish_cfb8_encrypt_mode() : ccblowfish_cfb8_decrypt_mode();
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
if (desc->ciphermode.data == NULL)
|
||
return CC_FAILURE;
|
||
return CC_SUCCESS;
|
||
}
|
||
|
||
int cc_get_C_ciphermode(cc_cipher_select cipher, cc_mode_select mode, cc_direction direction, cc_ciphermode_descriptor desc)
|
||
{
|
||
desc->cipher = cipher;
|
||
desc->mode = mode;
|
||
desc->direction = direction;
|
||
desc->ciphermode.data = NULL;
|
||
return CC_UNIMPLEMENTED;
|
||
}
|
||
|
||
static bool verify_and_ok_duplicate_key(const void *key, size_t keylen)
|
||
{
|
||
if (keylen != 24) {
|
||
return false;
|
||
}
|
||
if (memcmp(key, key+8, 8) == 0 || memcmp(key, key+16, 8) == 0 || memcmp(key+8, key+16, 8) == 0) {
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
int cc_symmetric_setup(cc_ciphermode_descriptor cm, const void *key, size_t keylen, const void *iv, cc_symmetric_context_p ctx)
|
||
{
|
||
int rc;
|
||
switch (cm->mode) {
|
||
case cc_ModeECB:
|
||
rc = cm->ciphermode.ecb->init(cm->ciphermode.ecb, ctx->ctx.ecb, keylen, key);
|
||
break;
|
||
case cc_ModeCBC:
|
||
rc = cm->ciphermode.cbc->init(cm->ciphermode.cbc, ctx->ctx.cbc, keylen, key);
|
||
break;
|
||
case cc_ModeCFB:
|
||
rc = cm->ciphermode.cfb->init(cm->ciphermode.cfb, ctx->ctx.cfb, keylen, key, iv);
|
||
break;
|
||
case cc_ModeCTR:
|
||
rc = cm->ciphermode.ctr->init(cm->ciphermode.ctr, ctx->ctx.ctr, keylen, key, iv);
|
||
break;
|
||
case cc_ModeOFB:
|
||
rc = cm->ciphermode.ofb->init(cm->ciphermode.ofb, ctx->ctx.ofb, keylen, key, iv);
|
||
break;
|
||
case cc_ModeCFB8:
|
||
rc = cm->ciphermode.cfb8->init(cm->ciphermode.cfb8, ctx->ctx.cfb8, keylen, key, iv);
|
||
break;
|
||
default:
|
||
return CC_FAILURE;
|
||
}
|
||
// 3DES was modified to return an error of -1 on a 3DES key setup which repeated any of the sub-keys
|
||
// However, we still want to test these historic test vectors. So if we get a fail on setup we verify that it is
|
||
// for a repeated key in 3DES, and if so, we continue with the test.
|
||
if ((rc == -1) && (cm->cipher == cc_cipher3DES)) {
|
||
rc = verify_and_ok_duplicate_key(key, keylen) ? 0 : rc;
|
||
}
|
||
|
||
return (rc == 0) ? CC_SUCCESS : CC_FAILURE;
|
||
}
|
||
|
||
int cc_symmetric_setup_tweaked(cc_ciphermode_descriptor cm,
|
||
const void *key,
|
||
size_t keylen,
|
||
const void *tweak,
|
||
CC_UNUSED const void *iv,
|
||
cc_symmetric_context_p ctx)
|
||
{
|
||
switch (cm->mode) {
|
||
case cc_ModeXTS:
|
||
if (cm->ciphermode.xts->init(cm->ciphermode.xts, ctx->ctx.xts, keylen, key, tweak) == 0) {
|
||
return CC_SUCCESS;
|
||
}
|
||
}
|
||
return CC_FAILURE;
|
||
}
|
||
|
||
int cc_symmetric_setup_authenticated(cc_ciphermode_descriptor cm,
|
||
const void *key,
|
||
size_t keylen,
|
||
const void *iv,
|
||
size_t iv_len,
|
||
const void *adata,
|
||
size_t adata_len,
|
||
const void *adata2,
|
||
size_t adata2_len,
|
||
size_t data_len,
|
||
size_t tag_len,
|
||
cc_symmetric_context_p ctx)
|
||
{
|
||
int rc;
|
||
switch (cm->mode) {
|
||
case cc_ModeGCM:
|
||
rc = ccgcm_init(cm->ciphermode.gcm, ctx->ctx.gcm, keylen, key);
|
||
if (rc == 0)
|
||
rc = ccgcm_set_iv(cm->ciphermode.gcm, ctx->ctx.gcm, iv_len, iv);
|
||
if (rc == 0)
|
||
rc = ccgcm_aad(cm->ciphermode.gcm, ctx->ctx.gcm, adata_len, adata);
|
||
break;
|
||
case cc_ModeCCM:
|
||
rc = ccccm_init(cm->ciphermode.ccm, ctx->ctx.ccm, keylen, key);
|
||
if (rc == 0)
|
||
rc =
|
||
ccccm_set_iv(cm->ciphermode.ccm, ctx->ctx.ccm, ctx->xtra_ctx.ccm_nonce, iv_len, iv, tag_len, adata_len, data_len);
|
||
if (rc == 0)
|
||
rc = ccccm_cbcmac(cm->ciphermode.ccm, ctx->ctx.ccm, ctx->xtra_ctx.ccm_nonce, adata_len, adata);
|
||
break;
|
||
case cc_ModeSIV:
|
||
rc = ccsiv_init(cm->ciphermode.siv, ctx->ctx.siv, keylen, key);
|
||
if (rc == 0)
|
||
rc = ccsiv_aad(cm->ciphermode.siv, ctx->ctx.siv, adata_len, adata);
|
||
if (rc == 0)
|
||
rc = ccsiv_aad(cm->ciphermode.siv, ctx->ctx.siv, adata2_len, adata2);
|
||
if (rc == 0)
|
||
rc = ccsiv_set_nonce(cm->ciphermode.siv, ctx->ctx.siv, iv_len, iv);
|
||
break;
|
||
case cc_ModeSIV_HMAC:
|
||
rc = ccsiv_hmac_init(cm->ciphermode.siv_hmac, ctx->ctx.siv_hmac, keylen, key, tag_len);
|
||
if (adata_len == 0){
|
||
is(ccsiv_hmac_aad(cm->ciphermode.siv_hmac, ctx->ctx.siv_hmac, adata_len, adata), CCMODE_AD_EMPTY, "Empty associated data not reported as error.");
|
||
}
|
||
if (rc == 0 && adata_len != 0)
|
||
rc = ccsiv_hmac_aad(cm->ciphermode.siv_hmac, ctx->ctx.siv_hmac, adata_len, adata);
|
||
if (rc == 0 && adata2_len != 0)
|
||
rc = ccsiv_hmac_aad(cm->ciphermode.siv_hmac, ctx->ctx.siv_hmac, adata2_len, adata2);
|
||
|
||
if (iv_len == 0){
|
||
is(ccsiv_hmac_set_nonce(cm->ciphermode.siv_hmac, ctx->ctx.siv_hmac, iv_len, iv), CCMODE_NONCE_EMPTY, "Empty nonce data not reported as error.");
|
||
}
|
||
if (rc == 0 && iv_len != 0)
|
||
rc = ccsiv_hmac_set_nonce(cm->ciphermode.siv_hmac, ctx->ctx.siv_hmac, iv_len, iv);
|
||
break;
|
||
|
||
default:
|
||
return CC_FAILURE;
|
||
}
|
||
return rc;
|
||
}
|
||
|
||
int cc_symmetric_crypt(cc_symmetric_context_p ctx, const void *iv, const void *in, void *out, size_t len)
|
||
{
|
||
int rc;
|
||
switch (ctx->mode_desc->mode) {
|
||
case cc_ModeECB:
|
||
rc = ctx->mode_desc->ciphermode.ecb->ecb(ctx->ctx.ecb, len / ctx->mode_desc->ciphermode.ecb->block_size, in, out);
|
||
break;
|
||
case cc_ModeCBC: {
|
||
cccbc_iv_decl(ctx->mode_desc->ciphermode.cbc->block_size, cbciv);
|
||
if ((rc = cccbc_set_iv(ctx->mode_desc->ciphermode.cbc, cbciv, iv))) {
|
||
return rc;
|
||
}
|
||
if ((rc = ctx->mode_desc->ciphermode.cbc->cbc(
|
||
ctx->ctx.cbc, cbciv, len / ctx->mode_desc->ciphermode.cbc->block_size, in, out))) {
|
||
return rc;
|
||
}
|
||
} break;
|
||
case cc_ModeCFB:
|
||
rc = ctx->mode_desc->ciphermode.cfb->cfb(ctx->ctx.cfb, len / ctx->mode_desc->ciphermode.cfb->block_size, in, out);
|
||
break;
|
||
case cc_ModeCTR:
|
||
rc = ctx->mode_desc->ciphermode.ctr->ctr(ctx->ctx.ctr, len / ctx->mode_desc->ciphermode.ctr->block_size, in, out);
|
||
break;
|
||
case cc_ModeOFB:
|
||
rc = ctx->mode_desc->ciphermode.ofb->ofb(ctx->ctx.ofb, len / ctx->mode_desc->ciphermode.ofb->block_size, in, out);
|
||
break;
|
||
case cc_ModeCFB8:
|
||
rc = ctx->mode_desc->ciphermode.cfb8->cfb8(ctx->ctx.cfb8, len / ctx->mode_desc->ciphermode.cfb8->block_size, in, out);
|
||
break;
|
||
case cc_ModeXTS: {
|
||
ccxts_tweak_decl(ctx->mode_desc->ciphermode.xts->tweak_size, xts_iv);
|
||
if ((rc = ccxts_set_tweak(ctx->mode_desc->ciphermode.xts, ctx->ctx.xts, xts_iv, iv))) {
|
||
return rc;
|
||
}
|
||
if (ctx->mode_desc->ciphermode.xts->xts(
|
||
ctx->ctx.xts, xts_iv, len / ctx->mode_desc->ciphermode.xts->block_size, in, out) == NULL) {
|
||
return -1;
|
||
}
|
||
} break;
|
||
case cc_ModeGCM:
|
||
rc =
|
||
ccgcm_update(ctx->mode_desc->ciphermode.gcm, ctx->ctx.gcm, len / ctx->mode_desc->ciphermode.gcm->block_size, in, out);
|
||
break;
|
||
case cc_ModeCCM:
|
||
rc = ccccm_update(ctx->mode_desc->ciphermode.ccm,
|
||
ctx->ctx.ccm,
|
||
ctx->xtra_ctx.ccm_nonce,
|
||
len / ctx->mode_desc->ciphermode.ccm->block_size,
|
||
in,
|
||
out);
|
||
break;
|
||
case cc_ModeSIV:
|
||
rc = ccsiv_crypt(ctx->mode_desc->ciphermode.siv, ctx->ctx.siv, len / ctx->mode_desc->ciphermode.siv->block_size, in, out);
|
||
break;
|
||
case cc_ModeSIV_HMAC:
|
||
rc = ccsiv_hmac_crypt(ctx->mode_desc->ciphermode.siv_hmac, ctx->ctx.siv_hmac, len, in, out);
|
||
break;
|
||
default:
|
||
return CC_FAILURE;
|
||
}
|
||
return rc;
|
||
}
|
||
|
||
void cc_symmetric_final(CC_UNUSED cc_symmetric_context_p ctx)
|
||
{
|
||
}
|
||
|
||
int cc_symmetric_authenticated_finalize(cc_symmetric_context_p ctx, char *tag, size_t tag_len)
|
||
{
|
||
int rc;
|
||
switch (ctx->mode_desc->mode) {
|
||
case cc_ModeGCM:
|
||
rc = ctx->mode_desc->ciphermode.gcm->finalize(ctx->ctx.gcm, tag_len, tag);
|
||
break;
|
||
case cc_ModeCCM:
|
||
rc = ctx->mode_desc->ciphermode.ccm->finalize(ctx->ctx.ccm, ctx->xtra_ctx.ccm_nonce, tag);
|
||
break;
|
||
default:
|
||
return CC_FAILURE;
|
||
}
|
||
return rc;
|
||
}
|
||
|
||
int cc_symmetric_oneshot(cc_ciphermode_descriptor cm,
|
||
const void *key,
|
||
size_t keylen,
|
||
const void *iv,
|
||
const void *in,
|
||
void *out,
|
||
size_t len)
|
||
{
|
||
int rc;
|
||
switch (cm->mode) {
|
||
case cc_ModeECB:
|
||
rc = ccecb_one_shot(cm->ciphermode.ecb, keylen, key, len / cm->ciphermode.ecb->block_size, in, out);
|
||
break;
|
||
case cc_ModeCBC:
|
||
rc = cccbc_one_shot(cm->ciphermode.cbc, keylen, key, iv, len / cm->ciphermode.cbc->block_size, in, out);
|
||
break;
|
||
case cc_ModeCFB:
|
||
rc = cccfb_one_shot(cm->ciphermode.cfb, keylen, key, iv, len / cm->ciphermode.cfb->block_size, in, out);
|
||
break;
|
||
case cc_ModeCTR:
|
||
rc = ccctr_one_shot(cm->ciphermode.ctr, keylen, key, iv, len / cm->ciphermode.ctr->block_size, in, out);
|
||
break;
|
||
case cc_ModeOFB:
|
||
rc = ccofb_one_shot(cm->ciphermode.ofb, keylen, key, iv, len / cm->ciphermode.ofb->block_size, in, out);
|
||
break;
|
||
case cc_ModeCFB8:
|
||
rc = cccfb8_one_shot(cm->ciphermode.cfb8, keylen, key, iv, len / cm->ciphermode.cfb8->block_size, in, out);
|
||
break;
|
||
default:
|
||
return CC_FAILURE;
|
||
}
|
||
return rc;
|
||
}
|
||
|
||
int cc_symmetric_reset(cc_symmetric_context_p ctx)
|
||
{
|
||
int rc;
|
||
switch (ctx->mode_desc->mode) {
|
||
case cc_ModeGCM:
|
||
rc = ccgcm_reset(ctx->mode_desc->ciphermode.gcm, ctx->ctx.gcm);
|
||
break;
|
||
case cc_ModeCCM:
|
||
rc = ccccm_reset(ctx->mode_desc->ciphermode.ccm, ctx->ctx.ccm, ctx->xtra_ctx.ccm_nonce);
|
||
break;
|
||
case cc_ModeSIV:
|
||
rc = ccsiv_reset(ctx->mode_desc->ciphermode.siv, ctx->ctx.siv);
|
||
break;
|
||
default:
|
||
rc = CC_FAILURE;
|
||
}
|
||
return rc;
|
||
}
|
||
|
||
size_t cc_symmetric_bloc_size(cc_ciphermode_descriptor cm)
|
||
{
|
||
size_t block_size = 0;
|
||
|
||
switch (cm->mode) {
|
||
case cc_ModeECB:
|
||
block_size = cm->ciphermode.ecb->block_size;
|
||
break;
|
||
case cc_ModeCBC:
|
||
block_size = cm->ciphermode.cbc->block_size;
|
||
break;
|
||
case cc_ModeCFB:
|
||
block_size = cm->ciphermode.cfb->block_size;
|
||
break;
|
||
case cc_ModeCTR:
|
||
block_size = cm->ciphermode.ctr->block_size;
|
||
break;
|
||
case cc_ModeOFB:
|
||
block_size = cm->ciphermode.ofb->block_size;
|
||
break;
|
||
case cc_ModeCFB8:
|
||
block_size = cm->ciphermode.cfb8->block_size;
|
||
break;
|
||
default:
|
||
return 0;
|
||
}
|
||
return block_size;
|
||
}
|