mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
1082 lines
38 KiB
C
1082 lines
38 KiB
C
/*H********************************************************************************/
|
|
/*!
|
|
\File cryptnist.c
|
|
|
|
\Description
|
|
This module implements the math for elliptic curve cryptography
|
|
using curves in short Weierstrass form (NIST curves)
|
|
|
|
\Copyright
|
|
Copyright (c) Electronic Arts 2017. ALL RIGHTS RESERVED.
|
|
*/
|
|
/********************************************************************************H*/
|
|
|
|
/*** Include files ****************************************************************/
|
|
|
|
#include <string.h>
|
|
|
|
#include "DirtySDK/dirtysock/dirtylib.h"
|
|
#include "DirtySDK/dirtysock/dirtymem.h"
|
|
#include "DirtySDK/crypt/crypthash.h"
|
|
#include "DirtySDK/crypt/crypthmac.h"
|
|
#include "DirtySDK/crypt/cryptrand.h"
|
|
#include "DirtySDK/crypt/cryptnist.h"
|
|
|
|
/*** Defines **********************************************************************/
|
|
|
|
//! the marker that marks uncompressed point format
|
|
#define CRYPTNIST_UNCOMPRESSED_MARKER (0x04)
|
|
|
|
//! number of iterations to do per call
|
|
#if !defined(CRYPTNIST_NUM_ITERATIONS)
|
|
#define CRYPTNIST_NUM_ITERATIONS (0x10)
|
|
#endif
|
|
|
|
//! memgroup for allocating the table
|
|
#define CRYPTNIST_MEMID ('nist')
|
|
|
|
/*** Type Definitions *************************************************************/
|
|
|
|
//! defintion of a curve, basis of initialization into big numbers
|
|
typedef struct NistCurveT
|
|
{
|
|
int32_t iIdent;
|
|
int32_t iSize;
|
|
uint8_t aPrime[48];
|
|
uint8_t aCoefficientA[48];
|
|
uint8_t aCoefficientB[48];
|
|
uint8_t aBasePoint[97];
|
|
uint8_t aOrder[48];
|
|
} NistCurveT;
|
|
|
|
/*** Variables ********************************************************************/
|
|
|
|
//! used to easily checked for default points
|
|
static const CryptEccPointT _Zero = { { { 0x0 }, 1, 0 }, { { 0x0 }, 1, 0 } };
|
|
|
|
//! the curves we support
|
|
static const NistCurveT _aEccCurves[] =
|
|
{
|
|
{
|
|
CRYPTCURVE_SECP256R1, 32,
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC },
|
|
{ 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55, 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B },
|
|
{ 0x04, 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96,
|
|
0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5 },
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51 }
|
|
},
|
|
{
|
|
CRYPTCURVE_SECP384R1, 48,
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF },
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC },
|
|
{ 0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B, 0xE3, 0xF8, 0x2D, 0x19, 0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12, 0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A,
|
|
0xC6, 0x56, 0x39, 0x8D, 0x8A, 0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF },
|
|
{ 0x04, 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E, 0xF3, 0x20, 0xAD, 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98, 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38,
|
|
0x55, 0x02, 0xF2, 0x5D, 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7, 0x36, 0x17, 0xDE, 0x4A, 0x96, 0x26, 0x2C, 0x6F, 0x5D, 0x9E, 0x98, 0xBF, 0x92, 0x92, 0xDC, 0x29,
|
|
0xF8, 0xF4, 0x1D, 0xBD, 0x28, 0x9A, 0x14, 0x7C, 0xE9, 0xDA, 0x31, 0x13, 0xB5, 0xF0, 0xB8, 0xC0, 0x0A, 0x60, 0xB1, 0xCE, 0x1D, 0x7E, 0x81, 0x9D, 0x7A, 0x43, 0x1D, 0x7C, 0x90, 0xEA, 0x0E, 0x5F },
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
|
|
0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73 }
|
|
}
|
|
};
|
|
|
|
/*** Private Functions ************************************************************/
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptNistPointCalculate
|
|
|
|
\Description
|
|
Does the math for doubling / adding points given they you have calculated
|
|
S over the curve's prime
|
|
|
|
\Input *pState - curve state
|
|
\Input *pP - point P
|
|
\Input *pQ - point Q
|
|
\Input *pS - S used in calculation
|
|
\Input *pResult - [out] point R that is calculation of P+Q
|
|
|
|
\Version 02/17/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptNistPointCalculate(CryptNistT *pState, CryptEccPointT *pP, CryptEccPointT *pQ, CryptBnT *pS, CryptEccPointT *pResult)
|
|
{
|
|
CryptEccPointT Result;
|
|
|
|
// X = S² - P.X - Q.X
|
|
CryptBnInitSet(&Result.X, 0);
|
|
CryptBnModMultiply(&Result.X, pS, pS, &pState->Prime);
|
|
CryptBnSubtract(&Result.X, &Result.X, &pP->X);
|
|
CryptBnSubtract(&Result.X, &Result.X, &pQ->X);
|
|
|
|
// Y = S * (P.X - X) - P.Y
|
|
CryptBnInitSet(&Result.Y, 0);
|
|
CryptBnSubtract(&Result.Y, &pP->X, &Result.X);
|
|
CryptBnModMultiply(&Result.Y, &Result.Y, pS, &pState->Prime);
|
|
CryptBnSubtract(&Result.Y, &Result.Y, &pP->Y);
|
|
|
|
// X %= Curve.Prime
|
|
CryptBnMod(&Result.X, &pState->Prime, &Result.X, NULL);
|
|
// Y %= Curve.Prime
|
|
CryptBnMod(&Result.Y, &pState->Prime, &Result.Y, NULL);
|
|
|
|
// write out the result
|
|
ds_memcpy(pResult, &Result, sizeof(*pResult));
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptNistPointAddition
|
|
|
|
\Description
|
|
Adds two points together
|
|
|
|
\Input *pState - curve state
|
|
\Input *pPoint1 - first point in addition
|
|
\Input *pPoint2 - second point in addtion
|
|
\Input *pResult - [out] point R that is result of addition
|
|
|
|
\Version 02/17/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptNistPointAddition(CryptNistT *pState, CryptEccPointT *pPoint1, CryptEccPointT *pPoint2, CryptEccPointT *pResult)
|
|
{
|
|
if (memcmp(pPoint1, &_Zero, sizeof(*pPoint1)) == 0)
|
|
{
|
|
ds_memcpy(pResult, pPoint2, sizeof(*pResult));
|
|
}
|
|
else if (memcmp(pPoint2, &_Zero, sizeof(*pPoint2)) == 0)
|
|
{
|
|
ds_memcpy(pResult, pPoint1, sizeof(*pResult));
|
|
}
|
|
else
|
|
{
|
|
CryptBnT A, B;
|
|
|
|
CryptBnInitSet(&A, 0);
|
|
CryptBnInitSet(&B, 0);
|
|
|
|
// A = y1 - y2
|
|
CryptBnSubtract(&A, &pPoint1->Y, &pPoint2->Y);
|
|
|
|
// B = (x1 - x2)⁻¹ % Curve.Prime [Inverse Modulus]
|
|
CryptBnSubtract(&B, &pPoint1->X, &pPoint2->X);
|
|
CryptBnInverseMod(&B, &pState->Prime);
|
|
|
|
// A *= B
|
|
CryptBnModMultiply(&A, &A, &B, &pState->Prime);
|
|
|
|
// calculate the result
|
|
_CryptNistPointCalculate(pState, pPoint1, pPoint2, &A, pResult);
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptNistPointDouble
|
|
|
|
\Description
|
|
Doubles a point
|
|
|
|
\Input *pState - curve state
|
|
\Input *pPoint - point that we are doubling
|
|
\Input *pResult - [out] result of the doubling
|
|
|
|
\Version 02/17/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptNistPointDouble(CryptNistT *pState, CryptEccPointT *pPoint, CryptEccPointT *pResult)
|
|
{
|
|
CryptBnT A, B;
|
|
|
|
// if attempting to double zero, return
|
|
if (memcmp(pPoint, &_Zero, sizeof(*pPoint)) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// A = 3 * x * x + a
|
|
CryptBnInitSet(&A, 3);
|
|
CryptBnMultiply(&A, &A, &pPoint->X);
|
|
CryptBnMultiply(&A, &A, &pPoint->X);
|
|
CryptBnAccumulate(&A, &pState->CoefficientA);
|
|
|
|
// B = (2 * y)⁻¹ % Curve.Prime [Inverse Modulus]
|
|
CryptBnClone(&B, &pPoint->Y);
|
|
CryptBnLeftShift(&B);
|
|
CryptBnInverseMod(&B, &pState->Prime);
|
|
|
|
// A *= B
|
|
CryptBnModMultiply(&A, &A, &B, &pState->Prime);
|
|
|
|
// calculate the result
|
|
_CryptNistPointCalculate(pState, pPoint, pPoint, &A, pResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptNistDoubleAndAdd
|
|
|
|
\Description
|
|
Performs the scalar multiplication using double and add
|
|
operations using a sliding window for the private key
|
|
|
|
\Input *pState - curve state
|
|
\Input *pInput - point we are multiplying by the private key
|
|
\Input *pPrivateKey - private key was using to multiply
|
|
\Input *pResult - [out] result of the operation
|
|
|
|
\Output
|
|
int32_t - zero=success, otherwise=pending
|
|
|
|
\Notes
|
|
Adapted from the sliding window algorithm used for exponentiation
|
|
in RSA
|
|
See Handbook of Applied Cryptography Chapter 14.6.1 (14.85):
|
|
http://cacr.uwaterloo.ca/hac/about/chap14.pdf
|
|
|
|
\Version 05/08/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static int32_t _CryptNistDoubleAndAdd(CryptNistT *pState, CryptEccPointT *pInput, CryptBnT *pPrivateKey, CryptEccPointT *pResult)
|
|
{
|
|
int32_t iIter = CRYPTNIST_NUM_ITERATIONS;
|
|
|
|
do
|
|
{
|
|
const uint64_t uTick = NetTickUsec();
|
|
|
|
if (pState->iKeyIndex < 0)
|
|
{
|
|
int32_t iTableIndex;
|
|
CryptEccPointT Double;
|
|
|
|
// init working state
|
|
ds_memcpy(pResult, &_Zero, sizeof(*pResult));
|
|
|
|
// query memgroup
|
|
DirtyMemGroupQuery(&pState->iMemGroup, &pState->pMemGroupUserdata);
|
|
|
|
if ((pState->pTable = (CryptEccPointT *)DirtyMemAlloc(sizeof(*pState->pTable) * CRYPTNIST_TABLE_SIZE, CRYPTNIST_MEMID, pState->iMemGroup, pState->pMemGroupUserdata)) == NULL)
|
|
{
|
|
NetPrintf(("cryptnist: failed to allocate window table\n"));
|
|
return(0);
|
|
}
|
|
ds_memclr(pState->pTable, sizeof(*pState->pTable) * CRYPTNIST_TABLE_SIZE);
|
|
|
|
/* put the input into the first
|
|
index of the table, this will make it so further
|
|
entries in the table will not be too large
|
|
for our modulus operations */
|
|
ds_memcpy(&pState->pTable[0], pInput, sizeof(pState->pTable[0]));
|
|
|
|
// calculate doubled input as the basis for the other calculations
|
|
_CryptNistPointDouble(pState, pInput, &Double);
|
|
|
|
// calculate the further added points for the rest of the table
|
|
for (iTableIndex = 1; iTableIndex < CRYPTNIST_TABLE_SIZE; iTableIndex += 1)
|
|
{
|
|
_CryptNistPointAddition(pState, &pState->pTable[iTableIndex - 1], &Double, &pState->pTable[iTableIndex]);
|
|
}
|
|
|
|
// set the defaults
|
|
pState->iKeyIndex = CryptBnBitLen(pPrivateKey) - 1;
|
|
|
|
// clear the profiling information
|
|
pState->uCryptUSecs = 0;
|
|
}
|
|
|
|
/* scan backwards from the current private key bit
|
|
until a set bit is found to denote the start of the window
|
|
doubling the results until such a bit is found */
|
|
if (CryptBnBitTest(pPrivateKey, pState->iKeyIndex))
|
|
{
|
|
int32_t iWindowBit, iWindowValue, iWindowEnd;
|
|
|
|
/* scan backwards from the start of the window until the last set bit in the range of the window size is found which denotes the end bit index of the window
|
|
calculate the value of the window that will be used when adding against our precomputed table.
|
|
we skip the first bit as we know it is set based on the current private key bit check we make right above */
|
|
for (iWindowBit = 1, iWindowValue = 1, iWindowEnd = 0; (iWindowBit < CRYPTNIST_WINDOW_SIZE) && ((pState->iKeyIndex - iWindowBit) >= 0); iWindowBit += 1)
|
|
{
|
|
if (CryptBnBitTest(pPrivateKey, pState->iKeyIndex - iWindowBit))
|
|
{
|
|
iWindowValue <<= (iWindowBit - iWindowEnd);
|
|
iWindowValue |= 1; // force odd
|
|
iWindowEnd = iWindowBit;
|
|
}
|
|
}
|
|
|
|
// double for each bits in the window and moving the private key bit index down each time
|
|
for (iWindowBit = 0; iWindowBit < iWindowEnd + 1; iWindowBit += 1, pState->iKeyIndex -= 1)
|
|
{
|
|
_CryptNistPointDouble(pState, pResult, pResult);
|
|
}
|
|
|
|
// use the window value to get which precomputed power we need to multiply
|
|
_CryptNistPointAddition(pState, pResult, &pState->pTable[iWindowValue/2], pResult);
|
|
}
|
|
else
|
|
{
|
|
_CryptNistPointDouble(pState, pResult, pResult);
|
|
pState->iKeyIndex -= 1;
|
|
}
|
|
|
|
// update profiler information
|
|
pState->uCryptUSecs += NetTickDiff(NetTickUsec(), uTick);
|
|
}
|
|
while ((pState->iKeyIndex >= 0) && (--iIter > 0));
|
|
|
|
// cleanup memory when done
|
|
if (pState->iKeyIndex < 0)
|
|
{
|
|
DirtyMemFree(pState->pTable, CRYPTNIST_MEMID, pState->iMemGroup, pState->pMemGroupUserdata);
|
|
pState->pTable = NULL;
|
|
}
|
|
|
|
return(pState->iKeyIndex >= 0);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptNistDoubleMultiply
|
|
|
|
\Description
|
|
Uses Shamir's Trick to do double point multiplication:
|
|
(pInput1 * pPrivateKey1) + (pInput2 * pPrivateKey2)
|
|
|
|
\Input *pState - curve state
|
|
\Input *pInput1 - point we are multiplying by pMul1
|
|
\Input *pMul1 - big number we are multiplying by pInput1
|
|
\Input *pInput2 - point we are multiplying by pMul2
|
|
\Input *pMul2 - big number we are multiplying by pInput2
|
|
\Input *pResult - [out] result of the operation
|
|
|
|
\Output
|
|
int32_t - zero=success, otherwise=pending
|
|
|
|
\Notes
|
|
For more information on the algorithm, see the Double-scalar
|
|
multiplication slides: http://www.lirmm.fr/~imbert/talks/laurent_Asilomar_08.pdf
|
|
|
|
\Version 05/15/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static int32_t _CryptNistDoubleMultiply(CryptNistT *pState, CryptEccPointT *pInput1, CryptBnT *pMul1, CryptEccPointT *pInput2, CryptBnT *pMul2, CryptEccPointT *pResult)
|
|
{
|
|
int32_t iIter = CRYPTNIST_NUM_ITERATIONS;
|
|
|
|
do
|
|
{
|
|
const uint64_t uTick = NetTickUsec();
|
|
uint8_t bLHBitSet, bRHBitSet;
|
|
|
|
if (pState->iKeyIndex < 0)
|
|
{
|
|
DirtyMemGroupQuery(&pState->iMemGroup, &pState->pMemGroupUserdata);
|
|
|
|
if ((pState->pTable = (CryptEccPointT *)DirtyMemAlloc(sizeof(*pState->pTable), CRYPTNIST_MEMID, pState->iMemGroup, pState->pMemGroupUserdata)) == NULL)
|
|
{
|
|
NetPrintf(("cryptnist: failed to allocate window table\n"));
|
|
return(0);
|
|
}
|
|
ds_memclr(pState->pTable, sizeof(*pState->pTable));
|
|
|
|
// precompute pInput1 + pInput2
|
|
_CryptNistPointAddition(pState, pInput1, pInput2, &pState->pTable[0]);
|
|
|
|
// init working state
|
|
ds_memcpy(pResult, &_Zero, sizeof(*pResult));
|
|
|
|
// set the maximum bit size
|
|
pState->iKeyIndex = DS_MAX(CryptBnBitLen(pMul1), CryptBnBitLen(pMul2)) - 1;
|
|
|
|
// clear the profiling information
|
|
pState->uCryptUSecs = 0;
|
|
}
|
|
|
|
// double for each column
|
|
_CryptNistPointDouble(pState, pResult, pResult);
|
|
|
|
// check the bit set in the column
|
|
bLHBitSet = CryptBnBitTest(pMul1, pState->iKeyIndex);
|
|
bRHBitSet = CryptBnBitTest(pMul2, pState->iKeyIndex);
|
|
|
|
// if only left hand, then add by that side
|
|
if ((bLHBitSet == TRUE) && (bRHBitSet == FALSE))
|
|
{
|
|
_CryptNistPointAddition(pState, pResult, pInput1, pResult);
|
|
}
|
|
// if only right hand, then add by that side
|
|
else if ((bLHBitSet == FALSE) && (bRHBitSet == TRUE))
|
|
{
|
|
_CryptNistPointAddition(pState, pResult, pInput2, pResult);
|
|
}
|
|
// if both sides, then add by the sum of both
|
|
else if ((bLHBitSet == TRUE) && (bRHBitSet == TRUE))
|
|
{
|
|
_CryptNistPointAddition(pState, pResult, &pState->pTable[0], pResult);
|
|
}
|
|
|
|
// update profiler information
|
|
pState->uCryptUSecs += NetTickDiff(NetTickUsec(), uTick);
|
|
}
|
|
while ((--pState->iKeyIndex >= 0) && (--iIter > 0));
|
|
|
|
// cleanup table memory
|
|
if (pState->iKeyIndex < 0)
|
|
{
|
|
DirtyMemFree(pState->pTable, CRYPTNIST_MEMID, pState->iMemGroup, pState->pMemGroupUserdata);
|
|
pState->pTable = NULL;
|
|
}
|
|
|
|
return(pState->iKeyIndex >= 0);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptNistRand
|
|
|
|
\Description
|
|
Generates a random number in the range [1, curve.order-1]
|
|
|
|
\Input *pState - curve state
|
|
\Input *pResult - [out] random number generated
|
|
|
|
\Version 05/15/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptNistRand(const CryptNistT *pState, CryptBnT *pResult)
|
|
{
|
|
uint8_t aSecret[48];
|
|
CryptBnT Temp;
|
|
|
|
// generate a secret to the specified size
|
|
CryptRandGet(aSecret, sizeof(aSecret));
|
|
CryptBnInitFrom(pResult, -1, aSecret, DS_MIN((int32_t)sizeof(aSecret), pState->iSize));
|
|
|
|
// clone order so we don't modify
|
|
CryptBnClone(&Temp, &pState->Order);
|
|
|
|
// random number = (rand() % order-1 + 1)
|
|
CryptBnDecrement(&Temp);
|
|
CryptBnMod(pResult, &Temp, pResult, NULL);
|
|
CryptBnIncrement(pResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptNistDsaInitHash
|
|
|
|
\Description
|
|
Initializes the hash, truncating if necessary
|
|
|
|
\Input *pState - curve state
|
|
\Input *pHashData - the buffer with the hash digest
|
|
\Input iHashSize - size of the buffer
|
|
\Input *pHash - [out] big number representation of the hash
|
|
|
|
\Notes
|
|
Based on the algorithm for ECDSA, the hash needs to be truncated to the
|
|
bit length of curve.order which can be done by a right shift. The problem
|
|
is that other implementations don't follow this and just truncate whole
|
|
bytes first. For this reason that is what we do here.
|
|
|
|
\Version 02/13/2018 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptNistDsaInitHash(const CryptNistT *pState, const uint8_t *pHashData, int32_t iHashSize, CryptBnT *pHash)
|
|
{
|
|
int32_t iOrderSize = CryptBnBitLen(&pState->Order);
|
|
|
|
if ((iHashSize*8) > iOrderSize)
|
|
{
|
|
iHashSize = (iOrderSize + 7) / 8;
|
|
}
|
|
CryptBnInitFrom(pHash, -1, pHashData, iHashSize);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptNistInit
|
|
|
|
\Description
|
|
Initializes the curve state
|
|
|
|
\Input *pState - curve state
|
|
\Input *pCurve - curve data to initialize the state
|
|
|
|
\Output
|
|
int32_t - 0=success, negative=failure
|
|
|
|
\Version 02/17/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static int32_t _CryptNistInit(CryptNistT *pState, const NistCurveT *pCurve)
|
|
{
|
|
// initialize the curve parameters
|
|
pState->iSize = pCurve->iSize;
|
|
CryptBnInitFrom(&pState->Prime, -1, pCurve->aPrime, pCurve->iSize);
|
|
CryptBnInitFrom(&pState->CoefficientA, -1, pCurve->aCoefficientA, pCurve->iSize);
|
|
CryptBnInitFrom(&pState->CoefficientB, -1, pCurve->aCoefficientB, pCurve->iSize);
|
|
CryptBnInitFrom(&pState->Order, -1, pCurve->aOrder, pCurve->iSize);
|
|
if (CryptNistPointInitFrom(&pState->BasePoint, pCurve->aBasePoint, pCurve->iSize * 2 + 1) < 0)
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
// initialize the computation state
|
|
pState->iKeyIndex = -1;
|
|
return(0);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptNistDsaInitK
|
|
|
|
\Description
|
|
Generates a K value for signing operations deterministically based on
|
|
the private key, message hash and curve
|
|
|
|
\Input *pState - curve state
|
|
\Input *pPrivateKey - private key information
|
|
\Input *pHash - hash of the message we are signing
|
|
\Input iHashSize - size of the hash
|
|
\Input *pResult - [out] K value for signing
|
|
|
|
\Notes
|
|
This work is based on RFC6979: https://tools.ietf.org/html/rfc6979
|
|
It allows for selecting a K value without the use of random data.
|
|
Aside from this generating benefit the ability to generate deterministic
|
|
signatures are required for other cryptographic operations.
|
|
|
|
\Version 01/08/2018 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptNistDsaInitK(const CryptNistT *pState, const CryptBnT *pPrivateKey, const uint8_t *pHash, int32_t iHashSize, CryptBnT *pResult)
|
|
{
|
|
static const uint8_t _aZero[] = { 0x00 }, _aOne[] = { 0x01 };
|
|
|
|
CryptHashTypeE eHashType;
|
|
uint8_t aNewHash[CRYPTHASH_MAXDIGEST], aK[CRYPTHASH_MAXDIGEST], aV[CRYPTHASH_MAXDIGEST], aT[CRYPTHASH_MAXDIGEST], aPrivateKey[48];
|
|
CryptHmacMsgT aMessages[4];
|
|
int32_t iHashOffset = iHashSize < pState->iSize ? pState->iSize - iHashSize : 0;
|
|
|
|
// figure out the hash based on the type
|
|
if ((eHashType = CryptHashGetBySize(iHashSize)) == CRYPTHASH_NULL)
|
|
{
|
|
NetPrintf(("cryptnist: cannot generate deterministic k, unsupported hash used (size=%d)\n", iHashSize));
|
|
return;
|
|
}
|
|
|
|
// copy the hash to our buffer, this ensures correct format
|
|
ds_memclr(aNewHash, sizeof(aNewHash));
|
|
ds_memcpy_s(aNewHash+iHashOffset, sizeof(aNewHash)-iHashOffset, pHash, iHashSize);
|
|
|
|
// init k, v, private key
|
|
ds_memclr(aK, sizeof(aK));
|
|
ds_memset(aV, 0x01, sizeof(aV));
|
|
CryptBnFinal(pPrivateKey, aPrivateKey, pState->iSize);
|
|
|
|
// K = HMAC(V || 0x00 || PrivateKey || H(m))
|
|
aMessages[0].pMessage = aV;
|
|
aMessages[0].iMessageLen = iHashSize;
|
|
aMessages[1].pMessage = _aZero;
|
|
aMessages[1].iMessageLen = sizeof(_aZero);
|
|
aMessages[2].pMessage = aPrivateKey;
|
|
aMessages[2].iMessageLen = pState->iSize;
|
|
aMessages[3].pMessage = aNewHash;
|
|
aMessages[3].iMessageLen = pState->iSize;
|
|
CryptHmacCalcMulti(aK, iHashSize, aMessages, 4, aK, iHashSize, eHashType);
|
|
|
|
// V = HMAC(V)
|
|
CryptHmacCalc(aV, iHashSize, aV, iHashSize, aK, iHashSize, eHashType);
|
|
|
|
// K = HMAC(V || 0x01 || PrivateKey || H(m))
|
|
aMessages[0].pMessage = aV;
|
|
aMessages[0].iMessageLen = iHashSize;
|
|
aMessages[1].pMessage = _aOne;
|
|
aMessages[1].iMessageLen = sizeof(_aOne);
|
|
aMessages[2].pMessage = aPrivateKey;
|
|
aMessages[2].iMessageLen = pState->iSize;
|
|
aMessages[3].pMessage = aNewHash;
|
|
aMessages[3].iMessageLen = pState->iSize;
|
|
CryptHmacCalcMulti(aK, iHashSize, aMessages, 4, aK, iHashSize, eHashType);
|
|
|
|
// V = HMAC(V)
|
|
CryptHmacCalc(aV, iHashSize, aV, iHashSize, aK, iHashSize, eHashType);
|
|
|
|
// generate T for new K candidate
|
|
while (1)
|
|
{
|
|
int32_t iOffset = 0, iBytes;
|
|
|
|
while (iOffset < pState->iSize)
|
|
{
|
|
// V = HMAC(V)
|
|
CryptHmacCalc(aV, iHashSize, aV, iHashSize, aK, iHashSize, eHashType);
|
|
iBytes = DS_MIN(iHashSize, pState->iSize - iOffset);
|
|
ds_memcpy(aT+iOffset, aV, iBytes);
|
|
iOffset += iBytes;
|
|
}
|
|
|
|
// copy result and check if suitable
|
|
CryptBnInitFrom(pResult, -1, aT, pState->iSize);
|
|
if (CryptBnCompare(pResult, &pState->Order) < 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// K = HMAC(V || 0x00)
|
|
aMessages[0].pMessage = aV;
|
|
aMessages[0].iMessageLen = iHashSize;
|
|
aMessages[1].pMessage = _aZero;
|
|
aMessages[1].iMessageLen = sizeof(_aZero);
|
|
CryptHmacCalcMulti(aK, iHashSize, aMessages, 2, aK, iHashSize, eHashType);
|
|
|
|
// V = HMAC(V)
|
|
CryptHmacCalc(aV, iHashSize, aV, iHashSize, aK, iHashSize, eHashType);
|
|
}
|
|
}
|
|
|
|
/*** Public Functions *************************************************************/
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptNistInitDh
|
|
|
|
\Description
|
|
Initializes the curve state for performing diffie hellmen key exchange
|
|
|
|
\Input *pState - curve state
|
|
\Input iCurveType - identifier for the curve we are using
|
|
|
|
\Output
|
|
int32_t - 0=success, negative=failure
|
|
|
|
\Version 02/17/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CryptNistInitDh(CryptNistDhT *pState, int32_t iCurveType)
|
|
{
|
|
int32_t iResult, iCurveIdx;
|
|
const NistCurveT *pCurve = NULL;
|
|
|
|
ds_memclr(pState, sizeof(*pState));
|
|
|
|
// find the curve
|
|
for (iCurveIdx = 0; iCurveIdx < (signed)(sizeof(_aEccCurves)/sizeof(_aEccCurves[0])); iCurveIdx += 1)
|
|
{
|
|
if (iCurveType == _aEccCurves[iCurveIdx].iIdent)
|
|
{
|
|
pCurve = &_aEccCurves[iCurveIdx];
|
|
break;
|
|
}
|
|
}
|
|
// check to make sure we found a valid curve
|
|
if (pCurve == NULL)
|
|
{
|
|
NetPrintf(("cryptnist: could not find matching curve information for dh given ident %d\n", iCurveType));
|
|
return(-1);
|
|
}
|
|
|
|
// initialize the curve and computation data
|
|
if ((iResult = _CryptNistInit(&pState->Ecc, pCurve)) == 0)
|
|
{
|
|
// generate random private key
|
|
_CryptNistRand(&pState->Ecc, &pState->PrivateKey);
|
|
}
|
|
return(iResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptNistInitDsa
|
|
|
|
\Description
|
|
Initializes the curve state for performing dsa sign and verify
|
|
|
|
\Input *pState - curve state
|
|
\Input iCurveType - identifier for the curve we are using
|
|
|
|
\Output
|
|
int32_t - 0=success, negative=failure
|
|
|
|
\Version 04/12/2018 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CryptNistInitDsa(CryptNistDsaT *pState, int32_t iCurveType)
|
|
{
|
|
int32_t iCurveIdx;
|
|
const NistCurveT *pCurve = NULL;
|
|
|
|
ds_memclr(pState, sizeof(*pState));
|
|
|
|
// find the curve
|
|
for (iCurveIdx = 0; iCurveIdx < (signed)(sizeof(_aEccCurves)/sizeof(_aEccCurves[0])); iCurveIdx += 1)
|
|
{
|
|
if (iCurveType == _aEccCurves[iCurveIdx].iIdent)
|
|
{
|
|
pCurve = &_aEccCurves[iCurveIdx];
|
|
break;
|
|
}
|
|
}
|
|
// check to make sure we found a valid curve
|
|
if (pCurve == NULL)
|
|
{
|
|
NetPrintf(("cryptnist: could not find matching curve information for dh given ident %d\n", iCurveType));
|
|
return(-1);
|
|
}
|
|
|
|
// initialize the curve and computation data
|
|
return(_CryptNistInit(&pState->Ecc, pCurve));
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptNistPublic
|
|
|
|
\Description
|
|
Generates a public key
|
|
|
|
\Input *pState - curve state
|
|
\Input *pResult - [out] point on the curve that represents the public key (optional)
|
|
\Input *pCryptUsecs - [out] timing information for the operation (optional)
|
|
|
|
\Output
|
|
int32_t - zero=success, otherwise=pending
|
|
|
|
\Notes
|
|
If pResult is NULL, the result can be taken from CryptNistT.Result
|
|
|
|
\Version 02/17/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CryptNistPublic(CryptNistDhT *pState, CryptEccPointT *pResult, uint32_t *pCryptUsecs)
|
|
{
|
|
int32_t iResult;
|
|
|
|
if ((iResult = _CryptNistDoubleAndAdd(&pState->Ecc, &pState->Ecc.BasePoint, &pState->PrivateKey, &pState->Result)) == 0)
|
|
{
|
|
// copy the timing if passed in
|
|
if (pCryptUsecs != NULL)
|
|
{
|
|
*pCryptUsecs = pState->Ecc.uCryptUSecs;
|
|
}
|
|
/* copy the final result if a valid destination is provided (the caller can copy the result
|
|
later if desired) */
|
|
if (pResult != NULL)
|
|
{
|
|
ds_memcpy(pResult, &pState->Result, sizeof(*pResult));
|
|
}
|
|
}
|
|
return(iResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptNistSecret
|
|
|
|
\Description
|
|
Generates a shared secret
|
|
|
|
\Input *pState - curve state
|
|
\Input *pPublicKey - point as a basis to compute the shared secret
|
|
\Input *pResult - [out] point on the curve that represents the shared secret (optional)
|
|
\Input *pCryptUsecs - [out] timing information for the operation (optional)
|
|
|
|
\Output
|
|
int32_t - zero=success, otherwise=pending
|
|
|
|
\Notes
|
|
If pResult is NULL, the result can be taken from CryptNistT.Result
|
|
|
|
\Version 02/17/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CryptNistSecret(CryptNistDhT *pState, CryptEccPointT *pPublicKey, CryptEccPointT *pResult, uint32_t *pCryptUsecs)
|
|
{
|
|
int32_t iResult;
|
|
|
|
if ((iResult = _CryptNistDoubleAndAdd(&pState->Ecc, pPublicKey, &pState->PrivateKey, &pState->Result)) == 0)
|
|
{
|
|
// copy the timing if passed in
|
|
if (pCryptUsecs != NULL)
|
|
{
|
|
*pCryptUsecs = pState->Ecc.uCryptUSecs;
|
|
}
|
|
/* copy the final result if a valid destination is provided (the caller can copy the result
|
|
later if desired) */
|
|
if (pResult != NULL)
|
|
{
|
|
ds_memcpy(pResult, &pState->Result, sizeof(*pResult));
|
|
}
|
|
}
|
|
return(iResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptNistSign
|
|
|
|
\Description
|
|
Generates an elliptic curve dsa signature
|
|
|
|
\Input *pState - curve state
|
|
\Input *pPrivateKey - key used to sign
|
|
\Input *pHash - hash we are creating a signature for
|
|
\Input iHashSize - size of the hash
|
|
\Input *pSignature - [out] point on the curve that represents our signature (optional)
|
|
\Input *pCryptUsecs - [out] timing information for the operation (optional)
|
|
|
|
\Output
|
|
int32_t - zero=success, otherwise=pending
|
|
|
|
\Notes
|
|
If pSignature is NULL, the result can be taken from CryptNistT.Result
|
|
|
|
\Version 05/15/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CryptNistSign(CryptNistDsaT *pState, const CryptBnT *pPrivateKey, const uint8_t *pHash, int32_t iHashSize, CryptEccPointT *pSignature, uint32_t *pCryptUsecs)
|
|
{
|
|
int32_t iResult;
|
|
CryptNistT *pEcc = &pState->Ecc;
|
|
|
|
// generate a secret to the specified size
|
|
if (CryptBnBitLen(&pState->K) == 0)
|
|
{
|
|
_CryptNistDsaInitK(pEcc, pPrivateKey, pHash, iHashSize, &pState->K);
|
|
}
|
|
|
|
// calculate x,y using k * basepoint
|
|
if ((iResult = _CryptNistDoubleAndAdd(pEcc, &pEcc->BasePoint, &pState->K, &pState->Result)) == 0)
|
|
{
|
|
const uint64_t uTickUsecs = NetTickUsec();
|
|
CryptBnT Hash;
|
|
|
|
// r = x % order
|
|
CryptBnMod(&pState->Result.X, &pEcc->Order, &pState->Result.X, NULL);
|
|
|
|
// s1 = ((hash + r * private)
|
|
CryptBnInitFrom(&Hash, -1, pHash, iHashSize);
|
|
|
|
// truncate the hash if necessary
|
|
_CryptNistDsaInitHash(pEcc, pHash, iHashSize, &Hash);
|
|
|
|
CryptBnMultiply(&pState->Result.Y, &pState->Result.X, pPrivateKey);
|
|
CryptBnAccumulate(&pState->Result.Y, &Hash);
|
|
|
|
// s2 = inverse_mod(k, order)
|
|
CryptBnInverseMod(&pState->K, &pEcc->Order);
|
|
|
|
// s = s1 * s2 % order
|
|
CryptBnModMultiply(&pState->Result.Y, &pState->Result.Y, &pState->K, &pEcc->Order);
|
|
|
|
/* copy the final result if a valid destination is provided (the caller can copy the result
|
|
later if desired) */
|
|
if (pSignature != NULL)
|
|
{
|
|
ds_memcpy(pSignature, &pState->Result, sizeof(*pSignature));
|
|
}
|
|
|
|
// update profiler information
|
|
pEcc->uCryptUSecs += NetTickDiff(NetTickUsec(), uTickUsecs);
|
|
|
|
// copy the timing if passed in
|
|
if (pCryptUsecs != NULL)
|
|
{
|
|
*pCryptUsecs = pEcc->uCryptUSecs;
|
|
}
|
|
}
|
|
|
|
return(iResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptNistVerify
|
|
|
|
\Description
|
|
Verify the elliptic curve dsa signature
|
|
|
|
\Input *pState - curve state
|
|
\Input *pPublicKey - the public used for verifying the signature
|
|
\Input *pHash - hash we are verifying a signature for
|
|
\Input iHashSize - size of the hash
|
|
\Input *pSignature - point on the curve that represents our signature
|
|
\Input *pCryptUsecs - [out] timing information for the operation (optional)
|
|
|
|
\Output
|
|
int32_t - zero=success, >0=pending, <0=failure
|
|
|
|
\Version 05/15/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CryptNistVerify(CryptNistDsaT *pState, CryptEccPointT *pPublicKey, const uint8_t *pHash, int32_t iHashSize, CryptEccPointT *pSignature, uint32_t *pCryptUsecs)
|
|
{
|
|
int32_t iResult;
|
|
CryptNistT *pEcc = &pState->Ecc;
|
|
|
|
// initialize state if necessary
|
|
if (pEcc->iKeyIndex < 0)
|
|
{
|
|
CryptBnT S, Hash;
|
|
|
|
// truncate the hash if necessary
|
|
_CryptNistDsaInitHash(pEcc, pHash, iHashSize, &Hash);
|
|
|
|
// s' = inverse_mod(signature.s, order);
|
|
CryptBnClone(&S, &pSignature->Y);
|
|
CryptBnInverseMod(&S, &pEcc->Order);
|
|
|
|
// u1 = s' * hash % order
|
|
CryptBnModMultiply(&pState->U1, &Hash, &S, &pEcc->Order);
|
|
// u2 = s' * signature.r % order
|
|
CryptBnModMultiply(&pState->U2, &pSignature->X, &S, &pEcc->Order);
|
|
}
|
|
|
|
// result = (u1 * basepoint) + (u2 * publickey)
|
|
if ((iResult = _CryptNistDoubleMultiply(pEcc, &pEcc->BasePoint, &pState->U1, pPublicKey, &pState->U2, &pState->Result)) == 0)
|
|
{
|
|
// copy the timing if passed in
|
|
if (pCryptUsecs != NULL)
|
|
{
|
|
*pCryptUsecs = pEcc->uCryptUSecs;
|
|
}
|
|
// signature valid if result.x == signature.x
|
|
iResult = (memcmp(&pSignature->X, &pState->Result.X, sizeof(pSignature->X)) == 0) ? 0 : -1;
|
|
}
|
|
|
|
return(iResult);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptNistPointValidate
|
|
|
|
\Description
|
|
Validate that the point is on the curve
|
|
|
|
\Input *pState - curve state
|
|
\Input *pPoint - point we are validating
|
|
|
|
\Output
|
|
uint8_t - TRUE=on the curve, FALSE=not on the curve
|
|
|
|
\Version 02/17/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint8_t CryptNistPointValidate(const CryptNistDhT *pState, const CryptEccPointT *pPoint)
|
|
{
|
|
CryptBnT Result, X, Y, A;
|
|
const CryptNistT *pEcc = &pState->Ecc;
|
|
|
|
// a' = curve.a * x
|
|
CryptBnMultiply(&A, &pEcc->CoefficientA, &pPoint->X);
|
|
|
|
// y' = y * y
|
|
CryptBnMultiply(&Y, &pPoint->Y, &pPoint->Y);
|
|
|
|
// x' = x * x * x
|
|
CryptBnMultiply(&X, &pPoint->X, &pPoint->X);
|
|
CryptBnMultiply(&X, &X, &pPoint->X);
|
|
|
|
// result = y' - x' - a' - curve.b
|
|
CryptBnSubtract(&Result, &Y, &X);
|
|
CryptBnSubtract(&Result, &Result, &A);
|
|
CryptBnSubtract(&Result, &Result, &pEcc->CoefficientB);
|
|
|
|
CryptBnMod(&Result, &pEcc->Prime, &Result, NULL);
|
|
return(CryptBnBitLen(&Result) == 0);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptNistPointInitFrom
|
|
|
|
\Description
|
|
Loads a point from a buffer
|
|
|
|
\Input *pPoint - [out] the point we are writing the information to
|
|
\Input *pBuffer - buffer we are reading the point data from
|
|
\Input iBufLen - size of the buffer
|
|
|
|
\Output
|
|
int32_t - 0=success, negative=failure
|
|
|
|
\Notes
|
|
We only support reading uncompressed points
|
|
|
|
\Version 02/17/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CryptNistPointInitFrom(CryptEccPointT *pPoint, const uint8_t *pBuffer, int32_t iBufLen)
|
|
{
|
|
int32_t iPointLen = (iBufLen-1)/2;
|
|
|
|
// we only support uncompressed points, so ensure that this is the case
|
|
if (*pBuffer++ != CRYPTNIST_UNCOMPRESSED_MARKER)
|
|
{
|
|
NetPrintf(("cryptnist: could not initialize curve, base point in wrong format\n"));
|
|
return(-1);
|
|
}
|
|
CryptBnInitFrom(&pPoint->X, -1, pBuffer, iPointLen);
|
|
CryptBnInitFrom(&pPoint->Y, -1, pBuffer+iPointLen, iPointLen);
|
|
return(0);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptNistPointFinal
|
|
|
|
\Description
|
|
Loads a point into a buffer for dh
|
|
|
|
\Input *pState - curve state
|
|
\Input *pPoint - point state or NULL to use curve result
|
|
\Input bSecret - is this the shared secret? (only need x)
|
|
\Input *pBuffer - buffer we are writing the point data to
|
|
\Input iBufLen - size of the buffer
|
|
|
|
\Output
|
|
int32_t - 0=success, negative=failure
|
|
|
|
\Notes
|
|
We only support writing uncompressed points
|
|
|
|
\Version 02/17/2017 (eesponda)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CryptNistPointFinal(const CryptNistDhT *pState, const CryptEccPointT *pPoint, uint8_t bSecret, uint8_t *pBuffer, int32_t iBufLen)
|
|
{
|
|
if ((pState != NULL) && (pPoint == NULL))
|
|
{
|
|
pPoint = &pState->Result;
|
|
}
|
|
const int32_t iXSize = CryptBnByteLen(&pPoint->X);
|
|
const int32_t iYSize = CryptBnByteLen(&pPoint->Y);
|
|
const int32_t iOutputSize = !bSecret ? (iXSize + iYSize + 1) : iXSize;
|
|
|
|
if (iBufLen < iOutputSize)
|
|
{
|
|
NetPrintf(("cryptnist: not enough space in output buffer to encode points\n"));
|
|
return(-1);
|
|
}
|
|
|
|
if (!bSecret)
|
|
{
|
|
*pBuffer++ = CRYPTNIST_UNCOMPRESSED_MARKER;
|
|
CryptBnFinal(&pPoint->X, pBuffer, iXSize);
|
|
CryptBnFinal(&pPoint->Y, pBuffer+iXSize, iYSize);
|
|
}
|
|
else
|
|
{
|
|
CryptBnFinal(&pPoint->X, pBuffer, iXSize);
|
|
}
|
|
return(iOutputSize);
|
|
}
|