/* 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 ST MPA library or the // LibTomCrypt library to execute the operations. Since the TPM internal big number // format is identical to the MPA format, no reformatting is required. //** Includes #include "Tpm.h" #ifdef MATH_LIB_LTC #if defined ECC_NIST_P256 && ECC_NIST_P256 == YES && ECC_CURVE_COUNT > 1 #error "LibTomCrypt only supports P256" #endif //** Functions //*** BnModMult() // Does multiply and divide returning the remainder of the divide. LIB_EXPORT BOOL BnModMult( bigNum result, bigConst op1, bigConst op2, bigConst modulus ) { BN_VAR(temp, LARGEST_NUMBER_BITS * 2); // mpa_mul does not allocate from the pool if the result is not the same as // op1 or op2. since this is assured by the stack allocation of 'temp', the // pool pointer can be NULL pAssert(BnGetAllocated(result) >= BnGetSize(modulus)); mpa_mul((mpanum)temp, (const mpanum)op1, (const mpanum)op2, NULL); return BnDiv(NULL, result, temp, modulus); } //*** BnMult() // Multiplies two numbers LIB_EXPORT BOOL BnMult( bigNum result, bigConst multiplicand, bigConst multiplier ) { // Make sure that the mpa_mul function does not allocate anything // from the POOL by eliminating the reason for doing it. BN_VAR(tempResult, LARGEST_NUMBER_BITS * 2); if(result != multiplicand && result != multiplier) tempResult = result; mpa_mul((mpanum)tempResult, (const mpanum)multiplicand, (const mpanum)multiplier, NULL); BnCopy(result, tempResult); return TRUE; } //*** BnDiv() // This function divides two BIGNUM values. The function always returns TRUE. LIB_EXPORT BOOL BnDiv( bigNum quotient, bigNum remainder, bigConst dividend, bigConst divisor ) { MPA_ENTER(10, LARGEST_NUMBER_BITS); pAssert(!BnEqualZero(divisor)); if(BnGetSize(dividend) < BnGetSize(divisor)) { if(quotient) BnSetWord(quotient, 0); if(remainder) BnCopy(remainder, dividend); } else { pAssert((quotient == NULL) || (quotient->allocated >= (unsigned)(dividend->size - divisor->size))); pAssert((remainder == NULL) || (remainder->allocated >= divisor->size)); mpa_div((mpanum)quotient, (mpanum)remainder, (const mpanum)dividend, (const mpanum)divisor, POOL); } MPA_LEAVE(); return TRUE; } #ifdef TPM_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: ) { MPA_ENTER(20, LARGEST_NUMBER_BITS); // mpa_gcd((mpanum)gcd, (mpanum)number1, (mpanum)number2, POOL); MPA_LEAVE(); return TRUE; } //***BnModExp() // Do modular exponentiation using BIGNUM values. The conversion from a bignum_t // 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: ) { MPA_ENTER(20, LARGEST_NUMBER_BITS); BN_VAR(bnR, MAX_RSA_KEY_BITS); BN_VAR(bnR2, MAX_RSA_KEY_BITS); mpa_word_t n_inv; mpa_word_t ffmCtx[mpa_fmm_context_size_in_U32(MAX_RSA_KEY_BITS)]; // mpa_init_static_fmm_context((mpa_fmm_context_base *)ffmCtx, BYTES_TO_CRYPT_WORDS(sizeof(ffmCtx))); // Generate modular form if(mpa_compute_fmm_context((const mpanum)modulus, (mpanum)bnR, (mpanum)bnR2, &n_inv, POOL) != 0) FAIL(FATAL_ERROR_INTERNAL); // Do exponentiation mpa_exp_mod((mpanum)result, (const mpanum)number, (const mpanum)exponent, (const mpanum)modulus, (const mpanum)bnR, (const mpanum)bnR2, n_inv, POOL); MPA_LEAVE(); return TRUE; } //*** BnModInverse() // Modular multiplicative inverse LIB_EXPORT BOOL BnModInverse( bigNum result, bigConst number, bigConst modulus ) { BOOL retVal; MPA_ENTER(10, LARGEST_NUMBER_BITS); retVal = (mpa_inv_mod((mpanum)result, (const mpanum)number, (const mpanum)modulus, POOL) == 0); MPA_LEAVE(); return retVal; } #endif // TPM_ALG_RSA #ifdef TPM_ALG_ECC //*** 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' bigConst d, // IN: scalar for [d]S bigCurve E ) { MPA_ENTER(30, MAX_ECC_KEY_BITS * 2); // The point multiply in LTC seems to need a large reciprocal for // intermediate results POINT_VAR(result, MAX_ECC_KEY_BITS * 4); BOOL OK; // (POOL); // Avoid compiler warning if(S == NULL) S = CurveGetG(AccessCurveData(E)); OK = (ltc_ecc_mulmod((mpanum)d, (ecc_point *)S, (ecc_point *)result, (void *)CurveGetPrime(E), 1) == CRYPT_OK); OK = OK && !BnEqualZero(result->z); if(OK) BnPointCopy(R, result); MPA_LEAVE(); return OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT; } //*** BnEccModMult2() // This function does a point multiply of the form R = [d]S + [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: first point (optional) bigConst d, // IN: scalar for [d]S or [d]G pointConst Q, // IN: second point bigConst u, // IN: second scalar bigCurve E // IN: curve ) { MPA_ENTER(80, MAX_ECC_KEY_BITS); BOOL OK; // The point multiply in LTC seems to need a large reciprocal for // intermediate results POINT_VAR(result, MAX_ECC_KEY_BITS * 4); // (POOL); // Avoid compiler warning if(S == NULL) S = CurveGetG(AccessCurveData(E)); OK = (ltc_ecc_mul2add((ecc_point *)S, (mpanum)d, (ecc_point *)Q, (mpanum)u, (ecc_point *)result, (mpanum)CurveGetPrime(E)) == CRYPT_OK); OK = OK && !BnEqualZero(result->z); if(OK) BnPointCopy(R, result); MPA_LEAVE(); return OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT; } //*** BnEccAdd() // This function does addition of two points. Since this is not implemented // in LibTomCrypt() will try to trick it by doing multiply with scalar of 1. // I have no idea if this will work and it's not needed unless MQV or the SM2 // variant is enabled. // 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 ) { BN_WORD_INITIALIZED(one, 1); return BnEccModMult2(R, S, one, Q, one, E); } #endif // TPM_ALG_ECC #endif // MATH_LIB_LTC