aes_provider.c revision c54c769d4c1cde75dd28975fb0090a8f944651a6
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* Note, this file is cstyle and lint clean and should stay that way.
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
#include <k5-int.h>
#include <enc_provider.h>
#define BLOCK_SIZE 16
/*
* AES encrypt using CipherText Stealing mode built on top of CBC mode. CBC is
* currently support CTS while CBC is supported. CBC as compared to ECB that
* was previously used allows crypto providers to do the crypto more
* efficiently. In addition there is a crypto card (SCA6000) that did not
* provide ECB mode so krb was unable to take advantage. If CTS mode is ever
* supported by the Solaris Cryptographic Framework then this code should be
* changed to use that.
*
* CTS is based on what is described in Schneier's Applied Cryptography and RFC
* 3962.
*/
#ifdef _KERNEL
/*ARGSUSED*/
{
int ret = 0;
int nblocks, partialamount;
/*
* nlobp = next to last output block pointer, lobp = last output block
* pointer
*/
char local_iv_data[BLOCK_SIZE];
/*
* This function updates ivec->data if the ivec is passed in so
* it better have a data pointer and a proper length.
*/
"ivec->data = %p ivec->length = %d",
goto cleanup;
}
}
/* number of input blocks including partial block */
/* get # of bytes in partially filled block */
/*
* Simple case:
*
* Use CBC for all plaintext blocks, all must be full, then swap
* last 2 ciphertext blocks to implement CTS. Note, CBC needs a
* non-NULL IV.
*/
} else {
}
/*
* XXX due to a bug in the previous version of this function,
* input data that was 1 block long was decrypted instead of
* encypted. The fix for that is in another CR so until then
* we'll continue the tradition for interop's sake.
*/
if (ret != 0) {
"k5_ef_crypto: error: ret = 0x%08x",
ret);
goto cleanup;
}
if (nblocks > 1) {
/*
* swap last 2 ciphertext blocks to implement CTS
*/
char tmp[BLOCK_SIZE];
}
} else {
/*
* Complex case:
*
* This implements CTS mode where there is > 1 block and the
* last block is partially filled Uses CBC mode in the kCF, then
* does some swapping.
*
* pt = plain text, ct = cipher text
*/
/* Note the iovec below is NOT the ivec in the crypto sense */
/* ct = ciphertext, pt = plaintext */
/* tmp_pt will provide 0 padding for last parital pt block */
/*
* made. Plaintext first.
*/
/*
* first iovec has all full blocks of pt.
*/
/* use full block input */
/*
* second iovec has the parital pt and 0 padding
*/
/*
* since the first iovec includes the last partial pt,
* set length to enough bytes to pad out to a full block
*/
/* setup ciphertext iovecs */
/*
* First iovec has almost all the ct but not the ct for the last
* partial pt with the padding. That will be stored in the
* secont ct iovec.
*/
/*
* Second iovec has the last ciphertext block
*/
/* This had better be AES CBC mode! */
} else {
}
/* encrypt using AES CBC */
if (ret != CRYPTO_SUCCESS) {
"crypto_encrypt: error: ret = 0x%08x",
ret);
goto cleanup;
}
/*
* Swap:
* copy the next to last ct to last partial output block (only
* the partial amount is copied).
*/
/*
* copy the last ct output block to next to last output block
*/
} /* end partial block processing */
/*
* The ivec is updated to allow the caller to chain ivecs. At this
* point I don't think any kernel callers are using this however the
* userland version of this function does it so this should be done in
* kernel for consistency's sake. This is not done for 1 block, got
* this from MIT. Note, the next to last output block is copied because
* it contains the last full block of cipher text.
*/
if (ret)
return (ret);
}
#else /* User Space */
/*ARGSUSED*/
{
krb5_error_code ret = 0;
int nblocks, partialamount;
/*
* nlobp = next to last output block pointer, lobp = last output block
* pointer
*/
char tmp_ivec[BLOCK_SIZE];
/*
* This function updates ivec->data if the ivec is passed in so
* it better have a data pointer and a proper length.
*/
goto cleanup;
}
}
/* number of input blocks including partial block */
/* get # of bytes in partially filled block */
goto cleanup;
goto cleanup;
} else {
}
/*
* Note, since CBC is assumed to be the underlying mode, this
* call to C_EncryptInit is setting the IV. The IV in use here
* is either the ivec passed in or a block of 0's.
*/
"krb5int_aes_encrypt: rv = 0x%x", rv);
goto cleanup;
}
/*
* Simple case:
*
* Use CBC for all plaintext blocks, all must be full, then swap
* last 2 ciphertext blocks to implement CTS.
*/
/*
* to int cast to pointer to long!!!
*/
&outlen);
"krb5int_aes_encrypt: rv = 0x%x", rv);
goto cleanup;
}
if (nblocks > 1) {
/*
* swap last 2 ciphertext blocks to implement CTS
*/
char tmp[BLOCK_SIZE];
}
} else {
/*
* Complex case:
*
* This implements CTS mode where there is > 1 block and the
* then does some swapping.
*
* pt = plain text, ct = cipher text
*/
/*
* encrypt from P0...Pn-1 using CBC, last block of output is Cn
* & C'
*/
&outlen);
"krb5int_aes_encrypt: rv = 0x%x", rv);
goto cleanup;
}
/* tmp_pt will provide 0 padding for last parital pt block */
/* copy Pn to tmp_pt which has 0 padding */
/* encrypt Pn with 0 padding, Cn & C' ivec, output is Cn-1 */
&outlen);
"krb5int_aes_encrypt: rv = 0x%x", rv);
goto cleanup;
}
/* copy Cn from next to last output block to last block */
/* copy Cn-1 from tmp_ct to next to last output block */
/* Close the crypto session, ignore the output */
goto cleanup;
}
/*
* The ivec is updated to allow the caller to chain ivecs, done for the
* am not sure why but I'm continuing the tradition from the MIT code.
* Note, the next to last output block is copied because it contains the
* last full block of cipher text.
*/
if (ret)
return (ret);
}
#endif /* _KERNEL */
/*
* AES Decrypt using CipherText Stealing mode built on top of CBC mode. See the
* krb5int_aes_encrypt() comments for the reason CBC is being used.
*/
#ifdef _KERNEL
/*ARGSUSED*/
{
krb5_error_code ret = 0;
int nblocks, partialamount;
char local_iv_data[BLOCK_SIZE];
/*
* This function updates ivec->data if the ivec is passed in so
* it better have a data pointer and a proper length.
*/
"ivec->data = %p ivec->length = %d",
goto cleanup;
}
}
/* number of input blocks including partial block */
/* get # of bytes in partially filled block */
} else {
}
/*
* nlibp = next to last input block pointer
* libp = last input block pointer
*/
/*
* Simple case:
*
* Swap last 2 ciphertext blocks (all must be full), then use
* CBC to implement CTS.
*/
if (nblocks > 1) {
/*
* swap last 2 ciphertext blocks to implement CTS
*/
char tmp[BLOCK_SIZE];
/* first save orig input data for later restore */
/* swap */
}
if (nblocks > 1) {
/* restore orig input data */
}
if (ret != 0) {
"k5_ef_crypto returned error: ret = 0x%08x",
ret);
goto cleanup;
}
} else {
/* pointers to Cn, Cn-1, Cn-2 CipherText */
long length;
/*
* Complex case:
*
* Decrypting in CTS where there is a partial block of
* ciphertext.
*/
/* setting pointers to CipherText for later use */
/* Cn - 1 */
/* Cn - 2 */
if (nblocks > 2) {
/* set length to include blocks C0 thru Cn-2 */
/*
* First decrypt C0 thru Cn-2 using CBC with the input
* ivec.
*/
if (ret != 0) {
"k5_ef_crypto: error: ret = 0x%08x",
ret);
goto cleanup;
}
}
/*
* Prepare to decrypt Cn-1 using a ivec of Cn with 0 padding.
*/
/* the tmp ivec data holds Cn with 0 padding */
/* decrypt 1 block */
length = BLOCK_SIZE;
/*
* Now decrypt using Cn-1 input, Cn + 0 padding for ivec, Pn &
* C' output
*/
if (ret != 0) {
"k5_ef_crypto: error: ret = 0x%08x",
ret);
goto cleanup;
}
/*
* tmp input data should hold Cn with C'
* Note, tmp_output_data contains Pn + C',
*/
/* copy Cn */
/* copy C' */
(BLOCK_SIZE - partialamount));
/* copy Pn in tmp output to output->data */
if (nblocks > 2) {
/* use Cn-2 as ivec */
} else {
/* use 0 as ivec because Cn-2 does not exist */
}
/*
* Now decrypt Cn + C' input, using either Cn-2 or 0 for ivec
* (set above), Pn-1 output.
*/
if (ret != 0) {
"k5_ef_crypto: error: ret = 0x%08x",
ret);
goto cleanup;
}
} /* end partial block processing */
/*
* The ivec is updated to allow the caller to chain ivecs. At this
* point I don't think any kernel callers are using this however the
* userland version of this function does it so this should be done in
* kernel for consistency's sake. This is not done for 1 block, got
* this from MIT.
*/
}
if (ret)
return (ret);
}
#else /* User Space */
/*ARGSUSED*/
{
krb5_error_code ret = 0;
int nblocks, partialamount;
char tmp_ivec[BLOCK_SIZE];
/*
* This function updates ivec->data if the ivec is passed in so
* it better have a data pointer and a proper length.
*/
goto cleanup;
}
}
/* number of input blocks including partial block */
/* get # of bytes in partially filled block */
goto cleanup;
goto cleanup;
}
} else {
}
/*
* nlibp = next to last input block pointer
* libp = last input block pointer
*/
/*
* Simple case:
*
* Swap last 2 ciphertext blocks (all must be full), then use
* CBC to implement CTS.
*/
if (nblocks > 1) {
/*
* swap last 2 ciphertext blocks to implement CTS
*/
char tmp[BLOCK_SIZE];
/*
* Note, the side effect with this is that we are
* modifying the input->data!
*/
/* first save orig input data for later restore */
} else {
return (KRB5_CRYPTO_INTERNAL);
}
/*
* Note, since CBC is assumed to be the underlying mode, this
* call to C_DecryptInit is setting the IV. The IV in use here
* is either the ivec passed in or a block of 0's. All calls to
* C_DecryptInit set the IV in this function.
*/
"krb5int_aes_decrypt: rv = 0x%x", rv);
goto cleanup;
}
/*
* to int cast to pointer to long!!!
*/
&outlen);
if (nblocks > 1) {
/* restore orig input data */
}
} else {
/* pointers to Cn, Cn-1, Cn-2 CipherText */
/*
* Complex case:
*
* Decrypting in CTS where there is a partial block of
* ciphertext.
*/
/* setting pointers to CipherText for later use */
/* Cn - 1 */
/* Cn - 2 */
if (nblocks > 2) {
"krb5int_aes_decrypt: rv = 0x%x", rv);
goto cleanup;
}
/* set length to include blocks C0 thru Cn-2 */
/*
* First decrypt C0 thru Cn-2 using CBC with the input
* ivec.
*/
&outlen);
goto cleanup;
}
/*
* Prepare to decrypt Cn-1 using a ivec of Cn with 0 padding.
*/
/* the tmp ivec data holds Cn with 0 padding */
/* decrypt 1 block */
length = BLOCK_SIZE;
/* set ivec to Cn with 0 padding */
"krb5int_aes_decrypt: rv = 0x%x", rv);
goto cleanup;
}
/*
* Now decrypt using Cn-1 input, Cn + 0 padding for ivec, Pn &
* C' output
*/
&outlen);
goto cleanup;
/*
* tmp input data should hold Cn with C'
* Note, tmp_output_data contains Pn + C',
*/
/* copy Cn */
/* copy C' */
(BLOCK_SIZE - partialamount));
/* copy Pn in tmp output to output->data last block */
if (nblocks > 2) {
/* use Cn-2 as ivec */
} else {
/*
* nblocks == 2
*
* Cn-2 does not exist so either use 0 if input ivec
* does not exist or use the input ivec.
*/
} else {
/* use original input ivec */
}
}
"krb5int_aes_decrypt: rv = 0x%x", rv);
goto cleanup;
}
/*
* Now decrypt Cn + C' input, using either Cn-2, original input
* ivec or 0 for ivec (set above), Pn-1 output.
*/
(BLOCK_SIZE + partialamount)),
&outlen);
goto cleanup;
} /* end partial block processing */
/*
* The ivec is updated to allow the caller to chain ivecs, done for the
* am not sure why but I'm continuing the tradition from the MIT code.
*/
}
if (ret)
return (ret);
}
#endif /* _KERNEL */
static krb5_error_code
{
krb5_error_code ret = 0;
return (KRB5_BAD_KEYSIZE);
return (KRB5_CRYPTO_INTERNAL);
#ifdef _KERNEL
#else
#endif /* _KERNEL */
return (ret);
}
/*ARGSUSED*/
static krb5_error_code
{
if (!state)
return (0);
return (ENOMEM);
return (0);
}
const struct krb5_enc_provider krb5int_enc_aes128 = {
16, 16,
};
const struct krb5_enc_provider krb5int_enc_aes256 = {
32, 32,
};