/***************************************************************************** Function: RSA_STATUS RSAStep(void) Summary: Performs non-blocking RSA calculations. Description: Call this function to process a portion of the pending RSA operation until RSA_DONE is returned. This function performs small pieces of work each time it is called, so it must be called repeatedly in order to complete an operation. Performing small pieces at a time and then yielding to the main application allows long calculations to be performed in a non-blocking manner that fits with the co-operative multi-tasking model of the stack. Status updates are periodically returned. For lengthy decryption operations, this helps prevent client time-outs by allowing the application to periodically transmit a few bytes if necessary. Precondition: RSA has already been initialized and RSABeginUsage has returned TRUE. Parameters: None Return Values: RSA_WORKING - Calculation is in progress; no status update available. RSA_FINISHED_M1 - This call has completed the decryption calculation of the M1 CRT value. RSA_FINISHED_M2 - This call has completed the decryption calculation of the M2 CRT value. RSA_DONE - The RSA operation is complete. ***************************************************************************/ RSA_STATUS RSAStep(void) { #if defined(STACK_USE_RSA_DECRYPT) static BIGINT m1, m2; #endif switch(smRSA) { #if defined(STACK_USE_RSA_ENCRYPT) case SM_RSA_ENCRYPT_START: // Actually nothing to do here anymore smRSA = SM_RSA_ENCRYPT; case SM_RSA_ENCRYPT: // Call ModExp until complete if(_RSAModExp(&Y, &X, &E, &N)) {// Calculation is finished // Swap endian-ness if needed if(outputFormat == RSA_BIG_ENDIAN) BigIntSwapEndianness(&Y); // Indicate that we're finished smRSA = SM_RSA_DONE; return RSA_DONE; } break; #endif #if defined(STACK_USE_RSA_DECRYPT) case SM_RSA_DECRYPT_START: // Set up the RSA Decryption memories BigInt(&m1, (BIGINT_DATA_TYPE*)((BYTE*)&sslBuffer+(SSL_RSA_KEY_SIZE/8)), RSA_PRIME_WORDS); BigInt(&m2, (BIGINT_DATA_TYPE*)((BYTE*)&sslBuffer+3*(SSL_RSA_KEY_SIZE/16)), RSA_PRIME_WORDS); smRSA = SM_RSA_DECRYPT_FIND_M1; break; case SM_RSA_DECRYPT_FIND_M1: // m1 = c^dP % p if(_RSAModExpROM(&m1, &X, &dP, &P)) { smRSA = SM_RSA_DECRYPT_FIND_M2; return RSA_FINISHED_M1; } break; case SM_RSA_DECRYPT_FIND_M2: // m2 = c^dQ % q if(_RSAModExpROM(&m2, &X, &dQ, &Q)) { smRSA = SM_RSA_DECRYPT_FINISH; return RSA_FINISHED_M2; } break; case SM_RSA_DECRYPT_FINISH: // Almost done...finalize the CRT math if(BigIntCompare(&m1, &m2) > 0) {// if(m1 > m2) // m1 = m1 - m2 BigIntSubtract(&m1, &m2); // tmp = m1 * qInv BigIntMultiplyROM(&m1, &qInv, &tmp); // m1 = tmp % p BigIntModROM(&tmp, &P); BigIntCopy(&m1, &tmp); } else {// m1 < m2 // tmp = m2 BigIntCopy(&tmp, &m2); // m2 = m2 - m1 BigIntSubtract(&m2, &m1); // m1 = tmp BigIntCopy(&m1, &tmp); // tmp = m2 * qInv BigIntMultiplyROM(&m2, &qInv, &tmp); // m2 = m1 BigIntCopy(&m2, &m1); // tmp = tmp % p BigIntModROM(&tmp, &P); // m1 = P BigIntCopyROM(&m1, &P); // m1 = m1 - tmp; BigIntSubtract(&m1, &tmp); } // msg = m1 * q BigIntMultiplyROM(&m1, &Q, &tmp); // tmp = m2 + tmp BigIntAdd(&tmp, &m2); // Copy the decrypted value back to X BigIntCopy(&X, &tmp); // Swap endian-ness if needed if(outputFormat == RSA_BIG_ENDIAN) BigIntSwapEndianness(&X); // Indicate that we're finished smRSA = SM_RSA_DONE; return RSA_DONE; #endif default: // Unknown state return RSA_DONE; } // Indicate that we're still working return RSA_WORKING; }
void BigIntMod(BIGINT *n, BIGINT* m) { BIGINT_DATA_TYPE *ptrMSBn, MSBm; BIGINT_DATA_TYPE_2 qHatInt; union { BIGINT_DATA_TYPE v[2]; BIGINT_DATA_TYPE_2 Val; } topTwoWords; // Find the starting MSBs ptrMSBn = BigIntMSB(n); MSBm = *BigIntMSB(m); // Set up assembly pointers for m // _iB and _xB are limiters in the _mas function _iB = m->ptrLSB; _xB = BigIntMSB(m); // Find out how many bytes we need to shift and move the LSB up _iR = n->ptrLSB + (BigIntMagnitudeDifference(n, m) - 1); // This loops while the order of magnitude (in words) of n > m // Each iteration modulos off one word of magnitude from n while(_iR >= n->ptrLSB) { // Find qHat = MSBn:MSBn-1/MSBm topTwoWords.Val = *((BIGINT_DATA_TYPE_2*)(ptrMSBn - 1)); qHatInt = topTwoWords.Val / MSBm; if(qHatInt > BIGINT_DATA_MAX) qHatInt = BIGINT_DATA_MAX; #if BIGINT_DEBUG putrsUART("\r\n\r\n n = "); BigIntPrint(n); putrsUART("\r\n m = "); BigIntPrint(m); putrsUART("\r\n qHat ("); putulhexUART(qHatInt); putrsUART(") = topTwo("); putulhexUART(topTwoWords.Val); putrsUART(") / ("); putulhexUART(MSBm); putrsUART(") "); #endif // Once qHat is determined, we multiply M by qHat, shift it up // as many bytes as possible, and subtract the result. // In essence, qHat is a rough estimation of the quotient, divided // by a power of 2^8 (PIC18) or 2^16 (PIC24/dsPIC) or 2^32 (PIC32) // This implementation multiplies and subtracts in the same step // using a _mas function which saves about 30% of clock cycles. // Save the old MSB and set up the ASM pointers _wC = (BIGINT_DATA_TYPE)qHatInt; // Do the multiply and subtract // Occassionally this results in underflow...this is solved below. masBI(); // qHat may have been 1 or 2 greater than possible. If so, // the new MSB will be greater than the old one, so we *add* // M back to N in the shifted position until overflow occurs // and this case corrects itself. while(topTwoWords.v[1] < *BigIntMSB(n)) // while(((BIGINT_DATA_TYPE*)&topTwoWords)[1] < *BigIntMSB(n)) { _iA = _iR; _xA = BigIntMSB(n); addBI(); } // We should have modulated off a word (or two if we were lucky), // so move our MSB and LSB pointers as applicable while(*ptrMSBn == 0x0u) { _iR--; n->ptrMSB--; ptrMSBn--; } } // Iteration of the _mas function can only handle full-byte orders // of magnitude. The result may still be a little larger, so this // cleans up the last few multiples with simple subtraction. while(BigIntCompare(n, m) >= 0) { _iA = n->ptrLSB; _xA = n->ptrMSB; subBI(); // Invalidate MSB pointer n->bMSBValid = 0; } }