Assets/Scripts/BIP39/Utilities.cs
/// <summary>
/// Safely get Crypto Random byte array at the size you desire.
/// </summary>
/// <param name="size">Size of the crypto random byte array to build</param>
/// <param name="seedStretchingIterations">Optional parameter to specify how many SHA512 passes occur over our seed before we use it. Higher value is greater security but uses more computational power. If random byte generation is taking too long try specifying values lower than the default of 5000. You can set 0 to turn off stretching</param>
/// <returns>A byte array of completely random bytes</returns>
Safely get Crypto Random byte array at the size you desire.
Safely get Crypto Random byte array at the size you desire .
public static byte[] GetRandomBytes(int size, int seedStretchingIterations = 5000)
        {
            int processorCount = System.Environment.ProcessorCount;
            int currentThreadId = System.Environment.CurrentManagedThreadId;
            byte[] guidBytes = Guid.NewGuid().ToByteArray();
            byte[] threadedSeedBytes = new ThreadedSeedGenerator().GenerateSeed(24, true);
            byte[] output = new byte[size];
            if (processorCount <= 0)
            {
                processorCount = 16;
            }
            if (seedStretchingIterations < 0)
            {
                seedStretchingIterations = 0;
            }
            SecureRandom seedByteTakeDetermine = SecureRandom.GetInstance("SHA256PRNG");
            guidBytes = HmacSha512Digest(guidBytes, 0, guidBytes.Length, MergeByteArrays(threadedSeedBytes, UTF8Encoding.UTF8.GetBytes(Convert.ToString(System.Environment.TickCount))));
            try
            {
                seedByteTakeDetermine.SetSeed(((DateTime.Now.Ticks - System.Environment.TickCount) * processorCount) + currentThreadId);
                seedByteTakeDetermine.SetSeed(guidBytes);
                seedByteTakeDetermine.SetSeed(seedByteTakeDetermine.GenerateSeed(1 + currentThreadId));
                seedByteTakeDetermine.SetSeed(threadedSeedBytes);
            }
            catch
            {
                try
                {
                    seedByteTakeDetermine.SetSeed((DateTime.Now.Ticks - System.Environment.TickCount) + currentThreadId);
                    seedByteTakeDetermine.SetSeed(guidBytes);
                    seedByteTakeDetermine.SetSeed(seedByteTakeDetermine.GenerateSeed(1 + currentThreadId));
                    seedByteTakeDetermine.SetSeed(threadedSeedBytes);
                }
                catch
                {
                    seedByteTakeDetermine.SetSeed(DateTime.Now.Ticks - System.Environment.TickCount);
                    seedByteTakeDetermine.SetSeed(guidBytes);
                    seedByteTakeDetermine.SetSeed(seedByteTakeDetermine.GenerateSeed(1 + currentThreadId));
                    seedByteTakeDetermine.SetSeed(threadedSeedBytes);
                }
            }
            byte[] toHashForSeed;
            try
            {
                toHashForSeed = BitConverter.GetBytes(((processorCount - seedByteTakeDetermine.Next(0, processorCount)) * System.Environment.TickCount) * currentThreadId);
            }
            catch
            {
                try
                {
                    toHashForSeed = BitConverter.GetBytes(((processorCount - seedByteTakeDetermine.Next(0, processorCount)) + System.Environment.TickCount) * currentThreadId);
                }
                catch
                {
                    toHashForSeed = BitConverter.GetBytes(((processorCount - seedByteTakeDetermine.Next(0, processorCount)) + System.Environment.TickCount) + currentThreadId);
                }
            }
            toHashForSeed = Sha512Digest(toHashForSeed, 0, toHashForSeed.Length);
            toHashForSeed = MergeByteArrays(toHashForSeed, guidBytes);
            toHashForSeed = MergeByteArrays(toHashForSeed, BitConverter.GetBytes(currentThreadId));
            toHashForSeed = MergeByteArrays(toHashForSeed, BitConverter.GetBytes(DateTime.UtcNow.Ticks));
            toHashForSeed = MergeByteArrays(toHashForSeed, BitConverter.GetBytes(DateTime.Now.Ticks));
            toHashForSeed = MergeByteArrays(toHashForSeed, BitConverter.GetBytes(System.Environment.TickCount));
            toHashForSeed = MergeByteArrays(toHashForSeed, BitConverter.GetBytes(processorCount));
            toHashForSeed = MergeByteArrays(toHashForSeed, threadedSeedBytes);
            toHashForSeed = Sha512Digest(toHashForSeed, 0, toHashForSeed.Length);
            toHashForSeed = Sha512Digest(HmacSha512Digest(toHashForSeed, 0, seedByteTakeDetermine.Next(24, 64), guidBytes), 0, 64);
            seedByteTakeDetermine.SetSeed(currentThreadId + (DateTime.Now.Ticks - System.Environment.TickCount));
            int iterations = seedStretchingIterations - (seedByteTakeDetermine.Next(0, (seedStretchingIterations / seedByteTakeDetermine.Next(9, 100))));
            byte[] seedMaterial = Rfc2898_pbkdf2_hmacsha512.PBKDF2(toHashForSeed, seedByteTakeDetermine.GenerateSeed(64), iterations);
            SecureRandom secRand = new SecureRandom(new Org.BouncyCastle.Crypto.Prng.DigestRandomGenerator(new Sha512Digest()));
            secRand.SetSeed(seedMaterial);
            secRand.SetSeed(currentThreadId);
            secRand.SetSeed(MergeByteArrays(guidBytes, threadedSeedBytes));
            secRand.SetSeed(secRand.GenerateSeed(1 + secRand.Next(64)));
            secRand.SetSeed(seedMaterial);
            secRand.NextBytes(output, 0, size);
            return output;
        }
public static byte [ ] GetRandomBytes ( int size , int seedStretchingIterations = 5000 ) { int processorCount = System . Environment . ProcessorCount ; int currentThreadId = System . Environment . CurrentManagedThreadId ; byte [ ] guidBytes = Guid . NewGuid ( ) . ToByteArray ( ) ; byte [ ] threadedSeedBytes = new ThreadedSeedGenerator ( ) . GenerateSeed ( 24 , true ) ; byte [ ] output = new byte [ size ] ; if ( processorCount <= 0 ) { processorCount = 16 ; } if ( seedStretchingIterations < 0 ) { seedStretchingIterations = 0 ; } SecureRandom seedByteTakeDetermine = SecureRandom . GetInstance ( " " ) ; guidBytes = HmacSha512Digest ( guidBytes , 0 , guidBytes . Length , MergeByteArrays ( threadedSeedBytes , UTF8Encoding . UTF8 . GetBytes ( Convert . ToString ( System . Environment . TickCount ) ) ) ) ; try { seedByteTakeDetermine . SetSeed ( ( ( DateTime . Now . Ticks - System . Environment . TickCount ) * processorCount ) + currentThreadId ) ; seedByteTakeDetermine . SetSeed ( guidBytes ) ; seedByteTakeDetermine . SetSeed ( seedByteTakeDetermine . GenerateSeed ( 1 + currentThreadId ) ) ; seedByteTakeDetermine . SetSeed ( threadedSeedBytes ) ; } catch { try { seedByteTakeDetermine . SetSeed ( ( DateTime . Now . Ticks - System . Environment . TickCount ) + currentThreadId ) ; seedByteTakeDetermine . SetSeed ( guidBytes ) ; seedByteTakeDetermine . SetSeed ( seedByteTakeDetermine . GenerateSeed ( 1 + currentThreadId ) ) ; seedByteTakeDetermine . SetSeed ( threadedSeedBytes ) ; } catch { seedByteTakeDetermine . SetSeed ( DateTime . Now . Ticks - System . Environment . TickCount ) ; seedByteTakeDetermine . SetSeed ( guidBytes ) ; seedByteTakeDetermine . SetSeed ( seedByteTakeDetermine . GenerateSeed ( 1 + currentThreadId ) ) ; seedByteTakeDetermine . SetSeed ( threadedSeedBytes ) ; } } byte [ ] toHashForSeed ; try { toHashForSeed = BitConverter . GetBytes ( ( ( processorCount - seedByteTakeDetermine . Next ( 0 , processorCount ) ) * System . Environment . TickCount ) * currentThreadId ) ; } catch { try { toHashForSeed = BitConverter . GetBytes ( ( ( processorCount - seedByteTakeDetermine . Next ( 0 , processorCount ) ) + System . Environment . TickCount ) * currentThreadId ) ; } catch { toHashForSeed = BitConverter . GetBytes ( ( ( processorCount - seedByteTakeDetermine . Next ( 0 , processorCount ) ) + System . Environment . TickCount ) + currentThreadId ) ; } } toHashForSeed = Sha512Digest ( toHashForSeed , 0 , toHashForSeed . Length ) ; toHashForSeed = MergeByteArrays ( toHashForSeed , guidBytes ) ; toHashForSeed = MergeByteArrays ( toHashForSeed , BitConverter . GetBytes ( currentThreadId ) ) ; toHashForSeed = MergeByteArrays ( toHashForSeed , BitConverter . GetBytes ( DateTime . UtcNow . Ticks ) ) ; toHashForSeed = MergeByteArrays ( toHashForSeed , BitConverter . GetBytes ( DateTime . Now . Ticks ) ) ; toHashForSeed = MergeByteArrays ( toHashForSeed , BitConverter . GetBytes ( System . Environment . TickCount ) ) ; toHashForSeed = MergeByteArrays ( toHashForSeed , BitConverter . GetBytes ( processorCount ) ) ; toHashForSeed = MergeByteArrays ( toHashForSeed , threadedSeedBytes ) ; toHashForSeed = Sha512Digest ( toHashForSeed , 0 , toHashForSeed . Length ) ; toHashForSeed = Sha512Digest ( HmacSha512Digest ( toHashForSeed , 0 , seedByteTakeDetermine . Next ( 24 , 64 ) , guidBytes ) , 0 , 64 ) ; seedByteTakeDetermine . SetSeed ( currentThreadId + ( DateTime . Now . Ticks - System . Environment . TickCount ) ) ; int iterations = seedStretchingIterations - ( seedByteTakeDetermine . Next ( 0 , ( seedStretchingIterations / seedByteTakeDetermine . Next ( 9 , 100 ) ) ) ) ; byte [ ] seedMaterial = Rfc2898_pbkdf2_hmacsha512 . PBKDF2 ( toHashForSeed , seedByteTakeDetermine . GenerateSeed ( 64 ) , iterations ) ; SecureRandom secRand = new SecureRandom ( new Org . BouncyCastle . Crypto . Prng . DigestRandomGenerator ( new Sha512Digest ( ) ) ) ; secRand . SetSeed ( seedMaterial ) ; secRand . SetSeed ( currentThreadId ) ; secRand . SetSeed ( MergeByteArrays ( guidBytes , threadedSeedBytes ) ) ; secRand . SetSeed ( secRand . GenerateSeed ( 1 + secRand . Next ( 64 ) ) ) ; secRand . SetSeed ( seedMaterial ) ; secRand . NextBytes ( output , 0 , size ) ; return output ; }
Safely get Crypto Random byte array at the size you desire.
Safely get Crypto Random byte array at the size you desire .
//varies from system to system, a tiny amount of entropy, tiny //another tiny amount of entropy due to the varying nature of thread id //a GUID is considered unique so also provides some entropy //this combined with DateTime.Now is the default seed in BouncyCastles SecureRandom //if for whatever reason it says 0 or less processors just make it 16 //if some fool trys to set stretching to < 0 we protect them from themselves //we create a SecureRandom based off SHA256 just to get a random int which will be used to determine what bytes to "take" from our built seed hash and then rehash those taken seed bytes using a KDF (key stretching) such that it would slow down anyone trying to rebuild private keys from common seeds. //if the number is too big or causes an error or whatever we will failover to this, as it's not our main source of random bytes and not used in the KDF stretching it's ok. //if again the number is too big or causes an error or whatever we will failover to this, as it's not our main source of random bytes and not used in the KDF stretching it's ok. //hardened seed //if the number was too large or something we failover to this //if the number was again too large or something we failover to this //we grab a random amount of bytes between 24 and 64 to rehash  make a new set of 64 bytes, using guidBytes as hmackey //by making the iterations also random we are again making it hard to determin our seed by brute force //here we use key stretching techniques to make it harder to replay the random seed values by forcing computational time up //build a SecureRandom object that uses Sha512 to provide randomness and we will give it our created above hardened seed //set the seed that we created just above //generate more seed materisal //add our prefab seed again onto the previous material just to be sure the above statements are adding and not clobbering seed material //here we derive our random bytes
A byte array of completely random bytes
A byte array of completely random bytes
size
int
Size of the crypto random byte array to build
Size of the crypto random byte array to build
seedStretchingIterations
int
Optional parameter to specify how many SHA512 passes occur over our seed before we use it. Higher value is greater security but uses more computational power. If random byte generation is taking too long try specifying values lower than the default of 5000. You can set 0 to turn off stretching
Optional parameter to specify how many SHA512 passes occur over our seed before we use it . Higher value is greater security but uses more computational power . If random byte generation is taking too long try specifying values lower than the default of 5000 . You can set 0 to turn off stretching