📄 dsasignimpl.c
字号:
/* Copyright 2003-2006, Voltage Security, all rights reserved.
*/
#include "vibecrypto.h"
#include "environment.h"
#include "base.h"
#include "libctx.h"
#include "algobj.h"
#include "random.h"
#include "sign.h"
#include "dsa.h"
#include "mpint.h"
#include "errorctx.h"
#include "surrender.h"
int DSACheckSignatureInput (
VoltAlgorithmObject *obj,
VoltKeyObject *key,
VtRandomObject random,
unsigned char *dataToSign,
unsigned int dataToSignLen,
unsigned int *signatureSize
)
{
int status;
unsigned int keyDataFlag;
VoltSignClassCtx *signCtx = (VoltSignClassCtx *)(obj->classCtx);
VoltDsaSignCtx *dsaCtx = (VoltDsaSignCtx *)(signCtx->localSignCtx);
VoltDsaPrivateKey *getKeyData;
VtDSAPriKeyInfo *getKeyInfo;
VtRandomObject randomToUse;
VOLT_DECLARE_ERROR_TYPE (errorType)
VOLT_DECLARE_FNCT_LINE (fnctLine)
/* This function not only checks the input, it sets dsaCtx values, so
* we don't have to get them again when we're inside SignData.
*/
do
{
/* How big will the signature be? It depends on the format.
*/
*signatureSize = VOLT_RAW_DSA_SIG_LEN;
if (dsaCtx->format == VT_DSA_SIGNATURE_DER_ENCODED)
*signatureSize = VOLT_DER_DSA_SIG_LEN;
/* Make sure the key is a DSA private key. Also, this implementation
* needs the key as data.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_KEY_OBJ;
if ((key->keyType & VOLT_KEY_TYPE_MASK_ASYM_ALG) != VOLT_KEY_ALG_DSA)
break;
VOLT_SET_FNCT_LINE (fnctLine)
if ((key->keyType & VOLT_KEY_TYPE_PRIVATE) == 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
if (key->mpCtx == (VoltMpIntCtx *)0)
break;
/* See if the key data is already in the form we want it. If so,
* reset keyDataFlag to 1.
*/
keyDataFlag = 0;
if ((key->keyType & VOLT_KEY_TYPE_MASK_DATA) == VOLT_KEY_TYPE_DATA)
{
getKeyData = (VoltDsaPrivateKey *)(key->keyData);
if (getKeyData->type == VOLT_KEY_TYPE_PRIVATE)
keyDataFlag = 1;
}
/* If we were not able to get the key data in the form we wanted
* it, see if we can create it.
*/
if (keyDataFlag == 0)
{
/* Can we get the key data out of the object?
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VtGetKeyParam (
(VtKeyObject)key, VtKeyParamDSAPrivate, (Pointer *)&getKeyInfo);
if (status == VT_ERROR_GET_INFO_UNAVAILABLE)
status = VT_ERROR_INVALID_KEY_OBJ;
if (status != 0)
break;
VtDestroyKeyObject (&(dsaCtx->tempKey));
dsaCtx->priKeyData = (VoltDsaPrivateKey *)0;
dsaCtx->pubKeyData = (VoltDsaPublicKey *)0;
/* Create a key object we know will possess the key data the way
* we want it.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = VtCreateKeyObject (
obj->voltObject.libraryCtx, VtKeyImplMpCtx, (Pointer)(key->mpCtx),
&(dsaCtx->tempKey));
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = VtSetKeyParam (
dsaCtx->tempKey, VtKeyParamDSAPrivate, (Pointer)getKeyInfo);
if (status != 0)
break;
key = (VoltKeyObject *)(dsaCtx->tempKey);
getKeyData = (VoltDsaPrivateKey *)(key->keyData);
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
}
/* The signer will need a valid random.
*/
randomToUse = random;
if (random == (VtRandomObject)0)
{
randomToUse = (VtRandomObject)VoltGetLibCtxInfo (
obj->voltObject.libraryCtx, VOLT_LIB_CTX_INFO_TYPE_RANDOM);
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_NO_RANDOM_OBJECT;
if (randomToUse == (VtRandomObject)0)
break;
}
status = VT_ERROR_INVALID_RANDOM_OBJ;
VOLT_SET_FNCT_LINE (fnctLine)
if (VOLT_OBJECT_TYPE_NOT_EQUAL (randomToUse, VOLT_OBJECT_TYPE_RANDOM))
break;
VOLT_SET_FNCT_LINE (fnctLine)
if (((VoltRandomObject *)randomToUse)->enabled == 0)
break;
/* The digest algorithm must be SHA-1.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_INPUT;
if (signCtx->digestAlg != VT_DIGEST_ALG_SHA1)
break;
/* The dataToSignLen must be 20 bytes long.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_INVALID_INPUT_LENGTH;
if (dataToSignLen != VOLT_DSA_SIGN_DATA_LEN)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_NULL_ARG;
if (dataToSign == (unsigned char *)0)
break;
signCtx->paddedBlockLen = VOLT_DSA_SIGN_DATA_LEN;
dsaCtx->random = randomToUse;
dsaCtx->priKeyData = getKeyData;
status = 0;
} while (0);
VOLT_LOG_ERROR_COMPARE (
status, obj->voltObject.libraryCtx, status, VT_ERROR_TYPE_PRIMARY,
fnctLine, "DSACheckSignatureInput", (char *)0)
return (status);
}
int DSASignData (
VoltAlgorithmObject *obj,
VoltKeyObject *key,
VtRandomObject random,
unsigned char *dataToSign,
unsigned int dataToSignLen,
unsigned char *signature,
unsigned int *sigLen
)
{
int status, testInt;
unsigned int sign, valLen, index, leadByte;
VoltLibCtx *libCtx = (VoltLibCtx *)(obj->voltObject.libraryCtx);
VoltSignClassCtx *signCtx = (VoltSignClassCtx *)(obj->classCtx);
VoltDsaSignCtx *dsaCtx = (VoltDsaSignCtx *)(signCtx->localSignCtx);
VoltDsaPrivateKey *keyData = (VoltDsaPrivateKey *)(key->keyData);
VoltMpIntCtx *mpCtx = key->mpCtx;
VtRandomObject rand = (VtRandomObject)0;
VoltMpInt *kVal = (VoltMpInt *)0;
VoltMpInt *kInv = (VoltMpInt *)0;
VoltMpInt *rVal = (VoltMpInt *)0;
VoltMpInt *sVal = (VoltMpInt *)0;
VtFips186PrngInfo randInfo;
unsigned char *subprimeQ = (unsigned char *)0;
unsigned char *buf;
VoltSurrenderCtx *surrCtx = (VoltSurrenderCtx *)0;
unsigned char xkey[VOLT_DSA_XKEY_LEN];
unsigned char xseed[VOLT_DSA_XSEED_LEN];
unsigned char kValBuf[VOLT_DSA_K_VAL_LEN];
VOLT_DECLARE_ERROR_TYPE (errorType)
VOLT_DECLARE_FNCT_LINE (fnctLine)
/* This function expects the random and keyData values inside the
* dsaCtx are set with the appropriate info.
*/
do
{
/* If there's a surrender ctx, call the Surrender function.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_GET_OBJECT_SURR_CTX (surrCtx, obj);
VOLT_CALL_SURRENDER (surrCtx, VT_SURRENDER_FNCT_DSA_SIGN, 3, 1)
/* Fill in the xkey and xseed buffers.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = VtGenerateRandomBytes (dsaCtx->random, xkey, VOLT_DSA_XKEY_LEN);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = VtGenerateRandomBytes (dsaCtx->random, xseed, VOLT_DSA_XSEED_LEN);
if (status != 0)
break;
/* We need subprimeQ for the generation of k.
*/
if (dsaCtx->priKeyData->keyItems == (VtDSAPriKeyInfo *)0)
{
/* How big does the buffer need to be?
* We're expecting a BufferTooSmall error, if we don't get it,
* that's an error.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->MpIntToOctetString (
keyData->subprimeQ, &sign, (unsigned char *)0, 0, &valLen);
if (status == 0)
status = VT_ERROR_INVALID_KEY_OBJ;
if (status != VT_ERROR_BUFFER_TOO_SMALL)
break;
/* Allocate a buffer to hold the subprime.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_MEMORY;
subprimeQ = (unsigned char *)Z2Malloc (valLen, 0);
if (subprimeQ == (unsigned char *)0)
break;
/* Now get the data.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->MpIntToOctetString (
keyData->subprimeQ, &sign, subprimeQ, valLen, &valLen);
if (status != 0)
break;
randInfo.primeQ.data = subprimeQ;
randInfo.primeQ.len = valLen;
}
else
{
randInfo.primeQ.data = keyData->keyItems->subprimeQ.data;
randInfo.primeQ.len = keyData->keyItems->subprimeQ.len;
}
/* For generating random k, use technique 3.2 of the FIPS 186
* standard.
*/
randInfo.variation = FIPS_186_PRNG_3_2_CERTIFY;
randInfo.mpCtx = (VtMpIntCtx)mpCtx;
randInfo.XKEY.data = xkey;
randInfo.XKEY.len = VOLT_DSA_XKEY_LEN;
/* Build a random object that will generate the random k in a FIPS
* prescibed manner.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = VtCreateRandomObject (
(VtLibCtx)libCtx, VtRandomImplFips186Prng, (Pointer)&randInfo, &rand);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = VtSeedRandom (rand, xseed, VOLT_DSA_XSEED_LEN);
if (status != 0)
break;
/* We're now ready to create the DSA signature.
* g is the base, x is the private value in the private key.
* k = random value < q
* kInv = k^(-1) mod q (the inverse of k mod q)
* r = (g^k mod p) mod q
* xr = (x * r) mod q
* s = (kInv * (digest + xr)) mod q
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->CreateMpInt ((Pointer)mpCtx, &kVal);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->CreateMpInt ((Pointer)mpCtx, &kInv);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->CreateMpInt ((Pointer)mpCtx, &rVal);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->CreateMpInt ((Pointer)mpCtx, &sVal);
if (status != 0)
break;
VOLT_CALL_SURRENDER (surrCtx, VT_SURRENDER_FNCT_DSA_SIGN, 3, 2)
/* Create a loop to do this a number of times in case we generate a
* "bad" k. If the r or s values are 0, or if there is no inverse
* to k, generate a new k.
* Try this an "arbitrary" 100 times. If, after 100 tries we still
* can't get a signature, return an error.
* In the real world, using real parameters, the probability of
* generating a "bad" k and getting a bad signature are so small,
* this loop will never actually run more than once. But it's there
* just in case.
*/
for (index = 0; index < 100; ++index)
{
/* Generate the random k.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = VtGenerateRandomBytes (rand, kValBuf, VOLT_DSA_K_VAL_LEN);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->OctetStringToMpInt
(0, kValBuf, VOLT_DSA_K_VAL_LEN, kVal);
if (status != 0)
break;
/* Find (g ^ k mod p) mod q. Do this before finding kInv so we can
* use kInv as a temp variable.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->ModExp
(keyData->baseG, kVal, keyData->primeP, kInv);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->ModReduce (kInv, keyData->subprimeQ, rVal);
if (status != 0)
break;
/* Find xr mod q next, use kInv as a temp variable. Place the
* result into sVal (another temp variable).
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->Multiply (keyData->priValX, rVal, kInv);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->ModReduce (kInv, keyData->subprimeQ, sVal);
if (status != 0)
break;
/* Find k^(-1) (k inverse).
* If subprimeQ is truly prime, there will be an inverse to k.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->ModInvert (kVal, keyData->subprimeQ, kInv);
if (status != 0)
{
/* If the error is something other than NoInverse, we're done.
*/
if (status != VT_ERROR_NO_INVERSE)
break;
/* No inverse, try a new k. If we've tried too many times,
* we'll quit with SignatureComputation error.
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_SIGNATURE_COMPUTATION;
continue;
}
/* Compute digest + xr. We're done with k, so use kVal as a temp
* variable. Recall that xr is currently in sVal.
*/
VOLT_SET_ERROR_TYPE (errorType, 0)
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->OctetStringToMpInt (0, dataToSign, dataToSignLen, kVal);
if (status != 0)
break;
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->Add (kVal, sVal, sVal);
if (status != 0)
break;
/* Multiply (digest + xr) by kInv mod q. Use kVal as a temp
* variable. This is s.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->Multiply (sVal, kInv, kVal);
if (status != 0)
break;
/* Place the result into sVal.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->ModReduce (kVal, keyData->subprimeQ, sVal);
if (status != 0)
break;
/* Check to see if r or s is 0. If so, try a new k.
*/
VOLT_SET_FNCT_LINE (fnctLine)
status = mpCtx->MpIntToInt (rVal, 1, &testInt);
if (status == 0)
{
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_SIGNATURE_COMPUTATION;
if (testInt == 0)
continue;
}
status = mpCtx->MpIntToInt (sVal, 1, &testInt);
if (status == 0)
{
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
VOLT_SET_FNCT_LINE (fnctLine)
status = VT_ERROR_SIGNATURE_COMPUTATION;
if (testInt == 0)
continue;
}
/* If we reach this code, the computations worked, we were
* successful.
*/
status = 0;
break;
}
if (status != 0)
break;
/* Place r and s into the signature buffer. If RAW, just place them
* into the buffer side by side (leading 00 bytes if a value is not
* entirely 20 bytes long).
*/
VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
if (dsaCtx->format == VT_DSA_SIGNATURE_R_S)
{
/* Get r.
*/
VOLT_SET_FNCT_LINE (fnctLine)
buf = signature;
status = mpCtx->MpIntToOctetString
(rVal, &sign, buf, VOLT_DSA_R_VAL_LEN, &valLen);
if (status != 0)
break;
/* If less than 20 bytes, redo the get to lead with 00 bytes.
* This will almost never happen, so the inefficiency is not
* likely to be an issue.
*/
if (valLen != VOLT_DSA_R_VAL_LEN)
{
VOLT_SET_FNCT_LINE (fnctLine)
Z2Memset (buf, 0, VOLT_DSA_R_VAL_LEN);
status = mpCtx->MpIntToOctetString
(rVal, &sign, buf + VOLT_DSA_R_VAL_LEN - valLen, valLen, &valLen);
if (status != 0)
break;
}
/* Get s.
*/
VOLT_SET_FNCT_LINE (fnctLine)
buf = signature + VOLT_DSA_R_VAL_LEN;
status = mpCtx->MpIntToOctetString
(sVal, &sign, buf, VOLT_DSA_S_VAL_LEN, &valLen);
if (status != 0)
break;
/* If less than 20 bytes, redo the get to lead with 00 bytes.
* This will almost never happen, so the inefficiency is not
* likely to be an issue.
*/
if (valLen != VOLT_DSA_S_VAL_LEN)
{
VOLT_SET_FNCT_LINE (fnctLine)
Z2Memset (buf, 0, VOLT_DSA_S_VAL_LEN);
status = mpCtx->MpIntToOctetString
(sVal, &sign, buf + VOLT_DSA_S_VAL_LEN - valLen, valLen, &valLen);
if (status != 0)
break;
}
*sigLen = VOLT_DSA_R_VAL_LEN + VOLT_DSA_S_VAL_LEN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -