blob: 4765b0a09514b9c94e8acc4398c7f616099b6244 [file] [log] [blame]
/*
* xfm.c
*
* Crypto transform implementation
*
* David A. McGrew
* Cisco Systems, Inc.
*/
#include "cryptoalg.h"
#include "aes_cbc.h"
#include "hmac.h"
#include "crypto_kernel.h" /* for crypto_get_random() */
#define KEY_LEN 16
#define ENC_KEY_LEN 16
#define MAC_KEY_LEN 16
#define IV_LEN 16
#define TAG_LEN 12
#define MAX_EXPAND 27
err_status_t
aes_128_cbc_hmac_sha1_96_func(void *key,
void *clear,
unsigned clear_len,
void *iv,
void *opaque,
unsigned *opaque_len,
void *auth_tag) {
aes_cbc_ctx_t aes_ctx;
hmac_ctx_t hmac_ctx;
unsigned char enc_key[ENC_KEY_LEN];
unsigned char mac_key[MAC_KEY_LEN];
err_status_t status;
/* check if we're doing authentication only */
if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) {
/* perform authentication only */
} else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) {
/*
* bad parameter - we expect either all three pointers to be NULL,
* or none of those pointers to be NULL
*/
return err_status_fail;
} else {
/* derive encryption and authentication keys from the input key */
status = hmac_init(&hmac_ctx, key, KEY_LEN);
if (status) return status;
status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key);
if (status) return status;
status = hmac_init(&hmac_ctx, key, KEY_LEN);
if (status) return status;
status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key);
if (status) return status;
/* perform encryption and authentication */
/* set aes key */
status = aes_cbc_context_init(&aes_ctx, key, direction_encrypt);
if (status) return status;
/* set iv */
status = crypto_get_random(iv, IV_LEN);
if (status) return status;
status = aes_cbc_set_iv(&aes_ctx, iv);
/* encrypt the opaque data */
status = aes_cbc_nist_encrypt(&aes_ctx, opaque, opaque_len);
if (status) return status;
/* authenticate clear and opaque data */
status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN);
if (status) return status;
status = hmac_start(&hmac_ctx);
if (status) return status;
status = hmac_update(&hmac_ctx, clear, clear_len);
if (status) return status;
status = hmac_compute(&hmac_ctx, opaque, *opaque_len, TAG_LEN, auth_tag);
if (status) return status;
}
return err_status_ok;
}
err_status_t
aes_128_cbc_hmac_sha1_96_inv(void *key,
void *clear,
unsigned clear_len,
void *iv,
void *opaque,
unsigned *opaque_len,
void *auth_tag) {
aes_cbc_ctx_t aes_ctx;
hmac_ctx_t hmac_ctx;
unsigned char enc_key[ENC_KEY_LEN];
unsigned char mac_key[MAC_KEY_LEN];
unsigned char tmp_tag[TAG_LEN];
unsigned char *tag = auth_tag;
err_status_t status;
int i;
/* check if we're doing authentication only */
if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) {
/* perform authentication only */
} else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) {
/*
* bad parameter - we expect either all three pointers to be NULL,
* or none of those pointers to be NULL
*/
return err_status_fail;
} else {
/* derive encryption and authentication keys from the input key */
status = hmac_init(&hmac_ctx, key, KEY_LEN);
if (status) return status;
status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key);
if (status) return status;
status = hmac_init(&hmac_ctx, key, KEY_LEN);
if (status) return status;
status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key);
if (status) return status;
/* perform encryption and authentication */
/* set aes key */
status = aes_cbc_context_init(&aes_ctx, key, direction_decrypt);
if (status) return status;
/* set iv */
status = rand_source_get_octet_string(iv, IV_LEN);
if (status) return status;
status = aes_cbc_set_iv(&aes_ctx, iv);
/* encrypt the opaque data */
status = aes_cbc_nist_decrypt(&aes_ctx, opaque, opaque_len);
if (status) return status;
/* authenticate clear and opaque data */
status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN);
if (status) return status;
status = hmac_start(&hmac_ctx);
if (status) return status;
status = hmac_update(&hmac_ctx, clear, clear_len);
if (status) return status;
status = hmac_compute(&hmac_ctx, opaque, *opaque_len, TAG_LEN, tmp_tag);
if (status) return status;
/* compare the computed tag with the one provided as input */
for (i=0; i < TAG_LEN; i++)
if (tmp_tag[i] != tag[i])
return err_status_auth_fail;
}
return err_status_ok;
}
#define ENC 1
#undef DEBUG
#define DEBUG 0
err_status_t
aes_128_cbc_hmac_sha1_96_enc(void *key,
const void *clear,
unsigned clear_len,
void *iv,
void *opaque,
unsigned *opaque_len) {
aes_cbc_ctx_t aes_ctx;
hmac_ctx_t hmac_ctx;
unsigned char enc_key[ENC_KEY_LEN];
unsigned char mac_key[MAC_KEY_LEN];
unsigned char *auth_tag;
err_status_t status;
/* check if we're doing authentication only */
if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) {
/* perform authentication only */
} else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) {
/*
* bad parameter - we expect either all three pointers to be NULL,
* or none of those pointers to be NULL
*/
return err_status_fail;
} else {
#if DEBUG
printf("ENC using key %s\n", octet_string_hex_string(key, KEY_LEN));
#endif
/* derive encryption and authentication keys from the input key */
status = hmac_init(&hmac_ctx, key, KEY_LEN);
if (status) return status;
status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key);
if (status) return status;
status = hmac_init(&hmac_ctx, key, KEY_LEN);
if (status) return status;
status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key);
if (status) return status;
/* perform encryption and authentication */
/* set aes key */
status = aes_cbc_context_init(&aes_ctx, key, direction_encrypt);
if (status) return status;
/* set iv */
status = rand_source_get_octet_string(iv, IV_LEN);
if (status) return status;
status = aes_cbc_set_iv(&aes_ctx, iv);
if (status) return status;
#if DEBUG
printf("plaintext len: %d\n", *opaque_len);
printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN));
printf("plaintext: %s\n", octet_string_hex_string(opaque, *opaque_len));
#endif
#if ENC
/* encrypt the opaque data */
status = aes_cbc_nist_encrypt(&aes_ctx, opaque, opaque_len);
if (status) return status;
#endif
#if DEBUG
printf("ciphertext len: %d\n", *opaque_len);
printf("ciphertext: %s\n", octet_string_hex_string(opaque, *opaque_len));
#endif
/*
* authenticate clear and opaque data, then write the
* authentication tag to the location immediately following the
* ciphertext
*/
status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN);
if (status) return status;
status = hmac_start(&hmac_ctx);
if (status) return status;
status = hmac_update(&hmac_ctx, clear, clear_len);
if (status) return status;
#if DEBUG
printf("hmac input: %s\n",
octet_string_hex_string(clear, clear_len));
#endif
auth_tag = (unsigned char *)opaque;
auth_tag += *opaque_len;
status = hmac_compute(&hmac_ctx, opaque, *opaque_len, TAG_LEN, auth_tag);
if (status) return status;
#if DEBUG
printf("hmac input: %s\n",
octet_string_hex_string(opaque, *opaque_len));
#endif
/* bump up the opaque_len to reflect the authentication tag */
*opaque_len += TAG_LEN;
#if DEBUG
printf("prot data len: %d\n", *opaque_len);
printf("prot data: %s\n", octet_string_hex_string(opaque, *opaque_len));
#endif
}
return err_status_ok;
}
err_status_t
aes_128_cbc_hmac_sha1_96_dec(void *key,
const void *clear,
unsigned clear_len,
void *iv,
void *opaque,
unsigned *opaque_len) {
aes_cbc_ctx_t aes_ctx;
hmac_ctx_t hmac_ctx;
unsigned char enc_key[ENC_KEY_LEN];
unsigned char mac_key[MAC_KEY_LEN];
unsigned char tmp_tag[TAG_LEN];
unsigned char *auth_tag;
unsigned ciphertext_len;
err_status_t status;
int i;
/* check if we're doing authentication only */
if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) {
/* perform authentication only */
} else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) {
/*
* bad parameter - we expect either all three pointers to be NULL,
* or none of those pointers to be NULL
*/
return err_status_fail;
} else {
#if DEBUG
printf("DEC using key %s\n", octet_string_hex_string(key, KEY_LEN));
#endif
/* derive encryption and authentication keys from the input key */
status = hmac_init(&hmac_ctx, key, KEY_LEN);
if (status) return status;
status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key);
if (status) return status;
status = hmac_init(&hmac_ctx, key, KEY_LEN);
if (status) return status;
status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key);
if (status) return status;
#if DEBUG
printf("prot data len: %d\n", *opaque_len);
printf("prot data: %s\n", octet_string_hex_string(opaque, *opaque_len));
#endif
/*
* set the protected data length to that of the ciphertext, by
* subtracting out the length of the authentication tag
*/
ciphertext_len = *opaque_len - TAG_LEN;
#if DEBUG
printf("ciphertext len: %d\n", ciphertext_len);
#endif
/* verify the authentication tag */
/*
* compute the authentication tag for the clear and opaque data,
* and write it to a temporary location
*/
status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN);
if (status) return status;
status = hmac_start(&hmac_ctx);
if (status) return status;
status = hmac_update(&hmac_ctx, clear, clear_len);
if (status) return status;
#if DEBUG
printf("hmac input: %s\n",
octet_string_hex_string(clear, clear_len));
#endif
status = hmac_compute(&hmac_ctx, opaque, ciphertext_len, TAG_LEN, tmp_tag);
if (status) return status;
#if DEBUG
printf("hmac input: %s\n",
octet_string_hex_string(opaque, ciphertext_len));
#endif
/*
* compare the computed tag with the one provided as input (which
* immediately follows the ciphertext)
*/
auth_tag = (unsigned char *)opaque;
auth_tag += ciphertext_len;
#if DEBUG
printf("auth_tag: %s\n", octet_string_hex_string(auth_tag, TAG_LEN));
printf("tmp_tag: %s\n", octet_string_hex_string(tmp_tag, TAG_LEN));
#endif
for (i=0; i < TAG_LEN; i++) {
if (tmp_tag[i] != auth_tag[i])
return err_status_auth_fail;
}
/* bump down the opaque_len to reflect the authentication tag */
*opaque_len -= TAG_LEN;
/* decrypt the confidential data */
status = aes_cbc_context_init(&aes_ctx, key, direction_decrypt);
if (status) return status;
status = aes_cbc_set_iv(&aes_ctx, iv);
if (status) return status;
#if DEBUG
printf("ciphertext: %s\n", octet_string_hex_string(opaque, *opaque_len));
printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN));
#endif
#if ENC
status = aes_cbc_nist_decrypt(&aes_ctx, opaque, &ciphertext_len);
if (status) return status;
#endif
#if DEBUG
printf("plaintext len: %d\n", ciphertext_len);
printf("plaintext: %s\n",
octet_string_hex_string(opaque, ciphertext_len));
#endif
/* indicate the length of the plaintext */
*opaque_len = ciphertext_len;
}
return err_status_ok;
}
cryptoalg_ctx_t cryptoalg_ctx = {
aes_128_cbc_hmac_sha1_96_enc,
aes_128_cbc_hmac_sha1_96_dec,
KEY_LEN,
IV_LEN,
TAG_LEN,
MAX_EXPAND,
};
cryptoalg_t cryptoalg = &cryptoalg_ctx;
#define NULL_TAG_LEN 12
err_status_t
null_enc(void *key,
const void *clear,
unsigned clear_len,
void *iv,
void *opaque,
unsigned *opaque_len) {
int i;
unsigned char *auth_tag;
unsigned char *init_vec = iv;
/* check if we're doing authentication only */
if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) {
/* perform authentication only */
} else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) {
/*
* bad parameter - we expect either all three pointers to be NULL,
* or none of those pointers to be NULL
*/
return err_status_fail;
} else {
#if DEBUG
printf("NULL ENC using key %s\n", octet_string_hex_string(key, KEY_LEN));
printf("NULL_TAG_LEN: %d\n", NULL_TAG_LEN);
printf("plaintext len: %d\n", *opaque_len);
#endif
for (i=0; i < IV_LEN; i++)
init_vec[i] = i + (i * 16);
#if DEBUG
printf("iv: %s\n",
octet_string_hex_string(iv, IV_LEN));
printf("plaintext: %s\n",
octet_string_hex_string(opaque, *opaque_len));
#endif
auth_tag = opaque;
auth_tag += *opaque_len;
for (i=0; i < NULL_TAG_LEN; i++)
auth_tag[i] = i + (i * 16);
*opaque_len += NULL_TAG_LEN;
#if DEBUG
printf("protected data len: %d\n", *opaque_len);
printf("protected data: %s\n",
octet_string_hex_string(opaque, *opaque_len));
#endif
}
return err_status_ok;
}
err_status_t
null_dec(void *key,
const void *clear,
unsigned clear_len,
void *iv,
void *opaque,
unsigned *opaque_len) {
unsigned char *auth_tag;
/* check if we're doing authentication only */
if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) {
/* perform authentication only */
} else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) {
/*
* bad parameter - we expect either all three pointers to be NULL,
* or none of those pointers to be NULL
*/
return err_status_fail;
} else {
#if DEBUG
printf("NULL DEC using key %s\n", octet_string_hex_string(key, KEY_LEN));
printf("protected data len: %d\n", *opaque_len);
printf("protected data: %s\n",
octet_string_hex_string(opaque, *opaque_len));
#endif
auth_tag = opaque;
auth_tag += (*opaque_len - NULL_TAG_LEN);
#if DEBUG
printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN));
#endif
*opaque_len -= NULL_TAG_LEN;
#if DEBUG
printf("plaintext len: %d\n", *opaque_len);
printf("plaintext: %s\n",
octet_string_hex_string(opaque, *opaque_len));
#endif
}
return err_status_ok;
}
cryptoalg_ctx_t null_cryptoalg_ctx = {
null_enc,
null_dec,
KEY_LEN,
IV_LEN,
NULL_TAG_LEN,
MAX_EXPAND,
};
cryptoalg_t null_cryptoalg = &null_cryptoalg_ctx;
int
cryptoalg_get_id(cryptoalg_t c) {
if (c == cryptoalg)
return 1;
return 0;
}
cryptoalg_t
cryptoalg_find_by_id(int id) {
switch(id) {
case 1:
return cryptoalg;
default:
break;
}
return 0;
}