aes_cbc_crypt.c revision b1af77f0b8cb4440b82cc201238074bf521094ed
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include "aes_cbc_crypt.h"
#include "aes_impl.h"
#ifndef _KERNEL
#include <limits.h>
#include <strings.h>
#endif /* !_KERNEL */
crypto_data_t *);
static void
static void
static int
crypto_data_t *out);
/*
* Initialize by setting iov_or_mp to point to the current iovec or mp,
* and by setting current_offset to an offset within the current iovec or mp .
*/
static void
{
case CRYPTO_DATA_RAW:
break;
case CRYPTO_DATA_UIO: {
;
*current_offset = offset;
break;
}
case CRYPTO_DATA_MBLK: {
;
*current_offset = offset;
break;
}
} /* end switch */
}
/*
* Get pointers for where in the output to copy a block of encrypted or
* decrypted data. The iov_or_mp argument stores a pointer to the current
* iovec or mp, and offset stores an offset into the current iovec or mp.
*/
static void
{
case CRYPTO_DATA_RAW: {
offset = *current_offset;
/* one AES block fits */
*out_data_1_len = amt;
*out_data_2 = NULL;
}
break;
}
case CRYPTO_DATA_UIO: {
uint8_t *p;
offset = *current_offset;
*out_data_1 = p;
/* can fit one AES block into this iov */
*out_data_1_len = amt;
*out_data_2 = NULL;
} else {
/* one AES block spans two iovecs */
return;
vec_idx++;
}
break;
}
case CRYPTO_DATA_MBLK: {
uint8_t *p;
offset = *current_offset;
*out_data_1 = p;
/* can fit one AES block into this mblk */
*out_data_1_len = amt;
*out_data_2 = NULL;
} else {
/* one AES block spans two mblks */
return;
}
break;
}
} /* end switch */
}
static int
{
/* EXPORT DELETE START */
void *iov_or_mp;
/* accumulate bytes here and return */
length);
return (0);
}
do {
/* Unprocessed data from last call. */
if (ctx->ac_remainder_len > 0) {
return (1);
} else {
}
/* don't write on the plaintext */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
}
/*
* XOR the previous cipher block or IV with the
* current clear block. Check for alignment.
*/
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
}
if (ctx->ac_remainder_len > 0) {
need);
}
} else {
/* copy block to where it belongs */
if (out_data_2 != NULL) {
}
/* update offset */
}
/* Update pointer to next block of data to be processed. */
if (ctx->ac_remainder_len != 0) {
ctx->ac_remainder_len = 0;
} else {
datap += AES_BLOCK_LEN;
}
/* Incomplete last block. */
goto out;
}
} while (remainder > 0);
out:
/*
* Save the last encrypted block in the context - but only for
* the CBC mode of operation.
*/
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
}
/* EXPORT DELETE END */
return (0);
}
/*
* Encrypt multiple blocks of data.
*/
/* ARGSUSED */
int
{
out));
out));
}
/* ARGSUSED */
static int
{
/* EXPORT DELETE START */
void *iov_or_mp;
/* accumulate bytes here and return */
length);
return (0);
}
do {
/* Unprocessed data from last call. */
if (ctx->ac_remainder_len > 0) {
return (1);
} else {
}
/* Save current ciphertext block */
/* LINTED: pointer alignment */
ctx);
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
/* LINTED: pointer alignment */
}
}
} else {
}
/*
* XOR the previous cipher block or IV with the
* currently decrypted block. Check for alignment.
*/
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
/* LINTED: pointer alignment */
}
/* copy temporary block to where it belongs */
if (out_data_2 != NULL) {
}
/* update offset */
} else if (ctx->ac_remainder_len > 0) {
/* copy temporary block to where it belongs */
}
/* Update pointer to next block of data to be processed. */
if (ctx->ac_remainder_len != 0) {
ctx->ac_remainder_len = 0;
} else {
datap += AES_BLOCK_LEN;
}
/* Incomplete last block. */
return (0);
}
} while (remainder > 0);
/* EXPORT DELETE END */
return (0);
}
/*
* Decrypt multiple blocks of data.
*/
int
{
out));
out));
}
/* ARGSUSED */
int
{
/* EXPORT DELETE START */
int i;
void *iov_or_mp;
return (CRYPTO_ARGUMENTS_BAD);
/* ac_iv is the counter block */
(uint8_t *)counter_block);
/* copy remainder to temporary buffer */
/* XOR with counter block */
for (i = 0; i < ctx->ac_remainder_len; i++) {
}
/* copy temporary block to where it belongs */
if (out_data_2 != NULL) {
}
ctx->ac_remainder_len = 0;
/* EXPORT DELETE END */
return (0);
}
/*
* Encrypt and decrypt multiple blocks of data in counter mode.
* Encrypt multiple blocks of data in CCM mode. Decrypt for CCM mode
* is done in another function.
*/
/* ARGSUSED */
int
{
/* EXPORT DELETE START */
void *iov_or_mp;
#ifdef _LITTLE_ENDIAN
uint8_t *p;
#endif
/* accumulate bytes here and return */
length);
return (0);
}
}
do {
/* Unprocessed data from last call. */
if (ctx->ac_remainder_len > 0) {
return (1);
} else {
}
/* don't write on the plaintext */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
}
/*
* do CBC MAC
*
* XOR the previous cipher block current clear block.
* mac_buf always contain previous cipher block.
*/
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
}
/* ac_cb is the counter block */
(uint8_t *)counter_block);
/*
* Increment counter. Counter bits are confined
* to the bottom 64 bits of the counter block.
*/
#ifdef _LITTLE_ENDIAN
(uint64_t)p[7]);
#endif
counter++;
#ifdef _LITTLE_ENDIAN
(uint64_t)p[7]);
#endif
/*
* XOR the previous cipher block or IV with the
* current clear block. Check for alignment.
*/
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
}
if (ctx->ac_remainder_len > 0) {
need);
}
} else {
/* copy block to where it belongs */
if (out_data_2 != NULL) {
}
/* update offset */
}
/* Update pointer to next block of data to be processed. */
if (ctx->ac_remainder_len != 0) {
ctx->ac_remainder_len = 0;
} else {
datap += AES_BLOCK_LEN;
}
/* Incomplete last block. */
goto out;
}
} while (remainder > 0);
out:
/* EXPORT DELETE END */
return (0);
}
/*
* The following function should be call at encrypt or decrypt init time
* for AES CCM mode.
*/
int
{
/* EXPORT DELETE START */
size_t encoded_a_len = 0;
/*
* Format the 1st block for CBC-MAC and construct the
* 1st counter block.
*
* aes_ctx->ac_iv is used for storing the counter block
* mac_buf will store b0 at this time.
*/
/* The IV for CBC MAC for AES CCM mode is always zero */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
/* encrypt the nonce */
/* take care of the associated data, if any */
if (auth_data_len == 0) {
return (0);
}
/* 1st block: it contains encoded associated data, and some data */
if (processed > auth_data_len) {
/* in case auth_data is very small */
}
/* xor with previous buffer */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
if (remainder == 0) {
/* a small amount of associated data, it's all done now */
return (0);
}
do {
if (remainder < AES_BLOCK_LEN) {
/*
* There's not a block full of data, pad rest of
* buffer with zero
*/
remainder = 0;
} else {
}
/* xor with previous buffer */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
} while (remainder > 0);
/* EXPORT DELETE END */
return (0);
}
void
{
/* EXPORT DELETE START */
int i;
/* first counter block start with index 0 */
counter = 0;
(uint8_t *)counter_block);
/* calculate XOR of MAC with first counter block */
for (i = 0; i < ctx->ac_ccm_mac_len; i++) {
}
/* EXPORT DELETE END */
}
/* ARGSUSED */
int
{
/* EXPORT DELETE START */
void *iov_or_mp;
int i;
return (CRYPTO_ARGUMENTS_BAD);
}
/*
* When we get here, the number of bytes of payload processed
* plus whatever data remains, if any,
* should be the same as the number of bytes that's being
* passed in the argument during init time.
*/
!= (ctx->ac_ccm_data_len)) {
return (CRYPTO_DATA_LEN_RANGE);
}
if (ctx->ac_remainder_len > 0) {
/* copy remainder to temporary buffer */
/* calculate the CBC MAC */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
/* calculate the counter mode */
(uint8_t *)counter_block);
/* copy remainder to temporary buffer */
/* XOR with counter block */
for (i = 0; i < ctx->ac_remainder_len; i++) {
}
}
/* Calculate the CCM MAC */
if (ctx->ac_remainder_len > 0) {
/* copy temporary block to where it belongs */
if (out_data_2 == NULL) {
/* everything will fit in out_data_1 */
} else {
} else {
/* mac will be in out_data_2 */
} else {
= out_data_1_len -
/*
* part of mac in will be in
* out_data_1, part of the mac will be
* in out_data_2
*/
}
}
}
} else {
/* copy block to where it belongs */
if (out_data_2 != NULL) {
}
}
ctx->ac_remainder_len = 0;
/* EXPORT DELETE END */
return (0);
}
int
{
/* EXPORT DELETE START */
uint8_t q;
/*
* Check the length of the MAC. Only valid length
* lengths for the MAC are: 4, 6, 8, 10, 12, 14, 16
*/
return (CRYPTO_MECHANISM_PARAM_INVALID);
}
/* Check the nonce value. Valid values are 7, 8, 9, 10, 11, 12, 13 */
return (CRYPTO_MECHANISM_PARAM_INVALID);
}
/*
* If it is decrypt, need to make sure size of ciphertext is at least
* bigger than MAC len
*/
return (CRYPTO_MECHANISM_PARAM_INVALID);
}
/*
* Check to make sure the length of the payload is within the
* range of values allowed by q
*/
if (q < 8) {
} else {
}
return (CRYPTO_MECHANISM_PARAM_INVALID);
}
/* EXPORT DELETE END */
return (0);
}
/*
* Format the first block used in CBC-MAC (B0) and the initial counter
* block based on formating functions and counter generation functions
* specified in RFC 3610 and NIST publication 800-38C, appendix A
*
* b0 is the first block used in CBC-MAC
* cb0 is the first counter block
*
* It's assumed that the arguments b0 and cb0 are preallocated AES blocks
*
*/
static void
{
/* EXPORT DELETE START */
uint8_t t, q, have_adata = 0;
int i, j, k;
#ifdef _LITTLE_ENDIAN
#endif /* _LITTLE_ENDIAN */
/* Construct the first octect of b0 */
if (authDataSize > 0) {
have_adata = 1;
}
/* copy the nonce value into b0 */
/* store the length of the payload into b0 */
}
/* format the counter block */
/* copy the nonce value into the counter block */
/* Create the mask for the counter field based on the size of nonce */
while (q-- > 0) {
mask |= (1ULL << q);
}
#ifdef _LITTLE_ENDIAN
#endif
/*
* During calculation, we start using counter block 1, we will
* set it up right here.
* We can just set the last byte to have the value 1, because
* even with the bigest nonce of 13, the last byte of the
* counter block will be used for the counter value.
*/
/* EXPORT DELETE END */
}
/*
* Encode the length of the associated data as
* specified in RFC 3610 and NIST publication 800-38C, appendix A
*/
static void
{
/* EXPORT DELETE START */
/* 0 < a < (2^16-2^8) */
*encoded_len = 2;
/* (2^16-2^8) <= a < 2^32 */
*encoded_len = 6;
encoded[0] = 0xff;
#ifdef _LP64
} else {
/* 2^32 <= a < 2^64 */
*encoded_len = 10;
encoded[0] = 0xff;
#endif /* _LP64 */
}
/* EXPORT DELETE END */
}
/*
* This will only deal with decrypting the last block of the input that
* might not be multiples of AES_BLOCK_LEN
*/
static void
{
/* EXPORT DELETE START */
int i;
/* XOR with counter block */
for (i = 0; i < ctx->ac_remainder_len; i++) {
}
/* EXPORT DELETE END */
}
/*
* This will decrypt the cipher text. However, the plaintext won't be
* returned to the caller. It will be returned when decrypt_final() is
* called if the MAC matches
*/
/* ARGSUSED */
static int
{
/* EXPORT DELETE START */
#ifdef _LITTLE_ENDIAN
uint8_t *p;
#endif /* _LITTLE_ENDIAN */
if (pm_len > 0) {
/*
* all ciphertext has been processed, just waiting for
* part of the value of the mac
*/
return (CRYPTO_DATA_LEN_RANGE);
}
return (0);
}
/*
* If we decrypt the given data, what total amount of data would
* have been decrypted?
*/
if (total_decrypted_len >
return (CRYPTO_DATA_LEN_RANGE);
}
if (total_decrypted_len > pt_len) {
/*
* part of the input will be the MAC, need to isolate that
* to be dealt with later. The left-over data in
* ac_remainder_len from last time will not be part of the
* MAC. Otherwise, it would have already been taken out
* when this call is made last time.
*/
/*
* since this is last of the ciphertext, will
* just decrypt with it here
*/
ctx->ac_remainder_len = 0;
return (0);
} else {
/* let rest of the code handle this */
}
/* accumulate bytes here and return */
length);
return (0);
}
do {
/* Unprocessed data from last call. */
if (ctx->ac_remainder_len > 0) {
return (1);
} else {
}
/* don't write on the plaintext */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
/* Calculate the counter mode, ac_cb is the counter block */
(uint8_t *)counter_block);
/*
* Increment counter.
* Counter bits are confined to the bottom 64 bits
*/
#ifdef _LITTLE_ENDIAN
(uint64_t)p[7]);
#endif
counter++;
#ifdef _LITTLE_ENDIAN
(uint64_t)p[7]);
#endif
/* XOR with the ciphertext */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
/* Copy the plaintext to the "holding buffer" */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
/* Update pointer to next block of data to be processed. */
if (ctx->ac_remainder_len != 0) {
ctx->ac_remainder_len = 0;
} else {
datap += AES_BLOCK_LEN;
}
/* Incomplete last block */
if (ctx->ac_ccm_processed_mac_len > 0) {
/*
* not expecting anymore ciphertext, just
* compute plaintext for the remaining input
*/
ctx->ac_remainder_len = 0;
}
goto out;
}
} while (remainder > 0);
out:
/* EXPORT DELETE END */
return (0);
}
int
{
/* EXPORT DELETE START */
void *iov_or_mp;
/* Make sure output buffer can fit all of the plaintext */
return (CRYPTO_ARGUMENTS_BAD);
}
while (mac_remain > 0) {
if (mac_remain < AES_BLOCK_LEN) {
mac_remain = 0;
} else {
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
pt += AES_BLOCK_LEN;
}
/* calculate the CBC MAC */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
/* LINTED: pointer alignment */
} else {
}
}
/* Calculate the CCM MAC */
/* compare the input CCM MAC value with what we calculated */
/* They don't match */
return (CRYPTO_DATA_LEN_RANGE);
} else {
if (out_data_2 != NULL) {
}
}
/* EXPORT DELETE END */
return (0);
}