Beispiel #1
0
/*****************************************************************************
  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;
	
}
Beispiel #2
0
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;
	}
}