FEEAsymmetricContext.cpp [plain text]
#ifdef CRYPTKIT_CSP_ENABLE
#include "FEEAsymmetricContext.h"
#include "FEECSPUtils.h"
#include <security_cryptkit/falloc.h>
#include <CommonCrypto/CommonDigest.h>
static void validateFeedContext(
const Context &context)
{
uint32 blockSize = context.getInt(CSSM_ATTRIBUTE_BLOCK_SIZE);
if(blockSize != 0) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_BLOCK_SIZE);
}
CSSM_ENCRYPT_MODE cssmMode = context.getInt(CSSM_ATTRIBUTE_MODE);
if(cssmMode != 0) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE);
}
#if 0
CssmData *iv = context.get<CssmData>(CSSM_ATTRIBUTE_INIT_VECTOR);
if(iv != NULL) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_INIT_VECTOR);
}
#endif
CSSM_PADDING padding = context.getInt(CSSM_ATTRIBUTE_PADDING);
if(padding != 0) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING);
}
}
CryptKit::FEEDContext::~FEEDContext()
{
if(mFeeFeed) {
feeFEEDFree(mFeeFeed);
mFeeFeed = NULL;
}
if(mPrivKey && mAllocdPrivKey) {
feePubKeyFree(mPrivKey);
}
if(mPubKey && mAllocdPubKey) {
feePubKeyFree(mPubKey);
}
mPrivKey = NULL;
mPubKey = NULL;
mInitFlag = false;
}
void CryptKit::FEEDContext::init(
const Context &context,
bool encoding)
{
if(mInitFlag && !opStarted()) {
return;
}
if(mPrivKey == NULL) {
assert(!opStarted());
mPrivKey = contextToFeeKey(context,
session(),
CSSM_ATTRIBUTE_KEY,
CSSM_KEYCLASS_PRIVATE_KEY,
CSSM_KEYUSE_ANY,
mAllocdPrivKey);
}
else {
assert(opStarted());
}
if(mPubKey == NULL) {
assert(!opStarted());
mPubKey = contextToFeeKey(context,
session(),
CSSM_ATTRIBUTE_PUBLIC_KEY,
CSSM_KEYCLASS_PUBLIC_KEY,
CSSM_KEYUSE_ANY,
mAllocdPubKey);
}
else {
assert(opStarted());
}
validateFeedContext(context);
if(mFeeFeed != NULL) {
assert(opStarted());
feeFEEDFree(mFeeFeed);
mFeeFeed = NULL;
}
mFeeFeed = feeFEEDNewWithPubKey(mPrivKey,
mPubKey,
encoding ? 1 : 0,
feeRandCallback,
&session());
if(mFeeFeed == NULL) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
}
unsigned plainBlockSize = feeFEEDPlainBlockSize(mFeeFeed);
unsigned cipherBlockSize = feeFEEDCipherBlockSize(mFeeFeed);
setup(encoding ? plainBlockSize : cipherBlockSize, encoding ? cipherBlockSize : plainBlockSize, false, true, BCM_ECB,
NULL); mInitFlag = true;
}
void CryptKit::FEEDContext::encryptBlock(
const void *plainText, size_t plainTextLen,
void *cipherText,
size_t &cipherTextLen, bool final)
{
feeReturn frtn;
unsigned actMoved;
assert(mFeeFeed != NULL);
frtn = feeFEEDEncryptBlock(mFeeFeed,
(unsigned char *)plainText,
(unsigned int)plainTextLen,
(unsigned char *)cipherText,
&actMoved,
final ? 1 : 0);
if(frtn) {
throwCryptKit(frtn, "feeFEEDEncryptBlock");
}
if(actMoved > cipherTextLen) {
CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
}
cipherTextLen = actMoved;
}
void CryptKit::FEEDContext::decryptBlock(
const void *cipherText, size_t cipherTextLen,
void *plainText,
size_t &plainTextLen, bool final)
{
feeReturn frtn;
unsigned actMoved;
assert(mFeeFeed != NULL);
frtn = feeFEEDDecryptBlock(mFeeFeed,
(unsigned char *)cipherText,
(unsigned int)inBlockSize(),
(unsigned char *)plainText,
&actMoved,
final ? 1 : 0);
if(frtn) {
throwCryptKit(frtn, "feeFEEDDecryptBlock");
}
if(actMoved > plainTextLen) {
CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
}
plainTextLen = actMoved;
}
#define BUFFER_DEBUG 0
#if BUFFER_DEBUG
#define bprintf(s) printf s
#else
#define bprintf(s)
#endif
size_t CryptKit::FEEDContext::inputSize(
size_t outSize) {
unsigned inSize;
if(encoding()) {
inSize = feeFEEDPlainTextSize(mFeeFeed, (unsigned int)outSize, 0);
}
else {
inSize = feeFEEDCipherTextSize(mFeeFeed, (unsigned int)outSize, 0);
}
if(inSize >= inBufSize()) {
inSize -= inBufSize();
}
unsigned inBlocks = (unsigned int)((inSize + inBlockSize()) / inBlockSize());
inSize = (unsigned int)(inBlocks * inBlockSize()) - 1;
bprintf(("--- FEEDContext::inputSize inSize 0x%x outSize 0x%x\n",
inSize, outSize));
return inSize;
}
size_t CryptKit::FEEDContext::outputSize(
bool final,
size_t inSize) {
size_t rtn;
if(encoding()) {
rtn = feeFEEDCipherTextSize(mFeeFeed, (unsigned int)(inSize + inBufSize()), final ? 1 : 0);
}
else {
rtn = feeFEEDPlainTextSize(mFeeFeed, (unsigned int)(inSize + inBufSize()), final ? 1 : 0);
}
bprintf(("--- FEEDContext::outputSize inSize 0x%x outSize 0x%x final %d\n",
inSize, rtn, final));
return rtn;
}
void CryptKit::FEEDContext::minimumProgress(
size_t &in,
size_t &out) {
if(encoding()) {
in = inBlockSize();
out = feeFEEDCipherBufSize(mFeeFeed, 0);
}
else {
in = feeFEEDCipherBufSize(mFeeFeed, 0);
out = outBlockSize();
}
assert(in >= inBufSize());
in -= inBufSize();
if(in == 0) {
in++;
}
bprintf(("--- FEEDContext::minProgres inSize 0x%x outSize 0x%x\n",
in, out));
}
CryptKit::FEEDExpContext::~FEEDExpContext()
{
if(mFeeFeedExp) {
feeFEEDExpFree(mFeeFeedExp);
mFeeFeedExp = NULL;
}
if(mFeeKey && mAllocdFeeKey) {
feePubKeyFree(mFeeKey);
}
mFeeKey = NULL;
mInitFlag = false;
}
void CryptKit::FEEDExpContext::init(
const Context &context,
bool encoding)
{
if(mInitFlag && !opStarted()) {
return;
}
CSSM_KEYCLASS keyClass;
CSSM_KEYUSE keyUse;
if(encoding) {
keyClass = CSSM_KEYCLASS_PUBLIC_KEY;
keyUse = CSSM_KEYUSE_ENCRYPT;
}
else {
keyClass = CSSM_KEYCLASS_PRIVATE_KEY;
keyUse = CSSM_KEYUSE_DECRYPT;
}
if(mFeeKey == NULL) {
assert(!opStarted());
mFeeKey = contextToFeeKey(context,
session(),
CSSM_ATTRIBUTE_KEY,
keyClass,
keyUse,
mAllocdFeeKey);
}
else {
assert(opStarted());
}
validateFeedContext(context);
if(mFeeFeedExp != NULL) {
assert(opStarted());
feeFEEDExpFree(mFeeFeedExp);
mFeeFeedExp = NULL;
}
mFeeFeedExp = feeFEEDExpNewWithPubKey(mFeeKey,
feeRandCallback,
&session());
if(mFeeFeedExp == NULL) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
}
unsigned plainBlockSize = feeFEEDExpPlainBlockSize(mFeeFeedExp);
unsigned cipherBlockSize = feeFEEDExpCipherBlockSize(mFeeFeedExp);
setup(encoding ? plainBlockSize : cipherBlockSize, encoding ? cipherBlockSize : plainBlockSize, false, true, BCM_ECB,
NULL); mInitFlag = true;
}
void CryptKit::FEEDExpContext::encryptBlock(
const void *plainText, size_t plainTextLen,
void *cipherText,
size_t &cipherTextLen, bool final)
{
feeReturn frtn;
unsigned actMoved;
assert(mFeeFeedExp != NULL);
frtn = feeFEEDExpEncryptBlock(mFeeFeedExp,
(unsigned char *)plainText,
(unsigned int)plainTextLen,
(unsigned char *)cipherText,
&actMoved,
final ? 1 : 0);
if(frtn) {
throwCryptKit(frtn, "feeFEEDExpEncryptBlock");
}
if(actMoved > cipherTextLen) {
CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
}
cipherTextLen = actMoved;
}
void CryptKit::FEEDExpContext::decryptBlock(
const void *cipherText, size_t cipherTextLen,
void *plainText,
size_t &plainTextLen, bool final)
{
feeReturn frtn;
unsigned actMoved;
assert(mFeeFeedExp != NULL);
frtn = feeFEEDExpDecryptBlock(mFeeFeedExp,
(unsigned char *)cipherText,
(unsigned int)inBlockSize(),
(unsigned char *)plainText,
&actMoved,
final ? 1 : 0);
if(frtn) {
throwCryptKit(frtn, "feeFEEDExpDecryptBlock");
}
if(actMoved > plainTextLen) {
CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
}
plainTextLen = actMoved;
}
static void int32ToBytes(
uint32_t i,
unsigned char *b)
{
for(int dex=3; dex>=0; dex--) {
b[dex] = i;
i >>= 8;
}
}
static feeReturn ecdhKdf(
const Context &context,
const unsigned char *Z,
unsigned ZLen,
CSSM_DATA *K)
{
const unsigned char *sharedInfo = NULL;
CSSM_SIZE sharedInfoLen = 0;
CssmData *salt = context.get<CssmData>(CSSM_ATTRIBUTE_SALT);
if(salt != NULL) {
sharedInfo = (const unsigned char *)salt->Data;
sharedInfoLen = salt->Length;
}
unsigned char *outp = K->Data;
CSSM_SIZE bytesToGo = K->Length;
CC_SHA1_CTX sha1;
uint32_t counter = 1;
uint8 counterBytes[4];
unsigned char digOut[CC_SHA1_DIGEST_LENGTH];
do {
CC_SHA1_Init(&sha1);
CC_SHA1_Update(&sha1, Z, ZLen);
int32ToBytes(counter, counterBytes);
CC_SHA1_Update(&sha1, counterBytes, 4);
if(sharedInfoLen) {
CC_SHA1_Update(&sha1, sharedInfo, (CC_LONG)sharedInfoLen);
}
CC_SHA1_Final(digOut, &sha1);
unsigned toMove = CC_SHA1_DIGEST_LENGTH;
if(toMove > bytesToGo) {
toMove = (unsigned int)bytesToGo;
}
memmove(outp, digOut, toMove);
counter++;
outp += toMove;
bytesToGo -= toMove;
} while(bytesToGo);
return FR_Success;
}
void CryptKit::DeriveKey_ECDH (
const Context &context,
CSSM_ALGORITHMS algId,
const CssmData &Param, CSSM_DATA *keyData, AppleCSPSession &session)
{
bool mallocdPrivKey;
size_t privSize;
feePubKey privKey = contextToFeeKey(context, session, CSSM_ATTRIBUTE_KEY,
CSSM_KEYCLASS_PRIVATE_KEY, CSSM_KEYUSE_DERIVE, mallocdPrivKey);
if(privKey == NULL) {
CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY);
}
privSize = (feePubKeyBitsize(privKey) + 7) / 8;
if((algId == CSSM_ALGID_ECDH) & (privSize != keyData->Length)) {
CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
}
bool mallocdPubKey = false;
feePubKey pubKey = NULL;
if(Param.Data == NULL) {
pubKey = contextToFeeKey(context, session, CSSM_ATTRIBUTE_PUBLIC_KEY,
CSSM_KEYCLASS_PUBLIC_KEY, CSSM_KEYUSE_DERIVE, mallocdPubKey);
}
if((pubKey == NULL) && (Param.Data == NULL)) {
errorLog0("DeriveKey_ECDH: no pub_key\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
}
unsigned char *output = NULL;
unsigned outputLen = 0;
feeReturn frtn = feePubKeyECDH(privKey, pubKey,
(const unsigned char *)Param.Data, (unsigned)Param.Length,
&output, &outputLen);
if(frtn) {
goto errOut;
}
switch(algId) {
case CSSM_ALGID_ECDH:
if(outputLen != keyData->Length) {
errorLog0("DeriveKey_ECDH: length mismatch\n");
frtn = FR_Internal;
break;
}
memmove(keyData->Data, output, outputLen);
break;
case CSSM_ALGID_ECDH_X963_KDF:
frtn = ecdhKdf(context, output, outputLen, keyData);
break;
default:
frtn = FR_Internal;
break;
}
errOut:
if(mallocdPrivKey) {
feePubKeyFree(privKey);
}
if(mallocdPubKey) {
feePubKeyFree(pubKey);
}
if(output != NULL) {
ffree(output);
}
if(frtn) {
throwCryptKit(frtn, NULL);
}
}
#endif