--- a/kernel/eka/kernel/random.cpp Tue Feb 02 01:24:03 2010 +0200
+++ b/kernel/eka/kernel/random.cpp Sat Feb 20 00:10:51 2010 +0200
@@ -16,52 +16,23 @@
//
#include <kernel/kern_priv.h>
-
-//
-// Generate nth random number using the following algorithm
-//
-// X[n] = ((X[n-j] rotl r1) + (X[n-k] rotl r2)) modulo 2^b
-//
-// k=17, j=10, r1=5, r2=3
-//
-
-const TInt KBufferSize=17;
-const TInt KBufferSizeInBits=KBufferSize*32;
-const TInt KPointer2Offset=10; // Must be less than KBufferSize
-
-TUint32 RandomBuffer[KBufferSize];
-TInt RandomPointer=1;
-TInt RandomSaltPointer=KBufferSizeInBits-1;
-
-inline TUint32 RotateLeft5(TUint32 aVal)
- { return (aVal << 5) | (aVal >> 27); }
+#include "securerng.h"
+#include "execs.h"
-inline TUint32 RotateLeft3(TUint32 aVal)
- { return (aVal << 3) | (aVal >> 29); }
-
-void K::Randomize()
-//
-// Initialise the random pool
-//
- {
- TUint64 seed=K::TickQ->iRtc;
- TInt i;
- for (i=0; i<KBufferSize; i++)
- {
- RandomBuffer[i] = TUint32(seed);
- seed= ((seed<<5) + (seed>>59)) + 97;
- }
- NKern::LockSystem();
- for (i=0; i<50; i++)
- Kern::Random();
- NKern::UnlockSystem();
- }
-
+// The global pointer to the RNG instance
+DSecureRNG* SecureRNG;
/**
- Generate the next random number.
+ Gets 32 random bits from the kernel's random number generator.
+
+ The returned random data may or may not be cryptographically secure but should be of a high quality for
+ non-cryptographic purposes.
- @return The generated random number.
+ This function uses a cryptographically strong random number generator to generate the random data, which can
+ be slower than insecure generators. If security is not important, you may wish to use a trivial RNG instead
+ for performance.
+
+ @return The 32 random bits.
@pre Kernel Lock must not be held.
@pre No fast mutex should be held
@@ -70,42 +41,116 @@
*/
EXPORT_C TUint32 Kern::Random()
{
- TBool alreadyLocked = TheScheduler.iLock.HeldByCurrentThread();
- if (!alreadyLocked)
- NKern::LockSystem();
- TInt p1 = RandomPointer;
- if(--p1<0)
- p1 = KBufferSize-1;
- RandomPointer = p1;
- TInt p2 = p1+KPointer2Offset;
- if(p2>KBufferSize-1)
- p2 -= KBufferSize-1;
- TUint32 r = RandomBuffer[p1] = RotateLeft5(RandomBuffer[p2])+RotateLeft3(RandomBuffer[p1]);
- if (!alreadyLocked)
- NKern::UnlockSystem();
- return r;
+ CHECK_PRECONDITIONS(MASK_THREAD_STANDARD, "Kern::Random()");
+ TBuf8<4> randomBuffer;
+ randomBuffer.SetMax();
+ SecureRNG->GenerateRandomNumber(randomBuffer);
+ return *((const TUint32*)randomBuffer.Ptr());
+ }
+
+/**
+ Fills the provided descriptor with random data up to its current length. The number of random bytes required
+ should be specified by setting the length of the descriptor that is passed to the function.
+
+ If the returned random data cannot be guaranteed to be cryptographically secure, the function will return
+ KErrNotReady, but data will still be provided suitable for non-cryptographic purposes.
+
+ The security strength of the cryptograpically strong random number generator is 256 bits.
+
+ @param aRandomValue on return, the descriptor is filled with the requested number of random bytes.
+
+ @return KErrArgument if more than 65536 bytes are requested in a single call.
+ KErrNotReady if the returned random data cannot be guaranteed to be cryptographically secure.
+ KErrNone if the returned random data is believed to be cryptographically secure.
+
+ @pre Kernel Lock must not be held
+ @pre No fast mutex should be held
+ @pre Interrupts should be enabled
+ @pre Can be used in a device driver.
+*/
+EXPORT_C TInt Kern::SecureRandom(TDes8& aRandomValue)
+ {
+ CHECK_PRECONDITIONS(MASK_THREAD_STANDARD, "Kern::SecureRandom(TDes8&)");
+ return SecureRNG->GenerateRandomNumber(aRandomValue);
}
/**
- Adds a bit to the random pool used to generate random numbers.
- This method should be used by any sources of entropy to improve the quality of
- random number generation.
+ Adds the given entropy input to the entropy pool used for random number generation.
+ This is the only version of Kern::RandomSalt which allows entropy samples larger than 8 bytes to be added.
+
+ Entropy estimates should be chosen carefully to reflect the minimum entropy that the sample may contain.
- @param aBitOfSalt The least significant bit of this value is added to the random pool.
+ @param aEntropyData Pointer to the entropy data.
+ @param aEntropyDataLength Length of the entropy data in bytes.
+ @param aBitsOfEntropy The amount of entropy (in bits) present in the entropy data.
- @pre Can be used in a device driver.
+ @pre Kernel Lock must not be held
+ @pre No fast mutex should be held
+ @pre Interrupts should be enabled
+ @pre Can be used in a device driver.
*/
-EXPORT_C void Kern::RandomSalt(TUint32 aBitOfSalt)
+EXPORT_C void Kern::RandomSalt(const TUint8* aEntropyData, TUint aEntropyDataLength, TUint aBitsOfEntropy)
{
- TInt p=RandomSaltPointer; // protect RandomSaltPointer from re-entrantrancy
- if (aBitOfSalt&=1)
+ CHECK_PRECONDITIONS(MASK_THREAD_STANDARD, "Kern::RandomSalt(const TUint8*, TUint, TUint)");
+
+ // Check if the claimed entropy estimation (in bits) is not more than the maximum value.
+ __ASSERT_ALWAYS(aBitsOfEntropy <= aEntropyDataLength*8, K::PanicKernExec(EEntropyEstimateOutOfRange));
+
+ // If the Secure RNG system is not in idle mode, add the collected entropy to the entropy pool.
+ if (!SecureRNG->SecureRNGIdle())
{
- TInt word=p >> 5;
- TInt bit=p & 0x1f;
- RandomBuffer[word] ^= aBitOfSalt << bit;
+ SecureRNG->AddEntropy(aEntropyData, aEntropyDataLength, aBitsOfEntropy);
}
- if (--p<0)
- p=KBufferSizeInBits-1;
- RandomSaltPointer=p;
}
+/*
+ * Exec handler function for obtaining secure random numbers
+ */
+TInt ExecHandler::MathSecureRandom(TDes8& aRandomValue)
+ {
+ TInt randomValueLength = 0;
+ TInt randomValueMaxLength = 0;
+ //Gets information about the user specified descriptor.
+ TUint8* kernelPtr = (TUint8*)Kern::KUDesInfo(aRandomValue, randomValueLength, randomValueMaxLength);
+ if(randomValueMaxLength == -1) //user passed descriptor is not writable
+ {
+ K::PanicKernExec(EKUDesSetLengthInvalidType);
+ }
+
+ // The random number generator requires a temporary buffer to write the data to, before we write it back to
+ // userspace's buffer. The buffer is allocated here on the stack to avoid having to heap-allocate, and if
+ // the requested amount of data is larger, a loop is used. 2048 bytes will always fit onto the stack in an
+ // exec handler.
+ const TInt KRandomBufferSize = 2048;
+ TBuf8<KRandomBufferSize> randomBuffer;
+
+ TInt err = KErrNone;
+ TBool isKErrNotReadyTrue = EFalse;
+ while(randomValueLength > 0)
+ {
+ TInt noOfBytesToGenerate = (randomValueLength > KRandomBufferSize) ? KRandomBufferSize : randomValueLength;
+ randomBuffer.SetLength(noOfBytesToGenerate);
+ // Generate random numbers
+ err = Kern::SecureRandom(randomBuffer);
+ if(err == KErrNotReady)
+ {
+ isKErrNotReadyTrue = ETrue;
+ }
+ else if (err != KErrNone)
+ {
+ return err; // any other system wide error code needs to be returned immediately.
+ }
+ // Copy the generated random numbers to the user descriptor.
+ umemput(kernelPtr, randomBuffer.Ptr(), noOfBytesToGenerate);
+ kernelPtr += KRandomBufferSize;
+ randomValueLength -= KRandomBufferSize;
+ }
+
+ // Atleast one KErrNotReady error was generated during processing the request, so return the state as not ready
+ // indicating the internal states was not secure during random number generation.
+ if(isKErrNotReadyTrue)
+ {
+ return KErrNotReady;
+ }
+ return err;
+ }