// This file was extracted from the TCG Published // Trusted Platform Module Library // Part 4: Supporting Routines // Family "2.0" // Level 00 Revision 01.16 // October 30, 2014 #include <string.h> #include "OsslCryptoEngine.h" // // // Externally Accessible Functions // // _math__Normalize2B() // // This function will normalize the value in a TPM2B. If there are leading bytes of zero, the first non-zero // byte is shifted up. // // Return Value Meaning // // 0 no significant bytes, value is zero // >0 number of significant bytes // LIB_EXPORT UINT16 _math__Normalize2B( TPM2B *b // IN/OUT: number to normalize ) { UINT16 from; UINT16 to; UINT16 size = b->size; for(from = 0; b->buffer[from] == 0 && from < size; from++); b->size -= from; for(to = 0; from < size; to++, from++ ) b->buffer[to] = b->buffer[from]; return b->size; } // // // // _math__Denormalize2B() // // This function is used to adjust a TPM2B so that the number has the desired number of bytes. This is // accomplished by adding bytes of zero at the start of the number. // // Return Value Meaning // // TRUE number de-normalized // FALSE number already larger than the desired size // LIB_EXPORT BOOL _math__Denormalize2B( TPM2B *in, // IN:OUT TPM2B number to de-normalize UINT32 size // IN: the desired size ) { UINT32 to; UINT32 from; // If the current size is greater than the requested size, see if this can be // normalized to a value smaller than the requested size and then de-normalize if(in->size > size) { _math__Normalize2B(in); if(in->size > size) return FALSE; } // If the size is already what is requested, leave if(in->size == size) return TRUE; // move the bytes to the 'right' for(from = in->size, to = size; from > 0;) in->buffer[--to] = in->buffer[--from]; // 'to' will always be greater than 0 because we checked for equal above. for(; to > 0;) in->buffer[--to] = 0; in->size = (UINT16)size; return TRUE; } // // // _math__sub() // // This function to subtract one unsigned value from another c = a - b. c may be the same as a or b. // // Return Value Meaning // // 1 if (a > b) so no borrow // 0 if (a = b) so no borrow and b == a // -1 if (a < b) so there was a borrow // LIB_EXPORT int _math__sub( const UINT32 aSize, // IN: size of a const BYTE *a, // IN: a const UINT32 bSize, // IN: size of b const BYTE *b, // IN: b UINT16 *cSize, // OUT: set to MAX(aSize, bSize) BYTE *c // OUT: the difference ) { int borrow = 0; int notZero = 0; int i; int i2; // set c to the longer of a or b *cSize = (UINT16)((aSize > bSize) ? aSize : bSize); // pick the shorter of a and b i = (aSize > bSize) ? bSize : aSize; i2 = *cSize - i; a = &a[aSize - 1]; b = &b[bSize - 1]; c = &c[*cSize - 1]; for(; i > 0; i--) { borrow = *a-- - *b-- + borrow; *c-- = (BYTE)borrow; notZero = notZero || borrow; borrow >>= 8; } if(aSize > bSize) { for(;i2 > 0; i2--) { borrow = *a-- + borrow; *c-- = (BYTE)borrow; notZero = notZero || borrow; borrow >>= 8; } } else if(aSize < bSize) { for(;i2 > 0; i2--) { borrow = 0 - *b-- + borrow; *c-- = (BYTE)borrow; notZero = notZero || borrow; borrow >>= 8; } } // if there is a borrow, then b > a if(borrow) return -1; // either a > b or they are the same return notZero; } // // // _math__Inc() // // This function increments a large, big-endian number value by one. // // Return Value Meaning // // 0 result is zero // !0 result is not zero // LIB_EXPORT int _math__Inc( UINT32 aSize, // IN: size of a BYTE *a // IN: a ) { // for(a = &a[aSize-1];aSize > 0; aSize--) { if((*a-- += 1) != 0) return 1; } return 0; } // // // _math__Dec() // // This function decrements a large, ENDIAN value by one. // LIB_EXPORT void _math__Dec( UINT32 aSize, // IN: size of a BYTE *a // IN: a ) { for(a = &a[aSize-1]; aSize > 0; aSize--) { if((*a-- -= 1) != 0xff) return; } return; } // // // _math__Mul() // // This function is used to multiply two large integers: p = a* b. If the size of p is not specified (pSize == // NULL), the size of the results p is assumed to be aSize + bSize and the results are de-normalized so that // the resulting size is exactly aSize + bSize. If pSize is provided, then the actual size of the result is // returned. The initial value for pSize must be at least aSize + pSize. // // Return Value Meaning // // <0 indicates an error // >= 0 the size of the product // LIB_EXPORT int _math__Mul( const UINT32 aSize, // IN: size of a const BYTE *a, // IN: a const UINT32 bSize, // IN: size of b const BYTE *b, // IN: b UINT32 *pSize, // IN/OUT: size of the product BYTE *p // OUT: product. length of product = aSize + // bSize ) { BIGNUM *bnA; BIGNUM *bnB; BIGNUM *bnP; BN_CTX *context; int retVal = 0; // First check that pSize is large enough if present if((pSize != NULL) && (*pSize < (aSize + bSize))) return CRYPT_PARAMETER; pAssert(pSize == NULL || *pSize <= MAX_2B_BYTES); // // // Allocate space for BIGNUM context // context = BN_CTX_new(); if(context == NULL) FAIL(FATAL_ERROR_ALLOCATION); bnA = BN_CTX_get(context); bnB = BN_CTX_get(context); bnP = BN_CTX_get(context); if (bnP == NULL) FAIL(FATAL_ERROR_ALLOCATION); // Convert the inputs to BIGNUMs // if (BN_bin2bn(a, aSize, bnA) == NULL || BN_bin2bn(b, bSize, bnB) == NULL) FAIL(FATAL_ERROR_INTERNAL); // Perform the multiplication // if (BN_mul(bnP, bnA, bnB, context) != 1) FAIL(FATAL_ERROR_INTERNAL); // If the size of the results is allowed to float, then set the return // size. Otherwise, it might be necessary to de-normalize the results retVal = BN_num_bytes(bnP); if(pSize == NULL) { BN_bn2bin(bnP, &p[aSize + bSize - retVal]); memset(p, 0, aSize + bSize - retVal); retVal = aSize + bSize; } else { BN_bn2bin(bnP, p); *pSize = retVal; } BN_CTX_end(context); BN_CTX_free(context); return retVal; } // // // _math__Div() // // Divide an integer (n) by an integer (d) producing a quotient (q) and a remainder (r). If q or r is not needed, // then the pointer to them may be set to NULL. // // Return Value Meaning // // CRYPT_SUCCESS operation complete // CRYPT_UNDERFLOW q or r is too small to receive the result // LIB_EXPORT CRYPT_RESULT _math__Div( const TPM2B *n, // IN: numerator const TPM2B *d, // IN: denominator TPM2B *q, // OUT: quotient TPM2B *r // OUT: remainder ) { BIGNUM *bnN; BIGNUM *bnD; BIGNUM *bnQ; BIGNUM *bnR; BN_CTX *context; CRYPT_RESULT retVal = CRYPT_SUCCESS; // Get structures for the big number representations context = BN_CTX_new(); if(context == NULL) FAIL(FATAL_ERROR_ALLOCATION); BN_CTX_start(context); bnN = BN_CTX_get(context); bnD = BN_CTX_get(context); bnQ = BN_CTX_get(context); bnR = BN_CTX_get(context); // Errors in BN_CTX_get() are sticky so only need to check the last allocation if ( bnR == NULL || BN_bin2bn(n->buffer, n->size, bnN) == NULL || BN_bin2bn(d->buffer, d->size, bnD) == NULL) FAIL(FATAL_ERROR_INTERNAL); // Check for divide by zero. if(BN_num_bits(bnD) == 0) FAIL(FATAL_ERROR_DIVIDE_ZERO); // Perform the division if (BN_div(bnQ, bnR, bnN, bnD, context) != 1) FAIL(FATAL_ERROR_INTERNAL); // Convert the BIGNUM result back to our format if(q != NULL) // If the quotient is being returned { if(!BnTo2B(q, bnQ, q->size)) { retVal = CRYPT_UNDERFLOW; goto Done; } } if(r != NULL) // If the remainder is being returned { if(!BnTo2B(r, bnR, r->size)) retVal = CRYPT_UNDERFLOW; } Done: BN_CTX_end(context); BN_CTX_free(context); return retVal; } // // // _math__uComp() // // This function compare two unsigned values. // // Return Value Meaning // // 1 if (a > b) // 0 if (a = b) // -1 if (a < b) // LIB_EXPORT int _math__uComp( const UINT32 aSize, // IN: size of a const BYTE *a, // IN: a const UINT32 bSize, // IN: size of b const BYTE *b // IN: b ) { int borrow = 0; int notZero = 0; int i; // If a has more digits than b, then a is greater than b if // any of the more significant bytes is non zero if((i = (int)aSize - (int)bSize) > 0) for(; i > 0; i--) if(*a++) // means a > b return 1; // If b has more digits than a, then b is greater if any of the // more significant bytes is non zero if(i < 0) // Means that b is longer than a for(; i < 0; i++) if(*b++) // means that b > a return -1; // Either the vales are the same size or the upper bytes of a or b are // all zero, so compare the rest i = (aSize > bSize) ? bSize : aSize; a = &a[i-1]; b = &b[i-1]; for(; i > 0; i--) { borrow = *a-- - *b-- + borrow; notZero = notZero || borrow; borrow >>= 8; } // if there is a borrow, then b > a if(borrow) return -1; // either a > b or they are the same return notZero; } // // // _math__Comp() // // Compare two signed integers: // // Return Value Meaning // // 1 if a > b // 0 if a = b // -1 if a < b // LIB_EXPORT int _math__Comp( const UINT32 aSize, // IN: size of a const BYTE *a, // IN: a buffer const UINT32 bSize, // IN: size of b const BYTE *b // IN: b buffer ) { int signA, signB; // sign of a and b // For positive or 0, sign_a is 1 // for negative, sign_a is 0 signA = ((a[0] & 0x80) == 0) ? 1 : 0; // For positive or 0, sign_b is 1 // for negative, sign_b is 0 signB = ((b[0] & 0x80) == 0) ? 1 : 0; if(signA != signB) { return signA - signB; } if(signA == 1) // do unsigned compare function return _math__uComp(aSize, a, bSize, b); else // do unsigned compare the other way return 0 - _math__uComp(aSize, a, bSize, b); } // // // _math__ModExp // // This function is used to do modular exponentiation in support of RSA. The most typical uses are: c = m^e // mod n (RSA encrypt) and m = c^d mod n (RSA decrypt). When doing decryption, the e parameter of the // function will contain the private exponent d instead of the public exponent e. // If the results will not fit in the provided buffer, an error is returned (CRYPT_ERROR_UNDERFLOW). If // the results is smaller than the buffer, the results is de-normalized. // This version is intended for use with RSA and requires that m be less than n. // // Return Value Meaning // // CRYPT_SUCCESS exponentiation succeeded // CRYPT_PARAMETER number to exponentiate is larger than the modulus // CRYPT_UNDERFLOW result will not fit into the provided buffer // LIB_EXPORT CRYPT_RESULT _math__ModExp( UINT32 cSize, // IN: size of the result BYTE *c, // OUT: results buffer const UINT32 mSize, // IN: size of number to be exponentiated const BYTE *m, // IN: number to be exponentiated const UINT32 eSize, // IN: size of power const BYTE *e, // IN: power const UINT32 nSize, // IN: modulus size const BYTE *n // IN: modulu ) { CRYPT_RESULT retVal = CRYPT_SUCCESS; BN_CTX *context; BIGNUM *bnC; BIGNUM *bnM; BIGNUM *bnE; BIGNUM *bnN; INT32 i; context = BN_CTX_new(); if(context == NULL) FAIL(FATAL_ERROR_ALLOCATION); BN_CTX_start(context); bnC = BN_CTX_get(context); bnM = BN_CTX_get(context); bnE = BN_CTX_get(context); bnN = BN_CTX_get(context); // Errors for BN_CTX_get are sticky so only need to check last allocation if(bnN == NULL) FAIL(FATAL_ERROR_ALLOCATION); //convert arguments if ( BN_bin2bn(m, mSize, bnM) == NULL || BN_bin2bn(e, eSize, bnE) == NULL || BN_bin2bn(n, nSize, bnN) == NULL) FAIL(FATAL_ERROR_INTERNAL); // Don't do exponentiation if the number being exponentiated is // larger than the modulus. if(BN_ucmp(bnM, bnN) >= 0) { retVal = CRYPT_PARAMETER; goto Cleanup; } // Perform the exponentiation if(!(BN_mod_exp(bnC, bnM, bnE, bnN, context))) FAIL(FATAL_ERROR_INTERNAL); // Convert the results // Make sure that the results will fit in the provided buffer. if((unsigned)BN_num_bytes(bnC) > cSize) { retVal = CRYPT_UNDERFLOW; goto Cleanup; } i = cSize - BN_num_bytes(bnC); BN_bn2bin(bnC, &c[i]); memset(c, 0, i); Cleanup: // Free up allocated BN values BN_CTX_end(context); BN_CTX_free(context); return retVal; } // // // _math__IsPrime() // // Check if an 32-bit integer is a prime. // // Return Value Meaning // // TRUE if the integer is probably a prime // FALSE if the integer is definitely not a prime // LIB_EXPORT BOOL _math__IsPrime( const UINT32 prime ) { int isPrime; BIGNUM *p; // Assume the size variables are not overflow, which should not happen in // the contexts that this function will be called. if((p = BN_new()) == NULL) FAIL(FATAL_ERROR_ALLOCATION); if(!BN_set_word(p, prime)) FAIL(FATAL_ERROR_INTERNAL); // // BN_is_prime returning -1 means that it ran into an error. // // It should only return 0 or 1 // if((isPrime = BN_is_prime_ex(p, BN_prime_checks, NULL, NULL)) < 0) FAIL(FATAL_ERROR_INTERNAL); if(p != NULL) BN_clear_free(p); return (isPrime == 1); }