| // 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" |
| #ifdef TPM_ALG_RSA |
| // |
| // |
| // Local Functions |
| // |
| // RsaPrivateExponent() |
| // |
| // This function computes the private exponent de = 1 mod (p-1)*(q-1) The inputs are the public modulus |
| // and one of the primes. |
| // The results are returned in the key->private structure. The size of that structure is expanded to hold the |
| // private exponent. If the computed value is smaller than the public modulus, the private exponent is de- |
| // normalized. |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS private exponent computed |
| // CRYPT_PARAMETER prime is not half the size of the modulus, or the modulus is not evenly |
| // divisible by the prime, or no private exponent could be computed |
| // from the input parameters |
| // |
| CRYPT_RESULT |
| RsaPrivateExponent( |
| RSA_KEY *key // IN: the key to augment with the private |
| // exponent |
| ) |
| { |
| BN_CTX *context; |
| BIGNUM *bnD; |
| BIGNUM *bnN; |
| BIGNUM *bnP; |
| BIGNUM *bnE; |
| BIGNUM *bnPhi; |
| BIGNUM *bnQ; |
| BIGNUM *bnQr; |
| UINT32 fill; |
| CRYPT_RESULT retVal = CRYPT_SUCCESS; // Assume success |
| pAssert(key != NULL && key->privateKey != NULL && key->publicKey != NULL); |
| context = BN_CTX_new(); |
| if(context == NULL) |
| FAIL(FATAL_ERROR_ALLOCATION); |
| BN_CTX_start(context); |
| bnE = BN_CTX_get(context); |
| bnD = BN_CTX_get(context); |
| bnN = BN_CTX_get(context); |
| bnP = BN_CTX_get(context); |
| bnPhi = BN_CTX_get(context); |
| bnQ = BN_CTX_get(context); |
| bnQr = BN_CTX_get(context); |
| if(bnQr == NULL) |
| FAIL(FATAL_ERROR_ALLOCATION); |
| // Assume the size of the public key value is within range |
| pAssert(key->publicKey->size <= MAX_RSA_KEY_BYTES); |
| if( BN_bin2bn(key->publicKey->buffer, key->publicKey->size, bnN) == NULL |
| || BN_bin2bn(key->privateKey->buffer, key->privateKey->size, bnP) == NULL) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // If P size is not 1/2 of n size, then this is not a valid value for this |
| // implementation. This will also catch the case were P is input as zero. |
| // This generates a return rather than an assert because the key being loaded |
| // might be SW generated and wrong. |
| if(BN_num_bits(bnP) < BN_num_bits(bnN)/2) |
| { |
| retVal = CRYPT_PARAMETER; |
| goto Cleanup; |
| } |
| // Get q = n/p; |
| if (BN_div(bnQ, bnQr, bnN, bnP, context) != 1) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // If there is a remainder, then this is not a valid n |
| if(BN_num_bytes(bnQr) != 0 || BN_num_bits(bnQ) != BN_num_bits(bnP)) |
| { |
| retVal = CRYPT_PARAMETER; // problem may be recoverable |
| goto Cleanup; |
| } |
| // Get compute Phi = (p - 1)(q - 1) = pq - p - q + 1 = n - p - q + 1 |
| if( BN_copy(bnPhi, bnN) == NULL |
| || !BN_sub(bnPhi, bnPhi, bnP) |
| || !BN_sub(bnPhi, bnPhi, bnQ) |
| || !BN_add_word(bnPhi, 1)) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // Compute the multiplicative inverse |
| BN_set_word(bnE, key->exponent); |
| if(BN_mod_inverse(bnD, bnE, bnPhi, context) == NULL) |
| { |
| // Going to assume that the error is caused by a bad |
| // set of parameters. Specifically, an exponent that is |
| // not compatible with the primes. In an implementation that |
| // has better visibility to the error codes, this might be |
| // refined so that failures in the library would return |
| // a more informative value. Should not assume here that |
| // the error codes will remain unchanged. |
| retVal = CRYPT_PARAMETER; |
| goto Cleanup; |
| } |
| fill = key->publicKey->size - BN_num_bytes(bnD); |
| BN_bn2bin(bnD, &key->privateKey->buffer[fill]); |
| memset(key->privateKey->buffer, 0, fill); |
| // Change the size of the private key so that it is known to contain |
| // a private exponent rather than a prime. |
| key->privateKey->size = key->publicKey->size; |
| Cleanup: |
| BN_CTX_end(context); |
| BN_CTX_free(context); |
| return retVal; |
| } |
| // |
| // |
| // _cpri__TestKeyRSA() |
| // |
| // This function computes the private exponent de = 1 mod (p-1)*(q-1) The inputs are the public modulus |
| // and one of the primes or two primes. |
| // If both primes are provided, the public modulus is computed. If only one prime is provided, the second |
| // prime is computed. In either case, a private exponent is produced and placed in d. |
| // If no modular inverse exists, then CRYPT_PARAMETER is returned. |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS private exponent (d) was generated |
| // CRYPT_PARAMETER one or more parameters are invalid |
| // |
| LIB_EXPORT CRYPT_RESULT |
| _cpri__TestKeyRSA( |
| TPM2B *d, // OUT: the address to receive the private |
| // exponent |
| UINT32 exponent, // IN: the public modulu |
| TPM2B *publicKey, // IN/OUT: an input if only one prime is |
| // provided. an output if both primes are |
| // provided |
| TPM2B *prime1, // IN: a first prime |
| TPM2B *prime2 // IN: an optional second prime |
| ) |
| { |
| BN_CTX *context; |
| BIGNUM *bnD; |
| BIGNUM *bnN; |
| BIGNUM *bnP; |
| BIGNUM *bnE; |
| BIGNUM *bnPhi; |
| BIGNUM *bnQ; |
| BIGNUM *bnQr; |
| UINT32 fill; |
| CRYPT_RESULT retVal = CRYPT_SUCCESS; // Assume success |
| pAssert(publicKey != NULL && prime1 != NULL); |
| // Make sure that the sizes are within range |
| pAssert( prime1->size <= MAX_RSA_KEY_BYTES/2 |
| && publicKey->size <= MAX_RSA_KEY_BYTES); |
| pAssert( prime2 == NULL || prime2->size < MAX_RSA_KEY_BYTES/2); |
| if(publicKey->size/2 != prime1->size) |
| return CRYPT_PARAMETER; |
| context = BN_CTX_new(); |
| if(context == NULL) |
| FAIL(FATAL_ERROR_ALLOCATION); |
| BN_CTX_start(context); |
| bnE = BN_CTX_get(context); // public exponent (e) |
| bnD = BN_CTX_get(context); // private exponent (d) |
| bnN = BN_CTX_get(context); // public modulus (n) |
| bnP = BN_CTX_get(context); // prime1 (p) |
| bnPhi = BN_CTX_get(context); // (p-1)(q-1) |
| bnQ = BN_CTX_get(context); // prime2 (q) |
| bnQr = BN_CTX_get(context); // n mod p |
| if(bnQr == NULL) |
| FAIL(FATAL_ERROR_ALLOCATION); |
| if(BN_bin2bn(prime1->buffer, prime1->size, bnP) == NULL) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // If prime2 is provided, then compute n |
| if(prime2 != NULL) |
| { |
| // Two primes provided so use them to compute n |
| if(BN_bin2bn(prime2->buffer, prime2->size, bnQ) == NULL) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // Make sure that the sizes of the primes are compatible |
| if(BN_num_bits(bnQ) != BN_num_bits(bnP)) |
| { |
| retVal = CRYPT_PARAMETER; |
| goto Cleanup; |
| } |
| // Multiply the primes to get the public modulus |
| if(BN_mul(bnN, bnP, bnQ, context) != 1) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // if the space provided for the public modulus is large enough, |
| // save the created value |
| if(BN_num_bits(bnN) != (publicKey->size * 8)) |
| { |
| retVal = CRYPT_PARAMETER; |
| goto Cleanup; |
| } |
| BN_bn2bin(bnN, publicKey->buffer); |
| } |
| else |
| { |
| // One prime provided so find the second prime by division |
| BN_bin2bn(publicKey->buffer, publicKey->size, bnN); |
| // Get q = n/p; |
| if(BN_div(bnQ, bnQr, bnN, bnP, context) != 1) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // If there is a remainder, then this is not a valid n |
| if(BN_num_bytes(bnQr) != 0 || BN_num_bits(bnQ) != BN_num_bits(bnP)) |
| { |
| retVal = CRYPT_PARAMETER; // problem may be recoverable |
| goto Cleanup; |
| } |
| } |
| // Get compute Phi = (p - 1)(q - 1) = pq - p - q + 1 = n - p - q + 1 |
| BN_copy(bnPhi, bnN); |
| BN_sub(bnPhi, bnPhi, bnP); |
| BN_sub(bnPhi, bnPhi, bnQ); |
| BN_add_word(bnPhi, 1); |
| // Compute the multiplicative inverse |
| BN_set_word(bnE, exponent); |
| if(BN_mod_inverse(bnD, bnE, bnPhi, context) == NULL) |
| { |
| // Going to assume that the error is caused by a bad set of parameters. |
| // Specifically, an exponent that is not compatible with the primes. |
| // In an implementation that has better visibility to the error codes, |
| // this might be refined so that failures in the library would return |
| // a more informative value. |
| // Do not assume that the error codes will remain unchanged. |
| retVal = CRYPT_PARAMETER; |
| goto Cleanup; |
| } |
| // Return the private exponent. |
| // Make sure it is normalized to have the correct size. |
| d->size = publicKey->size; |
| fill = d->size - BN_num_bytes(bnD); |
| BN_bn2bin(bnD, &d->buffer[fill]); |
| memset(d->buffer, 0, fill); |
| Cleanup: |
| BN_CTX_end(context); |
| BN_CTX_free(context); |
| return retVal; |
| } |
| // |
| // |
| // RSAEP() |
| // |
| // This function performs the RSAEP operation defined in PKCS#1v2.1. It is an exponentiation of a value |
| // (m) with the public exponent (e), modulo the public (n). |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS encryption complete |
| // CRYPT_PARAMETER number to exponentiate is larger than the modulus |
| // |
| static CRYPT_RESULT |
| RSAEP ( |
| UINT32 dInOutSize, // OUT size of the encrypted block |
| BYTE *dInOut, // OUT: the encrypted data |
| RSA_KEY *key // IN: the key to use |
| ) |
| { |
| UINT32 e; |
| BYTE exponent[4]; |
| CRYPT_RESULT retVal; |
| e = key->exponent; |
| if(e == 0) |
| e = RSA_DEFAULT_PUBLIC_EXPONENT; |
| UINT32_TO_BYTE_ARRAY(e, exponent); |
| //!!! Can put check for test of RSA here |
| retVal = _math__ModExp(dInOutSize, dInOut, dInOutSize, dInOut, 4, exponent, |
| key->publicKey->size, key->publicKey->buffer); |
| // Exponentiation result is stored in-place, thus no space shortage is possible. |
| pAssert(retVal != CRYPT_UNDERFLOW); |
| return retVal; |
| } |
| // |
| // |
| // RSADP() |
| // |
| // This function performs the RSADP operation defined in PKCS#1v2.1. It is an exponentiation of a value (c) |
| // with the private exponent (d), modulo the public modulus (n). The decryption is in place. |
| // |
| // This function also checks the size of the private key. If the size indicates that only a prime value is |
| // present, the key is converted to being a private exponent. |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS decryption succeeded |
| // CRYPT_PARAMETER the value to decrypt is larger than the modulus |
| // |
| static CRYPT_RESULT |
| RSADP ( |
| UINT32 dInOutSize, // IN/OUT: size of decrypted data |
| BYTE *dInOut, // IN/OUT: the decrypted data |
| RSA_KEY *key // IN: the key |
| ) |
| { |
| CRYPT_RESULT retVal; |
| //!!! Can put check for RSA tested here |
| // Make sure that the pointers are provided and that the private key is present |
| // If the private key is present it is assumed to have been created by |
| // so is presumed good _cpri__PrivateExponent |
| pAssert(key != NULL && dInOut != NULL && |
| key->publicKey->size == key->publicKey->size); |
| // make sure that the value to be decrypted is smaller than the modulus |
| // note: this check is redundant as is also performed by _math__ModExp() |
| // which is optimized for use in RSA operations |
| if(_math__uComp(key->publicKey->size, key->publicKey->buffer, |
| dInOutSize, dInOut) <= 0) |
| return CRYPT_PARAMETER; |
| // _math__ModExp can return CRYPT_PARAMTER or CRYPT_UNDERFLOW but actual |
| // underflow is not possible because everything is in the same buffer. |
| retVal = _math__ModExp(dInOutSize, dInOut, dInOutSize, dInOut, |
| key->privateKey->size, key->privateKey->buffer, |
| key->publicKey->size, key->publicKey->buffer); |
| // Exponentiation result is stored in-place, thus no space shortage is possible. |
| pAssert(retVal != CRYPT_UNDERFLOW); |
| return retVal; |
| } |
| // |
| // |
| // OaepEncode() |
| // |
| // This function performs OAEP padding. The size of the buffer to receive the OAEP padded data must |
| // equal the size of the modulus |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS encode successful |
| // CRYPT_PARAMETER hashAlg is not valid |
| // CRYPT_FAIL message size is too large |
| // |
| static CRYPT_RESULT |
| OaepEncode( |
| UINT32 paddedSize, // IN: pad value size |
| BYTE *padded, // OUT: the pad data |
| TPM_ALG_ID hashAlg, // IN: algorithm to use for padding |
| const char *label, // IN: null-terminated string (may be NULL) |
| UINT32 messageSize, // IN: the message size |
| BYTE *message // IN: the message being padded |
| #ifdef TEST_RSA // |
| , BYTE *testSeed // IN: optional seed used for testing. |
| #endif // TEST_RSA // |
| ) |
| { |
| UINT32 padLen; |
| UINT32 dbSize; |
| UINT32 i; |
| BYTE mySeed[MAX_DIGEST_SIZE]; |
| BYTE *seed = mySeed; |
| INT32 hLen = _cpri__GetDigestSize(hashAlg); |
| BYTE mask[MAX_RSA_KEY_BYTES]; |
| BYTE *pp; |
| BYTE *pm; |
| UINT32 lSize = 0; |
| CRYPT_RESULT retVal = CRYPT_SUCCESS; |
| pAssert(padded != NULL && message != NULL); |
| // A value of zero is not allowed because the KDF can't produce a result |
| // if the digest size is zero. |
| if(hLen <= 0) |
| return CRYPT_PARAMETER; |
| // If a label is provided, get the length of the string, including the |
| // terminator |
| if(label != NULL) |
| lSize = (UINT32)strlen(label) + 1; |
| // Basic size check |
| // messageSize <= k 2hLen 2 |
| if(messageSize > paddedSize - 2 * hLen - 2) |
| return CRYPT_FAIL; |
| // Hash L even if it is null |
| // Offset into padded leaving room for masked seed and byte of zero |
| pp = &padded[hLen + 1]; |
| retVal = _cpri__HashBlock(hashAlg, lSize, (BYTE *)label, hLen, pp); |
| // concatenate PS of k mLen 2hLen 2 |
| padLen = paddedSize - messageSize - (2 * hLen) - 2; |
| memset(&pp[hLen], 0, padLen); |
| pp[hLen+padLen] = 0x01; |
| padLen += 1; |
| memcpy(&pp[hLen+padLen], message, messageSize); |
| // The total size of db = hLen + pad + mSize; |
| dbSize = hLen+padLen+messageSize; |
| // If testing, then use the provided seed. Otherwise, use values |
| // from the RNG |
| #ifdef TEST_RSA |
| if(testSeed != NULL) |
| seed = testSeed; |
| else |
| #endif // TEST_RSA |
| _cpri__GenerateRandom(hLen, mySeed); |
| // mask = MGF1 (seed, nSize hLen 1) |
| if((retVal = _cpri__MGF1(dbSize, mask, hashAlg, hLen, seed)) < 0) |
| return retVal; // Don't expect an error because hash size is not zero |
| // was detected in the call to _cpri__HashBlock() above. |
| // Create the masked db |
| pm = mask; |
| for(i = dbSize; i > 0; i--) |
| *pp++ ^= *pm++; |
| pp = &padded[hLen + 1]; |
| // Run the masked data through MGF1 |
| if((retVal = _cpri__MGF1(hLen, &padded[1], hashAlg, dbSize, pp)) < 0) |
| return retVal; // Don't expect zero here as the only case for zero |
| // was detected in the call to _cpri__HashBlock() above. |
| // Now XOR the seed to create masked seed |
| pp = &padded[1]; |
| pm = seed; |
| for(i = hLen; i > 0; i--) |
| *pp++ ^= *pm++; |
| // Set the first byte to zero |
| *padded = 0x00; |
| return CRYPT_SUCCESS; |
| } |
| // |
| // |
| // OaepDecode() |
| // |
| // This function performs OAEP padding checking. The size of the buffer to receive the recovered data. If |
| // the padding is not valid, the dSize size is set to zero and the function returns CRYPT_NO_RESULTS. |
| // The dSize parameter is used as an input to indicate the size available in the buffer. If insufficient space is |
| // available, the size is not changed and the return code is CRYPT_FAIL. |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS decode complete |
| // CRYPT_PARAMETER the value to decode was larger than the modulus |
| // CRYPT_FAIL the padding is wrong or the buffer to receive the results is too small |
| // |
| static CRYPT_RESULT |
| OaepDecode( |
| UINT32 *dataOutSize, // IN/OUT: the recovered data size |
| BYTE *dataOut, // OUT: the recovered data |
| TPM_ALG_ID hashAlg, // IN: algorithm to use for padding |
| const char *label, // IN: null-terminated string (may be NULL) |
| UINT32 paddedSize, // IN: the size of the padded data |
| BYTE *padded // IN: the padded data |
| ) |
| { |
| UINT32 dSizeSave; |
| UINT32 i; |
| BYTE seedMask[MAX_DIGEST_SIZE]; |
| INT32 hLen = _cpri__GetDigestSize(hashAlg); |
| BYTE mask[MAX_RSA_KEY_BYTES]; |
| BYTE *pp; |
| BYTE *pm; |
| UINT32 lSize = 0; |
| CRYPT_RESULT retVal = CRYPT_SUCCESS; |
| // Unknown hash |
| pAssert(hLen > 0 && dataOutSize != NULL && dataOut != NULL && padded != NULL); |
| // If there is a label, get its size including the terminating 0x00 |
| if(label != NULL) |
| lSize = (UINT32)strlen(label) + 1; |
| // Set the return size to zero so that it doesn't have to be done on each |
| // failure |
| dSizeSave = *dataOutSize; |
| *dataOutSize = 0; |
| // Strange size (anything smaller can't be an OAEP padded block) |
| // Also check for no leading 0 |
| if(paddedSize < (unsigned)((2 * hLen) + 2) || *padded != 0) |
| return CRYPT_FAIL; |
| // Use the hash size to determine what to put through MGF1 in order |
| // to recover the seedMask |
| if((retVal = _cpri__MGF1(hLen, seedMask, hashAlg, |
| paddedSize-hLen-1, &padded[hLen+1])) < 0) |
| return retVal; |
| // Recover the seed into seedMask |
| pp = &padded[1]; |
| pm = seedMask; |
| for(i = hLen; i > 0; i--) |
| *pm++ ^= *pp++; |
| // Use the seed to generate the data mask |
| if((retVal = _cpri__MGF1(paddedSize-hLen-1, mask, hashAlg, |
| hLen, seedMask)) < 0) |
| return retVal; |
| // Use the mask generated from seed to recover the padded data |
| pp = &padded[hLen+1]; |
| pm = mask; |
| for(i = paddedSize-hLen-1; i > 0; i--) |
| *pm++ ^= *pp++; |
| // Make sure that the recovered data has the hash of the label |
| // Put trial value in the seed mask |
| if((retVal=_cpri__HashBlock(hashAlg, lSize,(BYTE *)label, hLen, seedMask)) < 0) |
| return retVal; |
| if(memcmp(seedMask, mask, hLen) != 0) |
| return CRYPT_FAIL; |
| // find the start of the data |
| pm = &mask[hLen]; |
| for(i = paddedSize-(2*hLen)-1; i > 0; i--) |
| { |
| if(*pm++ != 0) |
| break; |
| } |
| if(i == 0) |
| return CRYPT_PARAMETER; |
| // pm should be pointing at the first part of the data |
| // and i is one greater than the number of bytes to move |
| i--; |
| if(i > dSizeSave) |
| { |
| // Restore dSize |
| *dataOutSize = dSizeSave; |
| return CRYPT_FAIL; |
| } |
| memcpy(dataOut, pm, i); |
| *dataOutSize = i; |
| return CRYPT_SUCCESS; |
| } |
| // |
| // |
| // PKSC1v1_5Encode() |
| // |
| // This function performs the encoding for RSAES-PKCS1-V1_5-ENCRYPT as defined in PKCS#1V2.1 |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS data encoded |
| // CRYPT_PARAMETER message size is too large |
| // |
| static CRYPT_RESULT |
| RSAES_PKSC1v1_5Encode( |
| UINT32 paddedSize, // IN: pad value size |
| BYTE *padded, // OUT: the pad data |
| UINT32 messageSize, // IN: the message size |
| BYTE *message // IN: the message being padded |
| ) |
| { |
| UINT32 ps = paddedSize - messageSize - 3; |
| if(messageSize > paddedSize - 11) |
| return CRYPT_PARAMETER; |
| // move the message to the end of the buffer |
| memcpy(&padded[paddedSize - messageSize], message, messageSize); |
| // Set the first byte to 0x00 and the second to 0x02 |
| *padded = 0; |
| padded[1] = 2; |
| // Fill with random bytes |
| _cpri__GenerateRandom(ps, &padded[2]); |
| // Set the delimiter for the random field to 0 |
| padded[2+ps] = 0; |
| // Now, the only messy part. Make sure that all the ps bytes are non-zero |
| // In this implementation, use the value of the current index |
| for(ps++; ps > 1; ps--) |
| { |
| if(padded[ps] == 0) |
| padded[ps] = 0x55; // In the < 0.5% of the cases that the random |
| // value is 0, just pick a value to put into |
| // the spot. |
| } |
| return CRYPT_SUCCESS; |
| } |
| // |
| // |
| // RSAES_Decode() |
| // |
| // This function performs the decoding for RSAES-PKCS1-V1_5-ENCRYPT as defined in PKCS#1V2.1 |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS decode successful |
| // CRYPT_FAIL decoding error or results would no fit into provided buffer |
| // |
| static CRYPT_RESULT |
| RSAES_Decode( |
| UINT32 *messageSize, // IN/OUT: recovered message size |
| BYTE *message, // OUT: the recovered message |
| UINT32 codedSize, // IN: the encoded message size |
| BYTE *coded // IN: the encoded message |
| ) |
| { |
| BOOL fail = FALSE; |
| UINT32 ps; |
| fail = (codedSize < 11); |
| fail |= (coded[0] != 0x00) || (coded[1] != 0x02); |
| for(ps = 2; ps < codedSize; ps++) |
| { |
| if(coded[ps] == 0) |
| break; |
| } |
| ps++; |
| // Make sure that ps has not gone over the end and that there are at least 8 |
| // bytes of pad data. |
| fail |= ((ps >= codedSize) || ((ps-2) < 8)); |
| if((*messageSize < codedSize - ps) || fail) |
| return CRYPT_FAIL; |
| *messageSize = codedSize - ps; |
| memcpy(message, &coded[ps], codedSize - ps); |
| return CRYPT_SUCCESS; |
| } |
| // |
| // |
| // PssEncode() |
| // |
| // This function creates an encoded block of data that is the size of modulus. The function uses the |
| // maximum salt size that will fit in the encoded block. |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS encode successful |
| // CRYPT_PARAMETER hashAlg is not a supported hash algorithm |
| // |
| static CRYPT_RESULT |
| PssEncode ( |
| UINT32 eOutSize, // IN: size of the encode data buffer |
| BYTE *eOut, // OUT: encoded data buffer |
| TPM_ALG_ID hashAlg, // IN: hash algorithm to use for the encoding |
| UINT32 hashInSize, // IN: size of digest to encode |
| BYTE *hashIn // IN: the digest |
| #ifdef TEST_RSA // |
| , BYTE *saltIn // IN: optional parameter for testing |
| #endif // TEST_RSA // |
| ) |
| { |
| INT32 hLen = _cpri__GetDigestSize(hashAlg); |
| BYTE salt[MAX_RSA_KEY_BYTES - 1]; |
| UINT16 saltSize; |
| BYTE *ps = salt; |
| CRYPT_RESULT retVal; |
| UINT16 mLen; |
| CPRI_HASH_STATE hashState; |
| // These are fatal errors indicating bad TPM firmware |
| pAssert(eOut != NULL && hLen > 0 && hashIn != NULL ); |
| // Get the size of the mask |
| mLen = (UINT16)(eOutSize - hLen - 1); |
| // Maximum possible salt size is mask length - 1 |
| saltSize = mLen - 1; |
| // Use the maximum salt size allowed by FIPS 186-4 |
| if(saltSize > hLen) |
| saltSize = (UINT16)hLen; |
| //using eOut for scratch space |
| // Set the first 8 bytes to zero |
| memset(eOut, 0, 8); |
| // Get set the salt |
| #ifdef TEST_RSA |
| if(saltIn != NULL) |
| { |
| saltSize = hLen; |
| memcpy(salt, saltIn, hLen); |
| } |
| else |
| #endif // TEST_RSA |
| _cpri__GenerateRandom(saltSize, salt); |
| // Create the hash of the pad || input hash || salt |
| _cpri__StartHash(hashAlg, FALSE, &hashState); |
| _cpri__UpdateHash(&hashState, 8, eOut); |
| _cpri__UpdateHash(&hashState, hashInSize, hashIn); |
| _cpri__UpdateHash(&hashState, saltSize, salt); |
| _cpri__CompleteHash(&hashState, hLen, &eOut[eOutSize - hLen - 1]); |
| // Create a mask |
| if((retVal = _cpri__MGF1(mLen, eOut, hashAlg, hLen, &eOut[mLen])) < 0) |
| { |
| // Currently _cpri__MGF1 is not expected to return a CRYPT_RESULT error. |
| pAssert(0); |
| } |
| // Since this implementation uses key sizes that are all even multiples of |
| // 8, just need to make sure that the most significant bit is CLEAR |
| eOut[0] &= 0x7f; |
| // Before we mess up the eOut value, set the last byte to 0xbc |
| eOut[eOutSize - 1] = 0xbc; |
| // XOR a byte of 0x01 at the position just before where the salt will be XOR'ed |
| eOut = &eOut[mLen - saltSize - 1]; |
| *eOut++ ^= 0x01; |
| // XOR the salt data into the buffer |
| for(; saltSize > 0; saltSize--) |
| *eOut++ ^= *ps++; |
| // and we are done |
| return CRYPT_SUCCESS; |
| } |
| // |
| // |
| // PssDecode() |
| // |
| // This function checks that the PSS encoded block was built from the provided digest. If the check is |
| // successful, CRYPT_SUCCESS is returned. Any other value indicates an error. |
| // This implementation of PSS decoding is intended for the reference TPM implementation and is not at all |
| // generalized. It is used to check signatures over hashes and assumptions are made about the sizes of |
| // values. Those assumptions are enforce by this implementation. This implementation does allow for a |
| // variable size salt value to have been used by the creator of the signature. |
| // |
| // |
| // |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS decode successful |
| // CRYPT_SCHEME hashAlg is not a supported hash algorithm |
| // CRYPT_FAIL decode operation failed |
| // |
| static CRYPT_RESULT |
| PssDecode( |
| TPM_ALG_ID hashAlg, // IN: hash algorithm to use for the encoding |
| UINT32 dInSize, // IN: size of the digest to compare |
| BYTE *dIn, // In: the digest to compare |
| UINT32 eInSize, // IN: size of the encoded data |
| BYTE *eIn, // IN: the encoded data |
| UINT32 saltSize // IN: the expected size of the salt |
| ) |
| { |
| INT32 hLen = _cpri__GetDigestSize(hashAlg); |
| BYTE mask[MAX_RSA_KEY_BYTES]; |
| BYTE *pm = mask; |
| BYTE pad[8] = {0}; |
| UINT32 i; |
| UINT32 mLen; |
| BOOL fail = FALSE; |
| CRYPT_RESULT retVal; |
| CPRI_HASH_STATE hashState; |
| // These errors are indicative of failures due to programmer error |
| pAssert(dIn != NULL && eIn != NULL); |
| // check the hash scheme |
| if(hLen == 0) |
| return CRYPT_SCHEME; |
| // most significant bit must be zero |
| fail = ((eIn[0] & 0x80) != 0); |
| // last byte must be 0xbc |
| fail |= (eIn[eInSize - 1] != 0xbc); |
| // Use the hLen bytes at the end of the buffer to generate a mask |
| // Doesn't start at the end which is a flag byte |
| mLen = eInSize - hLen - 1; |
| if((retVal = _cpri__MGF1(mLen, mask, hashAlg, hLen, &eIn[mLen])) < 0) |
| return retVal; |
| if(retVal == 0) |
| return CRYPT_FAIL; |
| // Clear the MSO of the mask to make it consistent with the encoding. |
| mask[0] &= 0x7F; |
| // XOR the data into the mask to recover the salt. This sequence |
| // advances eIn so that it will end up pointing to the seed data |
| // which is the hash of the signature data |
| for(i = mLen; i > 0; i--) |
| *pm++ ^= *eIn++; |
| // Find the first byte of 0x01 after a string of all 0x00 |
| for(pm = mask, i = mLen; i > 0; i--) |
| { |
| if(*pm == 0x01) |
| break; |
| else |
| fail |= (*pm++ != 0); |
| } |
| fail |= (i == 0); |
| // if we have failed, will continue using the entire mask as the salt value so |
| // that the timing attacks will not disclose anything (I don't think that this |
| // is a problem for TPM applications but, usually, we don't fail so this |
| // doesn't cost anything). |
| if(fail) |
| { |
| i = mLen; |
| pm = mask; |
| } |
| else |
| { |
| pm++; |
| i--; |
| } |
| // If the salt size was provided, then the recovered size must match |
| fail |= (saltSize != 0 && i != saltSize); |
| // i contains the salt size and pm points to the salt. Going to use the input |
| // hash and the seed to recreate the hash in the lower portion of eIn. |
| _cpri__StartHash(hashAlg, FALSE, &hashState); |
| // add the pad of 8 zeros |
| _cpri__UpdateHash(&hashState, 8, pad); |
| // add the provided digest value |
| _cpri__UpdateHash(&hashState, dInSize, dIn); |
| // and the salt |
| _cpri__UpdateHash(&hashState, i, pm); |
| // get the result |
| retVal = _cpri__CompleteHash(&hashState, MAX_DIGEST_SIZE, mask); |
| // retVal will be the size of the digest or zero. If not equal to the indicated |
| // digest size, then the signature doesn't match |
| fail |= (retVal != hLen); |
| fail |= (memcmp(mask, eIn, hLen) != 0); |
| if(fail) |
| return CRYPT_FAIL; |
| else |
| return CRYPT_SUCCESS; |
| } |
| // |
| // |
| // PKSC1v1_5SignEncode() |
| // |
| // Encode a message using PKCS1v1().5 method. |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS encode complete |
| // CRYPT_SCHEME hashAlg is not a supported hash algorithm |
| // CRYPT_PARAMETER eOutSize is not large enough or hInSize does not match the digest |
| // size of hashAlg |
| // |
| static CRYPT_RESULT |
| RSASSA_Encode( |
| UINT32 eOutSize, // IN: the size of the resulting block |
| BYTE *eOut, // OUT: the encoded block |
| TPM_ALG_ID hashAlg, // IN: hash algorithm for PKSC1v1_5 |
| UINT32 hInSize, // IN: size of hash to be signed |
| BYTE *hIn // IN: hash buffer |
| ) |
| { |
| const BYTE *der; |
| INT32 derSize = _cpri__GetHashDER(hashAlg, &der); |
| INT32 fillSize; |
| pAssert(eOut != NULL && hIn != NULL); |
| // Can't use this scheme if the algorithm doesn't have a DER string defined. |
| if(derSize == 0 ) |
| return CRYPT_SCHEME; |
| // If the digest size of 'hashAl' doesn't match the input digest size, then |
| // the DER will misidentify the digest so return an error |
| if((unsigned)_cpri__GetDigestSize(hashAlg) != hInSize) |
| return CRYPT_PARAMETER; |
| fillSize = eOutSize - derSize - hInSize - 3; |
| // Make sure that this combination will fit in the provided space |
| if(fillSize < 8) |
| return CRYPT_PARAMETER; |
| // Start filling |
| *eOut++ = 0; // initial byte of zero |
| *eOut++ = 1; // byte of 0x01 |
| for(; fillSize > 0; fillSize--) |
| *eOut++ = 0xff; // bunch of 0xff |
| *eOut++ = 0; // another 0 |
| for(; derSize > 0; derSize--) |
| *eOut++ = *der++; // copy the DER |
| for(; hInSize > 0; hInSize--) |
| *eOut++ = *hIn++; // copy the hash |
| return CRYPT_SUCCESS; |
| } |
| // |
| // |
| // RSASSA_Decode() |
| // |
| // This function performs the RSASSA decoding of a signature. |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS decode successful |
| // CRYPT_FAIL decode unsuccessful |
| // CRYPT_SCHEME haslAlg is not supported |
| // |
| static CRYPT_RESULT |
| RSASSA_Decode( |
| TPM_ALG_ID hashAlg, // IN: hash algorithm to use for the encoding |
| UINT32 hInSize, // IN: size of the digest to compare |
| BYTE *hIn, // In: the digest to compare |
| UINT32 eInSize, // IN: size of the encoded data |
| BYTE *eIn // IN: the encoded data |
| ) |
| { |
| BOOL fail = FALSE; |
| const BYTE *der; |
| INT32 derSize = _cpri__GetHashDER(hashAlg, &der); |
| INT32 hashSize = _cpri__GetDigestSize(hashAlg); |
| INT32 fillSize; |
| pAssert(hIn != NULL && eIn != NULL); |
| // Can't use this scheme if the algorithm doesn't have a DER string |
| // defined or if the provided hash isn't the right size |
| if(derSize == 0 || (unsigned)hashSize != hInSize) |
| return CRYPT_SCHEME; |
| // Make sure that this combination will fit in the provided space |
| // Since no data movement takes place, can just walk though this |
| // and accept nearly random values. This can only be called from |
| // _cpri__ValidateSignature() so eInSize is known to be in range. |
| fillSize = eInSize - derSize - hashSize - 3; |
| // Start checking |
| fail |= (*eIn++ != 0); // initial byte of zero |
| fail |= (*eIn++ != 1); // byte of 0x01 |
| for(; fillSize > 0; fillSize--) |
| fail |= (*eIn++ != 0xff); // bunch of 0xff |
| fail |= (*eIn++ != 0); // another 0 |
| for(; derSize > 0; derSize--) |
| fail |= (*eIn++ != *der++); // match the DER |
| for(; hInSize > 0; hInSize--) |
| fail |= (*eIn++ != *hIn++); // match the hash |
| if(fail) |
| return CRYPT_FAIL; |
| return CRYPT_SUCCESS; |
| } |
| // |
| // |
| // Externally Accessible Functions |
| // |
| // _cpri__RsaStartup() |
| // |
| // Function that is called to initialize the hash service. In this implementation, this function does nothing but |
| // it is called by the CryptUtilStartup() function and must be present. |
| // |
| LIB_EXPORT BOOL |
| _cpri__RsaStartup( |
| void |
| ) |
| { |
| return TRUE; |
| } |
| // |
| // |
| // _cpri__EncryptRSA() |
| // |
| // This is the entry point for encryption using RSA. Encryption is use of the public exponent. The padding |
| // parameter determines what padding will be used. |
| // The cOutSize parameter must be at least as large as the size of the key. |
| // If the padding is RSA_PAD_NONE, dIn is treaded as a number. It must be lower in value than the key |
| // modulus. |
| // |
| // |
| // |
| // NOTE: If dIn has fewer bytes than cOut, then we don't add low-order zeros to dIn to make it the size of the RSA key for |
| // the call to RSAEP. This is because the high order bytes of dIn might have a numeric value that is greater than |
| // the value of the key modulus. If this had low-order zeros added, it would have a numeric value larger than the |
| // modulus even though it started out with a lower numeric value. |
| // |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS encryption complete |
| // CRYPT_PARAMETER cOutSize is too small (must be the size of the modulus) |
| // CRYPT_SCHEME padType is not a supported scheme |
| // |
| LIB_EXPORT CRYPT_RESULT |
| _cpri__EncryptRSA( |
| UINT32 *cOutSize, // OUT: the size of the encrypted data |
| BYTE *cOut, // OUT: the encrypted data |
| RSA_KEY *key, // IN: the key to use for encryption |
| TPM_ALG_ID padType, // IN: the type of padding |
| UINT32 dInSize, // IN: the amount of data to encrypt |
| BYTE *dIn, // IN: the data to encrypt |
| TPM_ALG_ID hashAlg, // IN: in case this is needed |
| const char *label // IN: in case it is needed |
| ) |
| { |
| CRYPT_RESULT retVal = CRYPT_SUCCESS; |
| pAssert(cOutSize != NULL); |
| // All encryption schemes return the same size of data |
| if(*cOutSize < key->publicKey->size) |
| return CRYPT_PARAMETER; |
| *cOutSize = key->publicKey->size; |
| switch (padType) |
| { |
| case TPM_ALG_NULL: // 'raw' encryption |
| { |
| // dIn can have more bytes than cOut as long as the extra bytes |
| // are zero |
| for(; dInSize > *cOutSize; dInSize--) |
| { |
| if(*dIn++ != 0) |
| return CRYPT_PARAMETER; |
| } |
| // If dIn is smaller than cOut, fill cOut with zeros |
| if(dInSize < *cOutSize) |
| memset(cOut, 0, *cOutSize - dInSize); |
| // Copy the rest of the value |
| memcpy(&cOut[*cOutSize-dInSize], dIn, dInSize); |
| // If the size of dIn is the same as cOut dIn could be larger than |
| // the modulus. If it is, then RSAEP() will catch it. |
| } |
| break; |
| case TPM_ALG_RSAES: |
| retVal = RSAES_PKSC1v1_5Encode(*cOutSize, cOut, dInSize, dIn); |
| break; |
| case TPM_ALG_OAEP: |
| retVal = OaepEncode(*cOutSize, cOut, hashAlg, label, dInSize, dIn |
| #ifdef TEST_RSA |
| ,NULL |
| #endif |
| ); |
| break; |
| default: |
| return CRYPT_SCHEME; |
| } |
| // All the schemes that do padding will come here for the encryption step |
| // Check that the Encoding worked |
| if(retVal != CRYPT_SUCCESS) |
| return retVal; |
| // Padding OK so do the encryption |
| return RSAEP(*cOutSize, cOut, key); |
| } |
| // |
| // |
| // _cpri__DecryptRSA() |
| // |
| // This is the entry point for decryption using RSA. Decryption is use of the private exponent. The padType |
| // parameter determines what padding was used. |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS successful completion |
| // CRYPT_PARAMETER cInSize is not the same as the size of the public modulus of key; or |
| // numeric value of the encrypted data is greater than the modulus |
| // CRYPT_FAIL dOutSize is not large enough for the result |
| // CRYPT_SCHEME padType is not supported |
| // |
| LIB_EXPORT CRYPT_RESULT |
| _cpri__DecryptRSA( |
| UINT32 *dOutSize, // OUT: the size of the decrypted data |
| BYTE *dOut, // OUT: the decrypted data |
| RSA_KEY *key, // IN: the key to use for decryption |
| TPM_ALG_ID padType, // IN: the type of padding |
| UINT32 cInSize, // IN: the amount of data to decrypt |
| BYTE *cIn, // IN: the data to decrypt |
| TPM_ALG_ID hashAlg, // IN: in case this is needed for the scheme |
| const char *label // IN: in case it is needed for the scheme |
| ) |
| { |
| CRYPT_RESULT retVal; |
| // Make sure that the necessary parameters are provided |
| pAssert(cIn != NULL && dOut != NULL && dOutSize != NULL && key != NULL); |
| // Size is checked to make sure that the decryption works properly |
| if(cInSize != key->publicKey->size) |
| return CRYPT_PARAMETER; |
| // For others that do padding, do the decryption in place and then |
| // go handle the decoding. |
| if((retVal = RSADP(cInSize, cIn, key)) != CRYPT_SUCCESS) |
| return retVal; // Decryption failed |
| // Remove padding |
| switch (padType) |
| { |
| case TPM_ALG_NULL: |
| if(*dOutSize < key->publicKey->size) |
| return CRYPT_FAIL; |
| *dOutSize = key->publicKey->size; |
| memcpy(dOut, cIn, *dOutSize); |
| return CRYPT_SUCCESS; |
| case TPM_ALG_RSAES: |
| return RSAES_Decode(dOutSize, dOut, cInSize, cIn); |
| break; |
| case TPM_ALG_OAEP: |
| return OaepDecode(dOutSize, dOut, hashAlg, label, cInSize, cIn); |
| break; |
| default: |
| return CRYPT_SCHEME; |
| break; |
| } |
| } |
| // |
| // |
| // _cpri__SignRSA() |
| // |
| // This function is used to generate an RSA signature of the type indicated in scheme. |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS sign operation completed normally |
| // CRYPT_SCHEME scheme or hashAlg are not supported |
| // CRYPT_PARAMETER hInSize does not match hashAlg (for RSASSA) |
| // |
| LIB_EXPORT CRYPT_RESULT |
| _cpri__SignRSA( |
| UINT32 *sigOutSize, // OUT: size of signature |
| BYTE *sigOut, // OUT: signature |
| RSA_KEY *key, // IN: key to use |
| TPM_ALG_ID scheme, // IN: the scheme to use |
| TPM_ALG_ID hashAlg, // IN: hash algorithm for PKSC1v1_5 |
| UINT32 hInSize, // IN: size of digest to be signed |
| BYTE *hIn // IN: digest buffer |
| ) |
| { |
| CRYPT_RESULT retVal; |
| // Parameter checks |
| pAssert(sigOutSize != NULL && sigOut != NULL && key != NULL && hIn != NULL); |
| // For all signatures the size is the size of the key modulus |
| *sigOutSize = key->publicKey->size; |
| switch (scheme) |
| { |
| case TPM_ALG_NULL: |
| *sigOutSize = 0; |
| return CRYPT_SUCCESS; |
| case TPM_ALG_RSAPSS: |
| // PssEncode can return CRYPT_PARAMETER |
| retVal = PssEncode(*sigOutSize, sigOut, hashAlg, hInSize, hIn |
| #ifdef TEST_RSA |
| , NULL |
| #endif |
| ); |
| break; |
| case TPM_ALG_RSASSA: |
| // RSASSA_Encode can return CRYPT_PARAMETER or CRYPT_SCHEME |
| retVal = RSASSA_Encode(*sigOutSize, sigOut, hashAlg, hInSize, hIn); |
| break; |
| default: |
| return CRYPT_SCHEME; |
| } |
| if(retVal != CRYPT_SUCCESS) |
| return retVal; |
| // Do the encryption using the private key |
| // RSADP can return CRYPT_PARAMETR |
| return RSADP(*sigOutSize,sigOut, key); |
| } |
| // |
| // |
| // _cpri__ValidateSignatureRSA() |
| // |
| // This function is used to validate an RSA signature. If the signature is valid CRYPT_SUCCESS is |
| // returned. If the signature is not valid, CRYPT_FAIL is returned. Other return codes indicate either |
| // parameter problems or fatal errors. |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_SUCCESS the signature checks |
| // CRYPT_FAIL the signature does not check |
| // CRYPT_SCHEME unsupported scheme or hash algorithm |
| // |
| LIB_EXPORT CRYPT_RESULT |
| _cpri__ValidateSignatureRSA( |
| RSA_KEY *key, // IN: key to use |
| TPM_ALG_ID scheme, // IN: the scheme to use |
| TPM_ALG_ID hashAlg, // IN: hash algorithm |
| UINT32 hInSize, // IN: size of digest to be checked |
| BYTE *hIn, // IN: digest buffer |
| UINT32 sigInSize, // IN: size of signature |
| BYTE *sigIn, // IN: signature |
| UINT16 saltSize // IN: salt size for PSS |
| ) |
| { |
| CRYPT_RESULT retVal; |
| // Fatal programming errors |
| pAssert(key != NULL && sigIn != NULL && hIn != NULL); |
| // Errors that might be caused by calling parameters |
| if(sigInSize != key->publicKey->size) |
| return CRYPT_FAIL; |
| // Decrypt the block |
| if((retVal = RSAEP(sigInSize, sigIn, key)) != CRYPT_SUCCESS) |
| return CRYPT_FAIL; |
| switch (scheme) |
| { |
| case TPM_ALG_NULL: |
| return CRYPT_SCHEME; |
| break; |
| case TPM_ALG_RSAPSS: |
| return PssDecode(hashAlg, hInSize, hIn, sigInSize, sigIn, saltSize); |
| break; |
| case TPM_ALG_RSASSA: |
| return RSASSA_Decode(hashAlg, hInSize, hIn, sigInSize, sigIn); |
| break; |
| default: |
| break; |
| } |
| return CRYPT_SCHEME; |
| } |
| #ifndef RSA_KEY_SIEVE |
| // |
| // |
| // _cpri__GenerateKeyRSA() |
| // |
| // Generate an RSA key from a provided seed |
| // |
| // |
| // |
| // |
| // Return Value Meaning |
| // |
| // CRYPT_FAIL exponent is not prime or is less than 3; or could not find a prime using |
| // the provided parameters |
| // CRYPT_CANCEL operation was canceled |
| // |
| LIB_EXPORT CRYPT_RESULT |
| _cpri__GenerateKeyRSA( |
| TPM2B *n, // OUT: The public modulu |
| TPM2B *p, // OUT: One of the prime factors of n |
| UINT16 keySizeInBits, // IN: Size of the public modulus in bit |
| UINT32 e, // IN: The public exponent |
| TPM_ALG_ID hashAlg, // IN: hash algorithm to use in the key |
| // generation proce |
| TPM2B *seed, // IN: the seed to use |
| const char *label, // IN: A label for the generation process. |
| TPM2B *extra, // IN: Party 1 data for the KDF |
| UINT32 *counter // IN/OUT: Counter value to allow KFD iteration |
| // to be propagated across multiple routine |
| ) |
| { |
| UINT32 lLen; // length of the label |
| // (counting the terminating 0); |
| UINT16 digestSize = _cpri__GetDigestSize(hashAlg); |
| TPM2B_HASH_BLOCK oPadKey; |
| UINT32 outer; |
| UINT32 inner; |
| BYTE swapped[4]; |
| CRYPT_RESULT retVal; |
| int i, fill; |
| const static char defaultLabel[] = "RSA key"; |
| BYTE *pb; |
| CPRI_HASH_STATE h1; // contains the hash of the |
| // HMAC key w/ iPad |
| CPRI_HASH_STATE h2; // contains the hash of the |
| // HMAC key w/ oPad |
| CPRI_HASH_STATE h; // the working hash context |
| BIGNUM *bnP; |
| BIGNUM *bnQ; |
| BIGNUM *bnT; |
| BIGNUM *bnE; |
| BIGNUM *bnN; |
| BN_CTX *context; |
| UINT32 rem; |
| // Make sure that hashAlg is valid hash |
| pAssert(digestSize != 0); |
| // if present, use externally provided counter |
| if(counter != NULL) |
| outer = *counter; |
| else |
| outer = 1; |
| // Validate exponent |
| UINT32_TO_BYTE_ARRAY(e, swapped); |
| // Need to check that the exponent is prime and not less than 3 |
| if( e != 0 && (e < 3 || !_math__IsPrime(e))) |
| return CRYPT_FAIL; |
| // Get structures for the big number representations |
| context = BN_CTX_new(); |
| if(context == NULL) |
| FAIL(FATAL_ERROR_ALLOCATION); |
| BN_CTX_start(context); |
| bnP = BN_CTX_get(context); |
| bnQ = BN_CTX_get(context); |
| bnT = BN_CTX_get(context); |
| bnE = BN_CTX_get(context); |
| bnN = BN_CTX_get(context); |
| if(bnN == NULL) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // Set Q to zero. This is used as a flag. The prime is computed in P. When a |
| // new prime is found, Q is checked to see if it is zero. If so, P is copied |
| // to Q and a new P is found. When both P and Q are non-zero, the modulus and |
| // private exponent are computed and a trial encryption/decryption is |
| // performed. If the encrypt/decrypt fails, assume that at least one of the |
| // primes is composite. Since we don't know which one, set Q to zero and start |
| // over and find a new pair of primes. |
| BN_zero(bnQ); |
| // Need to have some label |
| if(label == NULL) |
| label = (const char *)&defaultLabel; |
| // Get the label size |
| for(lLen = 0; label[lLen++] != 0;); |
| // Start the hash using the seed and get the intermediate hash value |
| _cpri__StartHMAC(hashAlg, FALSE, &h1, seed->size, seed->buffer, &oPadKey.b); |
| _cpri__StartHash(hashAlg, FALSE, &h2); |
| _cpri__UpdateHash(&h2, oPadKey.b.size, oPadKey.b.buffer); |
| n->size = (keySizeInBits +7)/8; |
| pAssert(n->size <= MAX_RSA_KEY_BYTES); |
| p->size = n->size / 2; |
| if(e == 0) |
| e = RSA_DEFAULT_PUBLIC_EXPONENT; |
| BN_set_word(bnE, e); |
| // The first test will increment the counter from zero. |
| for(outer += 1; outer != 0; outer++) |
| { |
| if(_plat__IsCanceled()) |
| { |
| retVal = CRYPT_CANCEL; |
| goto Cleanup; |
| } |
| // Need to fill in the candidate with the hash |
| fill = digestSize; |
| pb = p->buffer; |
| // Reset the inner counter |
| inner = 0; |
| for(i = p->size; i > 0; i -= digestSize) |
| { |
| inner++; |
| // Initialize the HMAC with saved state |
| _cpri__CopyHashState(&h, &h1); |
| // Hash the inner counter (the one that changes on each HMAC iteration) |
| UINT32_TO_BYTE_ARRAY(inner, swapped); |
| _cpri__UpdateHash(&h, 4, swapped); |
| _cpri__UpdateHash(&h, lLen, (BYTE *)label); |
| // Is there any party 1 data |
| if(extra != NULL) |
| _cpri__UpdateHash(&h, extra->size, extra->buffer); |
| // Include the outer counter (the one that changes on each prime |
| // prime candidate generation |
| UINT32_TO_BYTE_ARRAY(outer, swapped); |
| _cpri__UpdateHash(&h, 4, swapped); |
| _cpri__UpdateHash(&h, 2, (BYTE *)&keySizeInBits); |
| if(i < fill) |
| fill = i; |
| _cpri__CompleteHash(&h, fill, pb); |
| // Restart the oPad hash |
| _cpri__CopyHashState(&h, &h2); |
| // Add the last hashed data |
| _cpri__UpdateHash(&h, fill, pb); |
| // gives a completed HMAC |
| _cpri__CompleteHash(&h, fill, pb); |
| pb += fill; |
| } |
| // Set the Most significant 2 bits and the low bit of the candidate |
| p->buffer[0] |= 0xC0; |
| p->buffer[p->size - 1] |= 1; |
| // Convert the candidate to a BN |
| BN_bin2bn(p->buffer, p->size, bnP); |
| // If this is the second prime, make sure that it differs from the |
| // first prime by at least 2^100 |
| if(!BN_is_zero(bnQ)) |
| { |
| // bnQ is non-zero if we already found it |
| if(BN_ucmp(bnP, bnQ) < 0) |
| BN_sub(bnT, bnQ, bnP); |
| else |
| BN_sub(bnT, bnP, bnQ); |
| if(BN_num_bits(bnT) < 100) // Difference has to be at least 100 bits |
| continue; |
| } |
| // Make sure that the prime candidate (p) is not divisible by the exponent |
| // and that (p-1) is not divisible by the exponent |
| // Get the remainder after dividing by the modulus |
| rem = BN_mod_word(bnP, e); |
| if(rem == 0) // evenly divisible so add two keeping the number odd and |
| // making sure that 1 != p mod e |
| BN_add_word(bnP, 2); |
| else if(rem == 1) // leaves a remainder of 1 so subtract two keeping the |
| // number odd and making (e-1) = p mod e |
| BN_sub_word(bnP, 2); |
| // Have a candidate, check for primality |
| if((retVal = (CRYPT_RESULT)BN_is_prime_ex(bnP, |
| BN_prime_checks, NULL, NULL)) < 0) |
| FAIL(FATAL_ERROR_INTERNAL); |
| if(retVal != 1) |
| continue; |
| // Found a prime, is this the first or second. |
| if(BN_is_zero(bnQ)) |
| { |
| // copy p to q and compute another prime in p |
| BN_copy(bnQ, bnP); |
| continue; |
| } |
| //Form the public modulus |
| BN_mul(bnN, bnP, bnQ, context); |
| if(BN_num_bits(bnN) != keySizeInBits) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // Save the public modulus |
| BnTo2B(n, bnN, n->size); // Will pad the buffer to the correct size |
| pAssert((n->buffer[0] & 0x80) != 0); |
| // And one prime |
| BnTo2B(p, bnP, p->size); |
| pAssert((p->buffer[0] & 0x80) != 0); |
| // Finish by making sure that we can form the modular inverse of PHI |
| // with respect to the public exponent |
| // Compute PHI = (p - 1)(q - 1) = n - p - q + 1 |
| // Make sure that we can form the modular inverse |
| BN_sub(bnT, bnN, bnP); |
| BN_sub(bnT, bnT, bnQ); |
| BN_add_word(bnT, 1); |
| // find d such that (Phi * d) mod e ==1 |
| // If there isn't then we are broken because we took the step |
| // of making sure that the prime != 1 mod e so the modular inverse |
| // must exist |
| if(BN_mod_inverse(bnT, bnE, bnT, context) == NULL || BN_is_zero(bnT)) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // And, finally, do a trial encryption decryption |
| { |
| TPM2B_TYPE(RSA_KEY, MAX_RSA_KEY_BYTES); |
| TPM2B_RSA_KEY r; |
| r.t.size = sizeof(n->size); |
| // If we are using a seed, then results must be reproducible on each |
| // call. Otherwise, just get a random number |
| if(seed == NULL) |
| _cpri__GenerateRandom(n->size, r.t.buffer); |
| else |
| { |
| // this this version does not have a deterministic RNG, XOR the |
| // public key and private exponent to get a deterministic value |
| // for testing. |
| int i; |
| // Generate a random-ish number starting with the public modulus |
| // XORed with the MSO of the seed |
| for(i = 0; i < n->size; i++) |
| r.t.buffer[i] = n->buffer[i] ^ seed->buffer[0]; |
| } |
| // Make sure that the number is smaller than the public modulus |
| r.t.buffer[0] &= 0x7F; |
| // Convert |
| if( BN_bin2bn(r.t.buffer, r.t.size, bnP) == NULL |
| // Encrypt with the public exponent |
| || BN_mod_exp(bnQ, bnP, bnE, bnN, context) != 1 |
| // Decrypt with the private exponent |
| || BN_mod_exp(bnQ, bnQ, bnT, bnN, context) != 1) |
| FAIL(FATAL_ERROR_INTERNAL); |
| // If the starting and ending values are not the same, start over )-; |
| if(BN_ucmp(bnP, bnQ) != 0) |
| { |
| BN_zero(bnQ); |
| continue; |
| } |
| } |
| retVal = CRYPT_SUCCESS; |
| goto Cleanup; |
| } |
| retVal = CRYPT_FAIL; |
| Cleanup: |
| // Close out the hash sessions |
| _cpri__CompleteHash(&h2, 0, NULL); |
| _cpri__CompleteHash(&h1, 0, NULL); |
| // Free up allocated BN values |
| BN_CTX_end(context); |
| BN_CTX_free(context); |
| if(counter != NULL) |
| *counter = outer; |
| return retVal; |
| } |
| #endif // RSA_KEY_SIEVE |
| #endif // TPM_ALG_RSA |