#include "ckconfig.h"
#if CRYPTKIT_SYMMETRIC_ENABLE
#include "feeDES.h"
#include "feeTypes.h"
#include "ckDES.h"
#include "falloc.h"
#include "feeDebug.h"
#include "feeFunctions.h"
#include "platform.h"
#include <stdlib.h>
#ifndef NULL
#define NULL ((void *)0)
#endif
typedef struct {
int blockMode;
unsigned char lastBlock[DES_BLOCK_SIZE_BYTES];
struct _desInst dinst;
} fdesInst;
static void feeDESInit(desInst dinst)
{
desinit(dinst, DES_MODE_STD); }
feeDES feeDESNewWithState(const unsigned char *state,
unsigned stateLen)
{
fdesInst *fdinst;
if(stateLen < FEE_DES_MIN_STATE_SIZE) {
return NULL;
}
fdinst = (fdesInst*) fmalloc(sizeof(fdesInst));
bzero(fdinst, sizeof(fdesInst));
feeDESInit(&fdinst->dinst);
feeDESSetState((feeDES)fdinst, state, stateLen);
return fdinst;
}
void feeDESFree(feeDES des)
{
memset(des, 0, sizeof(fdesInst));
ffree(des);
}
feeReturn feeDESSetState(feeDES des,
const unsigned char *state,
unsigned stateLen)
{
fdesInst *fdinst = (fdesInst*) des;
char Key[DES_KEY_SIZE_BYTES_EXTERNAL];
unsigned byte;
if(stateLen < (DES_KEY_SIZE_BYTES_EXTERNAL)) {
return FR_IllegalArg;
}
bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES);
bcopy(state, Key, DES_KEY_SIZE_BYTES_EXTERNAL);
for(byte=0; byte<DES_KEY_SIZE_BYTES_EXTERNAL; byte++){
int i;
unsigned p;
p = 0;
for(i=0;i<7;i++) {
if(Key[byte] & (1 << i)) {
p++;
}
}
if((p & 1) == 0) {
Key[byte] |= 0x80;
}
else {
Key[byte] &= ~0x80;
}
}
dessetkey(&fdinst->dinst, Key);
return FR_Success;
}
void feeDESSetBlockMode(feeDES des)
{
fdesInst *fdinst = (fdesInst*) des;
fdinst->blockMode = 1;
}
void feeDESSetChainMode(feeDES des)
{
fdesInst *fdinst = (fdesInst*) des;
fdinst->blockMode = 0;
}
unsigned feeDESPlainBlockSize(feeDES des)
{
return DES_BLOCK_SIZE_BYTES;
}
unsigned feeDESCipherBlockSize(feeDES des)
{
return DES_BLOCK_SIZE_BYTES;
}
unsigned feeDESCipherBufSize(feeDES des)
{
return 2 * DES_BLOCK_SIZE_BYTES;
}
unsigned feeDESCipherTextSize(feeDES des, unsigned plainTextSize)
{
unsigned blocks = (plainTextSize + DES_BLOCK_SIZE_BYTES - 1) /
DES_BLOCK_SIZE_BYTES;
if((plainTextSize % DES_BLOCK_SIZE_BYTES) == 0) {
blocks++;
}
return blocks * DES_BLOCK_SIZE_BYTES;
}
unsigned feeDESKeySize(feeDES des)
{
return DES_KEY_SIZE_BITS;
}
feeReturn feeDESEncryptBlock(feeDES des,
const unsigned char *plainText,
unsigned plainTextLen,
unsigned char *cipherText,
unsigned *cipherTextLen, int finalBlock)
{
fdesInst *fdinst = (fdesInst*) des;
feeReturn frtn = FR_Success;
unsigned cipherLen;
if(plainTextLen > DES_BLOCK_SIZE_BYTES) {
return FR_IllegalArg;
}
if(plainTextLen) {
bcopy(plainText, cipherText, plainTextLen);
}
if(plainTextLen < DES_BLOCK_SIZE_BYTES) {
if(!finalBlock) {
return FR_IllegalArg;
}
cipherText[DES_BLOCK_SIZE_BYTES - 1] = plainTextLen;
}
if(!fdinst->blockMode) {
unsigned char *cp = cipherText;
unsigned char *cp1 = fdinst->lastBlock;
int i;
for(i=0; i<DES_BLOCK_SIZE_BYTES; i++) {
*cp++ ^= *cp1++;
}
}
endes(&fdinst->dinst, (char *)cipherText);
if(!fdinst->blockMode){
bcopy(cipherText, fdinst->lastBlock, DES_BLOCK_SIZE_BYTES);
}
cipherLen = DES_BLOCK_SIZE_BYTES;
if(finalBlock) {
if(plainTextLen == DES_BLOCK_SIZE_BYTES) {
unsigned moreCipher;
frtn = feeDESEncryptBlock(des,
NULL, 0, cipherText + DES_BLOCK_SIZE_BYTES, &moreCipher,
1);
if(frtn == FR_Success) {
cipherLen += moreCipher;
}
}
if(plainTextLen != 0) {
bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES);
}
}
if(frtn == FR_Success) {
*cipherTextLen = cipherLen;
}
return frtn;
}
feeReturn feeDESDecryptBlock(feeDES des,
const unsigned char *cipherText,
unsigned cipherTextLen,
unsigned char *plainText,
unsigned *plainTextLen, int finalBlock)
{
fdesInst *fdinst = (fdesInst*) des;
unsigned char work[DES_BLOCK_SIZE_BYTES];
unsigned char ivtmp[DES_BLOCK_SIZE_BYTES];
if(cipherTextLen != DES_BLOCK_SIZE_BYTES) {
return FR_IllegalArg;
}
bcopy(cipherText, work, DES_BLOCK_SIZE_BYTES);
if(!fdinst->blockMode && !finalBlock) {
bcopy(cipherText, ivtmp, DES_BLOCK_SIZE_BYTES);
}
dedes(&fdinst->dinst, (char *)work);
if(!fdinst->blockMode){
char *cp = (char *)work;
char *cp1 = (char*)fdinst->lastBlock;
int i;
for(i=0; i<DES_BLOCK_SIZE_BYTES; i++) {
*cp++ ^= *cp1++;
}
if(!finalBlock) {
bcopy(ivtmp, fdinst->lastBlock, DES_BLOCK_SIZE_BYTES);
}
}
if(finalBlock) {
unsigned resid = work[DES_BLOCK_SIZE_BYTES-1];
if(resid > (DES_BLOCK_SIZE_BYTES-1)) {
return FR_BadCipherText;
}
if(resid > 0) {
bcopy(work, plainText, resid);
}
*plainTextLen = resid;
bzero(fdinst->lastBlock, DES_BLOCK_SIZE_BYTES);
}
else {
bcopy(work, plainText, DES_BLOCK_SIZE_BYTES);
*plainTextLen = DES_BLOCK_SIZE_BYTES;
}
return FR_Success;
}
feeReturn feeDESEncrypt(feeDES des,
const unsigned char *plainText,
unsigned plainTextLen,
unsigned char **cipherText, unsigned *cipherTextLen) {
const unsigned char *ptext; unsigned ptextLen; unsigned thisPtextLen; unsigned ctextLen; unsigned char *ctextResult; unsigned char *ctextPtr;
unsigned ctextLenTotal; feeReturn frtn;
int finalBlock;
unsigned ctextMallocd;
if(plainTextLen == 0) {
dbgLog(("feeDESDecrypt: NULL plainText\n"));
return FR_IllegalArg;
}
ptext = plainText;
ptextLen = plainTextLen;
ctextMallocd = feeDESCipherTextSize(des, plainTextLen);
ctextResult = (unsigned char*) fmalloc(ctextMallocd);
ctextPtr = ctextResult;
ctextLenTotal = 0;
while(1) {
if(ptextLen <= DES_BLOCK_SIZE_BYTES) {
finalBlock = 1;
thisPtextLen = ptextLen;
}
else {
finalBlock = 0;
thisPtextLen = DES_BLOCK_SIZE_BYTES;
}
frtn = feeDESEncryptBlock(des,
ptext,
thisPtextLen,
ctextPtr,
&ctextLen,
finalBlock);
if(frtn) {
dbgLog(("feeDESEncrypt: encrypt error: %s\n",
feeReturnString(frtn)));
break;
}
if(ctextLen == 0) {
dbgLog(("feeDESEncrypt: null ciphertext\n"));
frtn = FR_Internal;
break;
}
ctextLenTotal += ctextLen;
if(ctextLenTotal > (plainTextLen + DES_BLOCK_SIZE_BYTES)) {
dbgLog(("feeDESEncrypt: ciphertext overflow\n"));
frtn = FR_Internal;
break;
}
if(finalBlock) {
break;
}
ctextPtr += ctextLen;
ptext += thisPtextLen;
ptextLen -= thisPtextLen;
}
if(frtn) {
ffree(ctextResult);
*cipherText = NULL;
*cipherTextLen = 0;
}
else {
#if FEE_DEBUG
if(ctextLenTotal != ctextMallocd) {
dbgLog(("feeDESEncrypt: ctextLen error\n"));
}
#endif
*cipherText = ctextResult;
*cipherTextLen = ctextLenTotal;
}
return frtn;
}
feeReturn feeDESDecrypt(feeDES des,
const unsigned char *cipherText,
unsigned cipherTextLen,
unsigned char **plainText, unsigned *plainTextLen) {
const unsigned char *ctext;
unsigned ctextLen; unsigned ptextLen; unsigned char *ptextResult; unsigned char *ptextPtr;
unsigned ptextLenTotal; feeReturn frtn = FR_Success;
int finalBlock;
if(cipherTextLen % DES_BLOCK_SIZE_BYTES) {
dbgLog(("feeDESDecrypt: unaligned cipherText\n"));
return FR_BadCipherText;
}
if(cipherTextLen == 0) {
dbgLog(("feeDESDecrypt: NULL cipherText\n"));
return FR_BadCipherText;
}
ctext = cipherText;
ctextLen = cipherTextLen;
ptextResult = (unsigned char*) fmalloc(cipherTextLen);
ptextPtr = ptextResult;
ptextLenTotal = 0;
while(ctextLen) {
if(ctextLen == DES_BLOCK_SIZE_BYTES) {
finalBlock = 1;
}
else {
finalBlock = 0;
}
frtn = feeDESDecryptBlock(des,
ctext,
DES_BLOCK_SIZE_BYTES,
ptextPtr,
&ptextLen,
finalBlock);
if(frtn) {
dbgLog(("feeDESDecrypt decrypt: %s\n",
feeReturnString(frtn)));
break;
}
if(ptextLen == 0) {
if(!finalBlock) {
dbgLog(("feeDESDecrypt: decrypt sync"
" error!\n"));
frtn = FR_BadCipherText;
break;
}
else {
break;
}
}
else {
ptextPtr += ptextLen;
ptextLenTotal += ptextLen;
}
ctext += DES_BLOCK_SIZE_BYTES;
ctextLen -= DES_BLOCK_SIZE_BYTES;
}
if(frtn) {
ffree(ptextResult);
*plainText = NULL;
*plainTextLen = 0;
}
else {
*plainText = ptextResult;
*plainTextLen = ptextLenTotal;
}
return frtn;
}
#endif