/* Microsoft Reference Implementation for TPM 2.0 | |
* | |
* The copyright in this software is being made available under the BSD License, | |
* included below. This software may be subject to other third party and | |
* contributor rights, including patent rights, and no such rights are granted | |
* under this license. | |
* | |
* Copyright (c) Microsoft Corporation | |
* | |
* All rights reserved. | |
* | |
* BSD License | |
* | |
* Redistribution and use in source and binary forms, with or without modification, | |
* are permitted provided that the following conditions are met: | |
* | |
* Redistributions of source code must retain the above copyright notice, this list | |
* of conditions and the following disclaimer. | |
* | |
* Redistributions in binary form must reproduce the above copyright notice, this | |
* list of conditions and the following disclaimer in the documentation and/or other | |
* materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" | |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
//** Introduction | |
// | |
// This file contains the math functions that are not implemented in the BnMath | |
// library (yet). These math functions will call the wolfcrypt library to execute | |
// the operations. There is a difference between the internal format and the | |
// wolfcrypt format. To call the wolfcrypt function, a mp_int structure is created | |
// for each passed variable. We define USE_FAST_MATH wolfcrypt option, which allocates | |
// mp_int on the stack. We must copy each word to the new structure, and set the used | |
// size. | |
// | |
// Not using USE_FAST_MATH would allow for a simple pointer swap for the big integer | |
// buffer 'd', however wolfcrypt expects to manage this memory, and will swap out | |
// the pointer to and from temporary variables and free the reference underneath us. | |
// Using USE_FAST_MATH also instructs wolfcrypt to use the stack for all these | |
// intermediate variables | |
//** Includes and Defines | |
#include "Tpm.h" | |
#ifdef MATH_LIB_WOLF | |
#include "BnConvert_fp.h" | |
#include "TpmToWolfMath_fp.h" | |
#define WOLF_HALF_RADIX (RADIX_BITS == 64 && !defined(FP_64BIT)) | |
//** Functions | |
//*** BnFromWolf() | |
// This function converts a wolfcrypt mp_int to a TPM bignum. In this implementation | |
// it is assumed that wolfcrypt used the same format for a big number as does the | |
// TPM -- an array of native-endian words in little-endian order. | |
void | |
BnFromWolf( | |
bigNum bn, | |
mp_int *wolfBn | |
) | |
{ | |
if(bn != NULL) | |
{ | |
int i; | |
#if WOLF_HALF_RADIX | |
pAssert((unsigned)wolfBn->used <= 2 * BnGetAllocated(bn)); | |
#else | |
pAssert((unsigned)wolfBn->used <= BnGetAllocated(bn)); | |
#endif | |
for (i = 0; i < wolfBn->used; i++) | |
{ | |
#if WOLF_HALF_RADIX | |
if (i & 1) | |
bn->d[i/2] |= (crypt_uword_t)wolfBn->dp[i] << 32; | |
else | |
bn->d[i/2] = wolfBn->dp[i]; | |
#else | |
bn->d[i] = wolfBn->dp[i]; | |
#endif | |
} | |
#if WOLF_HALF_RADIX | |
BnSetTop(bn, (wolfBn->used + 1)/2); | |
#else | |
BnSetTop(bn, wolfBn->used); | |
#endif | |
} | |
} | |
//*** BnToWolf() | |
// This function converts a TPM bignum to a wolfcrypt mp_init, and has the same | |
// assumptions as made by BnFromWolf() | |
void | |
BnToWolf( | |
mp_int *toInit, | |
bigConst initializer | |
) | |
{ | |
uint32_t i; | |
if (toInit != NULL && initializer != NULL) | |
{ | |
for (i = 0; i < initializer->size; i++) | |
{ | |
#if WOLF_HALF_RADIX | |
toInit->dp[2 * i] = (fp_digit)initializer->d[i]; | |
toInit->dp[2 * i + 1] = (fp_digit)(initializer->d[i] >> 32); | |
#else | |
toInit->dp[i] = initializer->d[i]; | |
#endif | |
} | |
#if WOLF_HALF_RADIX | |
toInit->used = (int)initializer->size * 2; | |
if (toInit->dp[toInit->used - 1] == 0 && toInit->dp[toInit->used - 2] != 0) | |
--toInit->used; | |
#else | |
toInit->used = (int)initializer->size; | |
#endif | |
toInit->sign = 0; | |
} | |
} | |
//*** MpInitialize() | |
// This function initializes an wolfcrypt mp_int. | |
mp_int * | |
MpInitialize( | |
mp_int *toInit | |
) | |
{ | |
mp_init( toInit ); | |
return toInit; | |
} | |
#if LIBRARY_COMPATIBILITY_CHECK | |
//** MathLibraryCompatibililtyCheck() | |
// This function is only used during development to make sure that the library | |
// that is being referenced is using the same size of data structures as the TPM. | |
BOOL | |
MathLibraryCompatibilityCheck( | |
void | |
) | |
{ | |
BN_VAR(tpmTemp, 64 * 8); // allocate some space for a test value | |
crypt_uword_t i; | |
TPM2B_TYPE(TEST, 16); | |
TPM2B_TEST test = {{16, {0x0F, 0x0E, 0x0D, 0x0C, | |
0x0B, 0x0A, 0x09, 0x08, | |
0x07, 0x06, 0x05, 0x04, | |
0x03, 0x02, 0x01, 0x00}}}; | |
// Convert the test TPM2B to a bigNum | |
BnFrom2B(tpmTemp, &test.b); | |
MP_INITIALIZED(wolfTemp, tpmTemp); | |
(wolfTemp); // compiler warning | |
// Make sure the values are consistent | |
VERIFY(wolfTemp->used * sizeof(fp_digit) == (int)tpmTemp->size * sizeof(crypt_uword_t)); | |
for(i = 0; i < tpmTemp->size; i++) | |
VERIFY(((crypt_uword_t*)wolfTemp->dp)[i] == tpmTemp->d[i]); | |
return 1; | |
Error: | |
return 0; | |
} | |
#endif | |
//*** BnModMult() | |
// Does multiply and divide returning the remainder of the divide. | |
LIB_EXPORT BOOL | |
BnModMult( | |
bigNum result, | |
bigConst op1, | |
bigConst op2, | |
bigConst modulus | |
) | |
{ | |
WOLF_ENTER(); | |
BOOL OK; | |
MP_INITIALIZED(bnOp1, op1); | |
MP_INITIALIZED(bnOp2, op2); | |
MP_INITIALIZED(bnTemp, NULL); | |
BN_VAR(temp, LARGEST_NUMBER_BITS * 2); | |
pAssert(BnGetAllocated(result) >= BnGetSize(modulus)); | |
OK = (mp_mul( bnOp1, bnOp2, bnTemp ) == MP_OKAY); | |
if(OK) | |
{ | |
BnFromWolf(temp, bnTemp); | |
OK = BnDiv(NULL, result, temp, modulus); | |
} | |
WOLF_LEAVE(); | |
return OK; | |
} | |
//*** BnMult() | |
// Multiplies two numbers | |
LIB_EXPORT BOOL | |
BnMult( | |
bigNum result, | |
bigConst multiplicand, | |
bigConst multiplier | |
) | |
{ | |
WOLF_ENTER(); | |
BOOL OK; | |
MP_INITIALIZED(bnTemp, NULL); | |
MP_INITIALIZED(bnA, multiplicand); | |
MP_INITIALIZED(bnB, multiplier); | |
pAssert(result->allocated >= | |
(BITS_TO_CRYPT_WORDS(BnSizeInBits(multiplicand) | |
+ BnSizeInBits(multiplier)))); | |
OK = (mp_mul( bnA, bnB, bnTemp ) == MP_OKAY); | |
if(OK) | |
{ | |
BnFromWolf(result, bnTemp); | |
} | |
WOLF_LEAVE(); | |
return OK; | |
} | |
//*** BnDiv() | |
// This function divides two bigNum values. The function returns FALSE if | |
// there is an error in the operation. | |
LIB_EXPORT BOOL | |
BnDiv( | |
bigNum quotient, | |
bigNum remainder, | |
bigConst dividend, | |
bigConst divisor | |
) | |
{ | |
WOLF_ENTER(); | |
BOOL OK; | |
MP_INITIALIZED(bnQ, quotient); | |
MP_INITIALIZED(bnR, remainder); | |
MP_INITIALIZED(bnDend, dividend); | |
MP_INITIALIZED(bnSor, divisor); | |
pAssert(!BnEqualZero(divisor)); | |
if(BnGetSize(dividend) < BnGetSize(divisor)) | |
{ | |
if(quotient) | |
BnSetWord(quotient, 0); | |
if(remainder) | |
BnCopy(remainder, dividend); | |
OK = TRUE; | |
} | |
else | |
{ | |
pAssert((quotient == NULL) | |
|| (quotient->allocated >= (unsigned)(dividend->size | |
- divisor->size))); | |
pAssert((remainder == NULL) | |
|| (remainder->allocated >= divisor->size)); | |
OK = (mp_div(bnDend , bnSor, bnQ, bnR) == MP_OKAY); | |
if(OK) | |
{ | |
BnFromWolf(quotient, bnQ); | |
BnFromWolf(remainder, bnR); | |
} | |
} | |
WOLF_LEAVE(); | |
return OK; | |
} | |
#if ALG_RSA | |
//*** BnGcd() | |
// Get the greatest common divisor of two numbers | |
LIB_EXPORT BOOL | |
BnGcd( | |
bigNum gcd, // OUT: the common divisor | |
bigConst number1, // IN: | |
bigConst number2 // IN: | |
) | |
{ | |
WOLF_ENTER(); | |
BOOL OK; | |
MP_INITIALIZED(bnGcd, gcd); | |
MP_INITIALIZED(bn1, number1); | |
MP_INITIALIZED(bn2, number2); | |
pAssert(gcd != NULL); | |
OK = (mp_gcd( bn1, bn2, bnGcd ) == MP_OKAY); | |
if(OK) | |
{ | |
BnFromWolf(gcd, bnGcd); | |
} | |
WOLF_LEAVE(); | |
return OK; | |
} | |
//***BnModExp() | |
// Do modular exponentiation using bigNum values. The conversion from a mp_int to | |
// a bigNum is trivial as they are based on the same structure | |
LIB_EXPORT BOOL | |
BnModExp( | |
bigNum result, // OUT: the result | |
bigConst number, // IN: number to exponentiate | |
bigConst exponent, // IN: | |
bigConst modulus // IN: | |
) | |
{ | |
WOLF_ENTER(); | |
BOOL OK; | |
MP_INITIALIZED(bnResult, result); | |
MP_INITIALIZED(bnN, number); | |
MP_INITIALIZED(bnE, exponent); | |
MP_INITIALIZED(bnM, modulus); | |
OK = (mp_exptmod( bnN, bnE, bnM, bnResult ) == MP_OKAY); | |
if(OK) | |
{ | |
BnFromWolf(result, bnResult); | |
} | |
WOLF_LEAVE(); | |
return OK; | |
} | |
//*** BnModInverse() | |
// Modular multiplicative inverse | |
LIB_EXPORT BOOL | |
BnModInverse( | |
bigNum result, | |
bigConst number, | |
bigConst modulus | |
) | |
{ | |
WOLF_ENTER(); | |
BOOL OK; | |
MP_INITIALIZED(bnResult, result); | |
MP_INITIALIZED(bnN, number); | |
MP_INITIALIZED(bnM, modulus); | |
OK = (mp_invmod(bnN, bnM, bnResult) == MP_OKAY); | |
if(OK) | |
{ | |
BnFromWolf(result, bnResult); | |
} | |
WOLF_LEAVE(); | |
return OK; | |
} | |
#endif // TPM_ALG_RSA | |
#if ALG_ECC | |
//*** PointFromWolf() | |
// Function to copy the point result from a wolf ecc_point to a bigNum | |
void | |
PointFromWolf( | |
bigPoint pOut, // OUT: resulting point | |
ecc_point *pIn // IN: the point to return | |
) | |
{ | |
BnFromWolf(pOut->x, pIn->x); | |
BnFromWolf(pOut->y, pIn->y); | |
BnFromWolf(pOut->z, pIn->z); | |
} | |
//*** PointToWolf() | |
// Function to copy the point result from a bigNum to a wolf ecc_point | |
void | |
PointToWolf( | |
ecc_point *pOut, // OUT: resulting point | |
pointConst pIn // IN: the point to return | |
) | |
{ | |
BnToWolf(pOut->x, pIn->x); | |
BnToWolf(pOut->y, pIn->y); | |
BnToWolf(pOut->z, pIn->z); | |
} | |
//*** EcPointInitialized() | |
// Allocate and initialize a point. | |
static ecc_point * | |
EcPointInitialized( | |
pointConst initializer | |
) | |
{ | |
ecc_point *P; | |
P = wc_ecc_new_point(); | |
pAssert(P != NULL); | |
// mp_int x,y,z are stack allocated. | |
// initializer is not required | |
if (P != NULL && initializer != NULL) | |
{ | |
PointToWolf( P, initializer ); | |
} | |
return P; | |
} | |
//*** BnEccModMult() | |
// This function does a point multiply of the form R = [d]S | |
// return type: BOOL | |
// FALSE failure in operation; treat as result being point at infinity | |
LIB_EXPORT BOOL | |
BnEccModMult( | |
bigPoint R, // OUT: computed point | |
pointConst S, // IN: point to multiply by 'd' (optional) | |
bigConst d, // IN: scalar for [d]S | |
bigCurve E | |
) | |
{ | |
WOLF_ENTER(); | |
BOOL OK; | |
MP_INITIALIZED(bnD, d); | |
MP_INITIALIZED(bnPrime, CurveGetPrime(E)); | |
POINT_CREATE(pS, NULL); | |
POINT_CREATE(pR, NULL); | |
if(S == NULL) | |
S = CurveGetG(AccessCurveData(E)); | |
PointToWolf(pS, S); | |
OK = (wc_ecc_mulmod(bnD, pS, pR, NULL, bnPrime, 1 ) == MP_OKAY); | |
if(OK) | |
{ | |
PointFromWolf(R, pR); | |
} | |
POINT_DELETE(pR); | |
POINT_DELETE(pS); | |
WOLF_LEAVE(); | |
return !BnEqualZero(R->z); | |
} | |
//*** BnEccModMult2() | |
// This function does a point multiply of the form R = [d]G + [u]Q | |
// return type: BOOL | |
// FALSE failure in operation; treat as result being point at infinity | |
LIB_EXPORT BOOL | |
BnEccModMult2( | |
bigPoint R, // OUT: computed point | |
pointConst S, // IN: optional point | |
bigConst d, // IN: scalar for [d]S or [d]G | |
pointConst Q, // IN: second point | |
bigConst u, // IN: second scalar | |
bigCurve E // IN: curve | |
) | |
{ | |
WOLF_ENTER(); | |
BOOL OK; | |
POINT_CREATE(pR, NULL); | |
POINT_CREATE(pS, NULL); | |
POINT_CREATE(pQ, Q); | |
MP_INITIALIZED(bnD, d); | |
MP_INITIALIZED(bnU, u); | |
MP_INITIALIZED(bnPrime, CurveGetPrime(E)); | |
MP_INITIALIZED(bnA, CurveGet_a(E)); | |
if(S == NULL) | |
S = CurveGetG(AccessCurveData(E)); | |
PointToWolf( pS, S ); | |
OK = (ecc_mul2add(pS, bnD, pQ, bnU, pR, bnA, bnPrime, NULL) == MP_OKAY); | |
if(OK) | |
{ | |
PointFromWolf(R, pR); | |
} | |
POINT_DELETE(pS); | |
POINT_DELETE(pQ); | |
POINT_DELETE(pR); | |
WOLF_LEAVE(); | |
return !BnEqualZero(R->z); | |
} | |
//** BnEccAdd() | |
// This function does addition of two points. | |
// return type: BOOL | |
// FALSE failure in operation; treat as result being point at infinity | |
LIB_EXPORT BOOL | |
BnEccAdd( | |
bigPoint R, // OUT: computed point | |
pointConst S, // IN: point to multiply by 'd' | |
pointConst Q, // IN: second point | |
bigCurve E // IN: curve | |
) | |
{ | |
WOLF_ENTER(); | |
BOOL OK; | |
mp_digit mp; | |
POINT_CREATE(pR, NULL); | |
POINT_CREATE(pS, S); | |
POINT_CREATE(pQ, Q); | |
MP_INITIALIZED(bnA, CurveGet_a(E)); | |
MP_INITIALIZED(bnMod, CurveGetPrime(E)); | |
// | |
OK = (mp_montgomery_setup(bnMod, &mp) == MP_OKAY); | |
OK = OK && (ecc_projective_add_point(pS, pQ, pR, bnA, bnMod, mp ) == MP_OKAY); | |
if(OK) | |
{ | |
PointFromWolf(R, pR); | |
} | |
POINT_DELETE(pS); | |
POINT_DELETE(pQ); | |
POINT_DELETE(pR); | |
WOLF_LEAVE(); | |
return !BnEqualZero(R->z); | |
} | |
#endif // TPM_ALG_ECC | |
#endif // MATH_LIB_WOLF |