📄 rsaencimpl.c
字号:
/* Copyright 2005-2006, Voltage Security, all rights reserved.
*/
#include "vibecrypto.h"
#include "environment.h"
#include "base.h"
#include "libctx.h"
#include "algobj.h"
#include "cipher.h"
#include "rsa.h"
#include "mpint.h"
#include "errorctx.h"
#include "surrender.h"
int RSAEncryptGetOutputSize (
VoltAlgorithmObject *obj,
unsigned int callFlag,
unsigned char *input,
unsigned int inputLen,
unsigned int *outputSize,
unsigned int *leftovers,
VtRandomObject random
)
{
int status;
unsigned int totalLen, blockCount;
VoltCipherClassCtx *cipherCtx = (VoltCipherClassCtx *)(obj->classCtx);
VOLT_DECLARE_ERROR_TYPE (errorType)
VOLT_DECLARE_FNCT_LINE (fnctLine)
totalLen = inputLen + cipherCtx->unprocessedDataLen;
status = 0;
switch (callFlag)
{
case VOLT_CALLER_ENCRYPT_UPDATE:
/* If there's padding, we're not allowed to call this function.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
if (cipherCtx->Pad != (VPad)0)
status = VT_ERROR_INVALID_CALL_ORDER;
/* How many blocks of input? That's how many blocks of output,
* then multiply by the block size to get the total length.
* The leftovers consist of data after the full blocks. However,
* don't count any data in the unprocessedData buffer. The first
* leftovers computation is the leftovers of the totalLen. If the
* totalLen does not make up one block, we need to adjust to
* count only the new bytes.
*/
blockCount = totalLen / cipherCtx->plainBlockSize;
*outputSize = blockCount * cipherCtx->cipherBlockSize;
*leftovers = totalLen - (blockCount * cipherCtx->plainBlockSize);
if (inputLen < *leftovers)
*leftovers = inputLen;
break;
case VOLT_CALLER_ENCRYPT_FINAL:
/* If there's padding, the outputSize will be one block and the
* entire input len will be leftovers. We only allow one total
* block of input, though, so make sure we don't have more.
*/
if (cipherCtx->Pad != (VPad)0)
{
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
if (totalLen >= cipherCtx->plainBlockSize)
status = VT_ERROR_INVALID_INPUT_LENGTH;
*outputSize = cipherCtx->cipherBlockSize;
*leftovers = inputLen;
break;
}
/* If no padding, input and output are the same, the input must
* be a multiple of the block size.
*/
blockCount = totalLen / cipherCtx->plainBlockSize;
*outputSize = blockCount * cipherCtx->cipherBlockSize;
*leftovers = 0;
totalLen -= (blockCount * cipherCtx->plainBlockSize);
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
if (totalLen != 0)
status = VT_ERROR_INVALID_INPUT_LENGTH;
break;
case VOLT_CALLER_DECRYPT_UPDATE:
/* If there's padding, we're not allowed to call this function.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
if (cipherCtx->Unpad != (VUnpad)0)
status = VT_ERROR_INVALID_CALL_ORDER;
/* How many blocks of input? That's how many blocks of output,
* then multiply by the block size to get the total length.
* The leftovers consist of data after the full blocks. However,
* don't count any data in the unprocessedData buffer. The first
* leftovers computation is the leftovers of the totalLen. If the
* totalLen does not make up one block, we need to adjust to
* count only the new bytes.
*/
blockCount = totalLen / cipherCtx->cipherBlockSize;
*outputSize = blockCount * cipherCtx->plainBlockSize;
*leftovers = totalLen - (blockCount * cipherCtx->cipherBlockSize);
if (inputLen < *leftovers)
*leftovers = inputLen;
break;
case VOLT_CALLER_DECRYPT_FINAL:
/* If there's padding, the outputSize will be at most one block
* and the entire block will be leftovers (to strip padding). We
* only allow one total block of input, though, so make sure we
* don't have more.
*/
if (cipherCtx->Unpad != (VUnpad)0)
{
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
if (totalLen != cipherCtx->cipherBlockSize)
status = VT_ERROR_INVALID_INPUT_LENGTH;
/* After padding, the output will be less, but we don't know
* until decrypting, so this is the max output length.
*/
*outputSize = cipherCtx->plainBlockSize;
*leftovers = cipherCtx->plainBlockSize;
break;
}
/* If no padding, input and output are the same, the input must
* be a multiple of the block size.
*/
blockCount = totalLen / cipherCtx->cipherBlockSize;
*outputSize = blockCount * cipherCtx->plainBlockSize;
*leftovers = 0;
totalLen -= (blockCount * cipherCtx->cipherBlockSize);
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
if (totalLen != 0)
status = VT_ERROR_INVALID_INPUT_LENGTH;
break;
default:
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_CALL_ORDER;
}
VOLT_LOG_ERROR_INFO_COMPARE (
status, 0, obj, status, 0, errorType,
(char *)0, "RSAEncryptGetOutputSize", fnctLine, (char *)0)
return (status);
}
int RSAEncryptInit (
VoltAlgorithmObject *algObj,
VoltKeyObject *keyObj
)
{
int status;
unsigned int blockSize;
VoltCipherClassCtx *cipherCtx = (VoltCipherClassCtx *)(algObj->classCtx);
VoltLibCtx *libCtx = (VoltLibCtx *)(algObj->voltObject.libraryCtx);
VtRSAPubKeyInfo *getKeyInfo;
VoltRsaPublicKey *newData;
VoltMpIntCtx *mpCtx;
VOLT_DECLARE_ERROR_TYPE (errorType)
VOLT_DECLARE_FNCT_LINE (fnctLine)
do
{
/* Make sure the key matches the algorithm object.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_KEY_OBJ;
if ((keyObj->keyType & VOLT_KEY_TYPE_MASK_ASYM_ALG) != VOLT_KEY_ALG_RSA)
break;
/* Only a public key is allowed to encrypt.
*/
VOLT_SET_FNCT_LINE (fnctLine)
if ((keyObj->keyType & VOLT_KEY_TYPE_PUBLIC) == 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
if (keyObj->mpCtx == (VoltMpIntCtx *)0)
break;
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VtGetKeyParam (
(VtKeyObject)keyObj, VtKeyParamRSAPublicEncrypt, (Pointer *)&getKeyInfo);
if (status != 0)
break;
/* If there's a localCipherCtx, get rid of it.
*/
if ( (cipherCtx->localCipherCtx != (Pointer)0) &&
(cipherCtx->LocalCipherCtxDestroy != (VCtxDestroy)0) )
cipherCtx->LocalCipherCtxDestroy (
(Pointer)algObj, cipherCtx->localCipherCtx);
cipherCtx->localCipherCtx = (Pointer)0;
cipherCtx->LocalCipherCtxDestroy = (VCtxDestroy)0;
/* Clone the mpCtx.
*/
if (algObj->mpCtx != (VoltMpIntCtx *)0)
VtDestroyMpIntCtx ((VtMpIntCtx *)&(algObj->mpCtx));
VOLT_SET_FNCT_LINE (fnctLine)
status = VtCloneObject (
(Pointer)(keyObj->mpCtx), (Pointer *)&(algObj->mpCtx));
if (status != 0)
break;
mpCtx = algObj->mpCtx;
/* Clear the cipherCtx for a new Init.
*/
cipherCtx->unprocessedDataLen = 0;
cipherCtx->plainBlockSize = 0;
cipherCtx->cipherBlockSize = 0;
/* Copy the key data over to the cipherCtx.
* First, we need the struct that holds the elements.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_MEMORY;
cipherCtx->localCipherCtx = Z2Malloc (sizeof (VoltRsaPublicKey), 0);
if (cipherCtx->localCipherCtx == (Pointer)0)
break;
Z2Memset (cipherCtx->localCipherCtx, 0, sizeof (VoltRsaPublicKey));
cipherCtx->LocalCipherCtxDestroy = RSAKeyDataDestroy;
newData = (VoltRsaPublicKey *)(cipherCtx->localCipherCtx);
newData->type = VOLT_KEY_TYPE_PUBLIC;
/* Create the mpInts.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->CreateMpInt ((Pointer)mpCtx, &(newData->modulus));
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->CreateMpInt ((Pointer)mpCtx, &(newData->pubExpo));
if (status != 0)
break;
/* Copy the values.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->OctetStringToMpInt (
0, getKeyInfo->modulus.data, getKeyInfo->modulus.len, newData->modulus);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->OctetStringToMpInt (
0, getKeyInfo->pubExpo.data, getKeyInfo->pubExpo.len, newData->pubExpo);
if (status != 0)
break;
/* Get the block size. We're expecting BUFFER_TOO_SMALL.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->GetBitLength (newData->modulus, &blockSize);
if (status != 0)
break;
blockSize = (blockSize + 7) / 8;
cipherCtx->plainBlockSize = blockSize;
cipherCtx->cipherBlockSize = blockSize;
/* We need the unprocessedData buffer to be blockSize bytes big.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_MEMORY;
cipherCtx->unprocessedData = (unsigned char *)Z2Realloc (
cipherCtx->unprocessedData, blockSize);
if (cipherCtx->unprocessedData == (unsigned char *)0)
break;
status = 0;
} while (0);
VOLT_LOG_ERROR_INFO_COMPARE (
status, 0, algObj, status, 0, errorType,
(char *)0, "RSAEncryptInit", fnctLine, (char *)0)
return (status);
}
int RSAEncryptUpdate (
VoltAlgorithmObject *algObj,
VtRandomObject random,
unsigned char *dataToEncrypt,
unsigned int dataToEncryptLen,
unsigned char *encryptedData
)
{
int status;
unsigned int blockSize, outputLen, sign;
VoltCipherClassCtx *cipherCtx = (VoltCipherClassCtx *)(algObj->classCtx);
VoltLibCtx *libCtx = (VoltLibCtx *)(algObj->voltObject.libraryCtx);
VoltRsaPublicKey *keyData = (VoltRsaPublicKey *)(cipherCtx->localCipherCtx);
VoltMpIntCtx *mpCtx;
VoltMpInt *base = (VoltMpInt *)0;
VoltMpInt *result = (VoltMpInt *)0;
VoltSurrenderCtx *surrCtx = (VoltSurrenderCtx *)0;
VOLT_DECLARE_FNCT_LINE (fnctLine)
do
{
/* If there's a surrender ctx, call the Surrender function.
*/
VOLT_GET_OBJECT_SURR_CTX (surrCtx, algObj);
VOLT_CALL_SURRENDER (surrCtx, VT_SURRENDER_FNCT_RSA_ENCRYPT, 3, 1)
mpCtx = keyData->modulus->mpCtx;
blockSize = cipherCtx->plainBlockSize;
/* Create mpInts to hold the data to encrypt and the encrypted data.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->CreateMpInt ((Pointer)mpCtx, &base);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->CreateMpInt ((Pointer)mpCtx, &result);
if (status != 0)
break;
while (dataToEncryptLen >= blockSize)
{
/* Get the block of data as an mpInt.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->OctetStringToMpInt (0, dataToEncrypt, blockSize, base);
if (status != 0)
break;
VOLT_CALL_SURRENDER (surrCtx, VT_SURRENDER_FNCT_RSA_ENCRYPT, 3, 2)
/* Encryption is modExp.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->ModExp (
base, keyData->pubExpo, keyData->modulus, result);
if (status != 0)
break;
/* Place the result as an octet string into the output buffer.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->MpIntToOctetString (
result, &sign, encryptedData, blockSize, &outputLen);
if (status != 0)
break;
/* If the outputLen < blockSize, we want to prepend 00 bytes.
*/
if (outputLen < blockSize)
{
/* Use sign as a temp variable.
*/
sign = blockSize - outputLen;
Z2Memmove (encryptedData + sign, encryptedData, outputLen);
Z2Memset (encryptedData, 0, sign);
}
dataToEncryptLen -= blockSize;
dataToEncrypt += blockSize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -