Changeset 2566


Ignore:
Timestamp:
03/21/12 10:26:45 (3 years ago)
Author:
lowjoel
Message:

Merged revisions 2563 and 2565 from Eraser 6.0:

  • Remove the unused PRFAlgorithms enum.
  • Removed the capability for switchable algorithms at runtime, and changed the default pool mixing function to SHA-1 since under FIPS compliance mode on Windows XP the SHA-2 family of hashes are not available. RIPEMD-160 is likewise not available. As such, under FIPS compliance mode, we will only use SHA-1, even on later OSes, and make primer mixing with RIPEMD-160 unavailable.
  • The sleep time between polls is now variable between 2 and 5 seconds. The previous one tended to pick the same amounts of time since it would effectively make one loop double the time it took to gather entropy from all entropy sources.
  • Only push entropy to the PRNGs every 10 minutes

Addresses #406

Location:
trunk/eraser
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/eraser

  • trunk/eraser/Eraser.Manager/EntropyPoller.cs

    r2516 r2566  
    4242    { 
    4343        /// <summary> 
    44         /// The algorithm used for mixing 
    45         /// </summary> 
    46         private enum PRFAlgorithms 
    47         { 
    48             Md5, 
    49             Sha1, 
    50             Ripemd160, 
    51             Sha256, 
    52             Sha384, 
    53             Sha512, 
    54         }; 
    55  
    56         /// <summary> 
    5744        /// Constructor. 
    5845        /// </summary> 
     
    6047        { 
    6148            //Create the pool. 
    62             pool = new byte[sizeof(uint) << 7]; 
     49            Pool = new byte[sizeof(uint) << 7]; 
    6350 
    6451            //Then start the thread which maintains the pool. 
     
    7461        private void Main() 
    7562        { 
    76             //This entropy thread will utilize a polling loop. 
     63            //Maintain the time we last provided entropy to the PRNGs. We will only 
     64            //provide entropy every 10 minutes. 
    7765            DateTime lastAddedEntropy = DateTime.Now; 
    7866            TimeSpan managerEntropySpan = new TimeSpan(0, 10, 0); 
    79             Stopwatch st = new Stopwatch(); 
    8067 
    8168            while (Thread.ThreadState != System.Threading.ThreadState.AbortRequested) 
    8269            { 
    83                 st.Start(); 
    8470                lock (EntropySources) 
    8571                    foreach (IEntropySource src in EntropySources) 
     
    8975                    } 
    9076 
    91                 st.Stop(); 
    92                 // 2049 = bin '100000000001' ==> great avalanche 
    93                 Thread.Sleep(2000 + (int)(st.ElapsedTicks % 2049L)); 
    94                 st.Reset(); 
     77                //Sleep for a "random" period between roughly [2, 5) seconds from now 
     78                Thread.Sleep(2000 + (int)(DateTime.Now.Ticks % 2999)); 
    9579 
    9680                // Send entropy to the PRNGs for new seeds. 
    97                 if (DateTime.Now - lastAddedEntropy > managerEntropySpan) 
     81                DateTime now = DateTime.Now; 
     82                if (now - lastAddedEntropy > managerEntropySpan) 
     83                { 
    9884                    Host.Instance.Prngs.AddEntropy(GetPool()); 
     85                    lastAddedEntropy = now; 
     86                } 
    9987            } 
    10088        } 
     
    120108            MixPool(); 
    121109 
    122             //Apply whitening effect 
    123             PRFAlgorithm = PRFAlgorithms.Ripemd160; 
    124             MixPool(); 
    125             PRFAlgorithm = PRFAlgorithms.Sha512; 
     110            //Apply "whitening" effect. Try to mix the pool using RIPEMD-160 to strengthen 
     111            //the cryptographic strength of the pool. 
     112            //There is a need to catch the InvalidOperationException because if Eraser is 
     113            //running under an OS with FIPS-compliance mode the RIPEMD-160 algorithm cannot 
     114            //be used. 
     115            try 
     116            { 
     117                using (HashAlgorithm hash = new RIPEMD160Managed()) 
     118                    MixPool(hash); 
     119            } 
     120            catch (InvalidOperationException) 
     121            { 
     122            } 
    126123        } 
    127124 
     
    137134 
    138135            //Return a safe copy 
    139             lock (poolLock) 
    140             { 
    141                 byte[] result = new byte[pool.Length]; 
    142                 pool.CopyTo(result, 0); 
     136            lock (PoolLock) 
     137            { 
     138                byte[] result = new byte[Pool.Length]; 
     139                Pool.CopyTo(result, 0); 
    143140 
    144141                return result; 
     
    151148        private void InvertPool() 
    152149        { 
    153             lock (poolLock) 
     150            lock (PoolLock) 
    154151                unsafe 
    155152                { 
    156                     fixed (byte* fPool = pool) 
     153                    fixed (byte* fPool = Pool) 
    157154                    { 
    158155                        uint* pPool = (uint*)fPool; 
    159                         uint poolLength = (uint)(pool.Length / sizeof(uint)); 
     156                        uint poolLength = (uint)(Pool.Length / sizeof(uint)); 
    160157                        while (poolLength-- != 0) 
    161158                            *pPool = (uint)(*pPool++ ^ uint.MaxValue); 
     
    167164        /// Mixes the contents of the pool. 
    168165        /// </summary> 
    169         private void MixPool() 
    170         { 
    171             lock (poolLock) 
     166        private void MixPool(HashAlgorithm hash) 
     167        { 
     168            lock (PoolLock) 
    172169            { 
    173170                //Mix the last 128 bytes first. 
    174171                const int mixBlockSize = 128; 
    175                 int hashSize = PRF.HashSize / 8; 
    176                 PRF.ComputeHash(pool, pool.Length - mixBlockSize, mixBlockSize).CopyTo(pool, 0); 
     172                int hashSize = hash.HashSize / 8; 
     173                hash.ComputeHash(Pool, Pool.Length - mixBlockSize, mixBlockSize).CopyTo(Pool, 0); 
    177174 
    178175                //Then mix the following bytes until wraparound is required 
    179176                int i = 0; 
    180                 for (; i < pool.Length - hashSize; i += hashSize) 
    181                     Buffer.BlockCopy(PRF.ComputeHash(pool, i, 
    182                         i + mixBlockSize >= pool.Length ? pool.Length - i : mixBlockSize), 
    183                         0, pool, i, i + hashSize >= pool.Length ? pool.Length - i : hashSize); 
     177                for (; i < Pool.Length - hashSize; i += hashSize) 
     178                    Buffer.BlockCopy(hash.ComputeHash(Pool, i, 
     179                        i + mixBlockSize >= Pool.Length ? Pool.Length - i : mixBlockSize), 
     180                        0, Pool, i, i + hashSize >= Pool.Length ? Pool.Length - i : hashSize); 
    184181 
    185182                //Mix the remaining blocks which require copying from the front 
    186183                byte[] combinedBuffer = new byte[mixBlockSize]; 
    187                 for (; i < pool.Length; i += hashSize) 
    188                 { 
    189                     Buffer.BlockCopy(pool, i, combinedBuffer, 0, pool.Length - i); 
    190  
    191                     Buffer.BlockCopy(pool, 0, combinedBuffer, pool.Length - i, 
    192                                 mixBlockSize - (pool.Length - i)); 
    193  
    194                     Buffer.BlockCopy(PRF.ComputeHash(combinedBuffer, 0, mixBlockSize), 0, 
    195                         pool, i, pool.Length - i > hashSize ? hashSize : pool.Length - i); 
    196                 } 
    197             } 
     184                for (; i < Pool.Length; i += hashSize) 
     185                { 
     186                    Buffer.BlockCopy(Pool, i, combinedBuffer, 0, Pool.Length - i); 
     187 
     188                    Buffer.BlockCopy(Pool, 0, combinedBuffer, Pool.Length - i, 
     189                                mixBlockSize - (Pool.Length - i)); 
     190 
     191                    Buffer.BlockCopy(hash.ComputeHash(combinedBuffer, 0, mixBlockSize), 0, 
     192                        Pool, i, Pool.Length - i > hashSize ? hashSize : Pool.Length - i); 
     193                } 
     194            } 
     195        } 
     196 
     197        /// <summary> 
     198        /// Mixes the contents of the entropy pool using the currently specified default 
     199        /// algorithm. 
     200        /// </summary> 
     201        private void MixPool() 
     202        { 
     203            using (HashAlgorithm hash = new SHA1CryptoServiceProvider()) 
     204                MixPool(hash); 
    198205        } 
    199206 
     
    205212        public unsafe void AddEntropy(byte[] entropy) 
    206213        { 
    207             lock (poolLock) 
     214            lock (PoolLock) 
    208215                fixed (byte* pEntropy = entropy) 
    209                 fixed (byte* pPool = pool) 
     216                fixed (byte* pPool = Pool) 
    210217                { 
    211218                    int size = entropy.Length; 
     
    214221                    { 
    215222                        //Bring the pool position back to the front if we are at our end 
    216                         if (poolPosition >= pool.Length) 
    217                             poolPosition = 0; 
    218  
    219                         int amountToMix = Math.Min(size, pool.Length - poolPosition); 
    220                         MemoryXor(pPool + poolPosition, mpEntropy, amountToMix); 
     223                        if (PoolPosition >= Pool.Length) 
     224                            PoolPosition = 0; 
     225 
     226                        int amountToMix = Math.Min(size, Pool.Length - PoolPosition); 
     227                        MemoryXor(pPool + PoolPosition, mpEntropy, amountToMix); 
    221228                        mpEntropy = mpEntropy + amountToMix; 
    222229                        size -= amountToMix; 
     
    255262 
    256263        /// <summary> 
    257         /// PRF algorithm handle 
    258         /// </summary> 
    259         private HashAlgorithm PRF 
    260         { 
    261             get 
    262             { 
    263                 Type type = null; 
    264                 switch (PRFAlgorithm) 
    265                 { 
    266                     case PRFAlgorithms.Md5: 
    267                         type = typeof(MD5CryptoServiceProvider); 
    268                         break; 
    269                     case PRFAlgorithms.Sha1: 
    270                         type = typeof(SHA1Managed); 
    271                         break; 
    272                     case PRFAlgorithms.Ripemd160: 
    273                         type = typeof(RIPEMD160Managed); 
    274                         break; 
    275                     case PRFAlgorithms.Sha256: 
    276                         type = typeof(SHA256Managed); 
    277                         break; 
    278                     case PRFAlgorithms.Sha384: 
    279                         type = typeof(SHA384Managed); 
    280                         break; 
    281                     default: 
    282                         type = typeof(SHA512Managed); 
    283                         break; 
    284                 } 
    285  
    286                 if (type.IsInstanceOfType(prfCache)) 
    287                     return prfCache; 
    288                 ConstructorInfo hashConstructor = type.GetConstructor(Type.EmptyTypes); 
    289                 return prfCache = (HashAlgorithm)hashConstructor.Invoke(null); 
    290             } 
    291         } 
    292  
    293         /// <summary> 
    294         /// The last created PRF algorithm handle. 
    295         /// </summary> 
    296         private HashAlgorithm prfCache; 
    297  
    298         /// <summary> 
    299         /// PRF algorithm identifier 
    300         /// </summary> 
    301         private PRFAlgorithms PRFAlgorithm = PRFAlgorithms.Sha512; 
    302  
    303         /// <summary> 
    304264        /// The pool of data which we currently maintain. 
    305265        /// </summary> 
    306         private byte[] pool; 
     266        private byte[] Pool; 
    307267 
    308268        /// <summary> 
    309269        /// The next position where entropy will be added to the pool. 
    310270        /// </summary> 
    311         private int poolPosition; 
     271        private int PoolPosition; 
    312272 
    313273        /// <summary> 
    314274        /// The lock guarding the pool array and the current entropy addition index. 
    315275        /// </summary> 
    316         private object poolLock = new object(); 
     276        private object PoolLock = new object(); 
    317277 
    318278        /// <summary> 
Note: See TracChangeset for help on using the changeset viewer.