source: branches/eraser6/pluginsRewrite/Eraser.Manager/EntropyPoller.cs @ 2443

Revision 2443, 8.3 KB checked in by lowjoel, 2 years ago (diff)

Made all the extension points in Eraser.Plugins to be interfaces, to be true to the need for the Plugins assembly. Move all the implementation to Eraser.DefaultPlugins? (will be in a separate commit since basically the entire library needs to be rewritten.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2010 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By: Kasra Nassiri <cjax@users.sourceforge.net>
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25
26using System.Threading;
27using System.Security.Cryptography;
28using System.Runtime.InteropServices;
29using System.Diagnostics;
30using System.Reflection;
31
32using Eraser.Plugins;
33using Eraser.Plugins.ExtensionPoints;
34
35namespace Eraser.Manager
36{
37    /// <summary>
38    /// A class which uses EntropyPoll class to fetch system data as a source of
39    /// randomness at "regular" but "random" intervals
40    /// </summary>
41    public class EntropyPoller
42    {
43        /// <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>
57        /// Constructor.
58        /// </summary>
59        public EntropyPoller()
60        {
61            //Create the pool.
62            pool = new byte[sizeof(uint) << 7];
63
64            //Then start the thread which maintains the pool.
65            Thread = new Thread(Main);
66            Thread.Start();
67        }
68
69        /// <summary>
70        /// The PRNG entropy thread. This thread will run in the background, getting
71        /// random data to be used for entropy. This will maintain the integrity
72        /// of generated data from the PRNGs.
73        /// </summary>
74        private void Main()
75        {
76            //This entropy thread will utilize a polling loop.
77            DateTime lastAddedEntropy = DateTime.Now;
78            TimeSpan managerEntropySpan = new TimeSpan(0, 10, 0);
79            Stopwatch st = new Stopwatch();
80
81            while (Thread.ThreadState != System.Threading.ThreadState.AbortRequested)
82            {
83                st.Start();
84                lock (EntropySources)
85                    foreach (IEntropySource src in EntropySources)
86                    {
87                        byte[] entropy = src.GetEntropy();
88                        AddEntropy(entropy);
89                    }
90
91                st.Stop();
92                // 2049 = bin '100000000001' ==> great avalanche
93                Thread.Sleep(2000 + (int)(st.ElapsedTicks % 2049L));
94                st.Reset();
95
96                // Send entropy to the PRNGs for new seeds.
97                if (DateTime.Now - lastAddedEntropy > managerEntropySpan)
98                    Host.Instance.Prngs.AddEntropy(GetPool());
99            }
100        }
101
102        /// <summary>
103        /// Stops the execution of the thread.
104        /// </summary>
105        public void Abort()
106        {
107            Thread.Abort();
108        }
109
110        /// <summary>
111        /// Adds a new Entropy Source to the Poller.
112        /// </summary>
113        /// <param name="source">The EntropySource object to add.</param>
114        public void AddEntropySource(IEntropySource source)
115        {
116            lock (EntropySources)
117                EntropySources.Add(source);
118
119            AddEntropy(source.GetPrimer());
120            MixPool();
121
122            //Apply whitening effect
123            PRFAlgorithm = PRFAlgorithms.Ripemd160;
124            MixPool();
125            PRFAlgorithm = PRFAlgorithms.Sha512;
126        }
127
128        /// <summary>
129        /// Retrieves the current contents of the entropy pool.
130        /// </summary>
131        /// <returns>A byte array containing all the randomness currently found.</returns>
132        public byte[] GetPool()
133        {
134            //Mix and invert the pool
135            MixPool();
136            InvertPool();
137
138            //Return a safe copy
139            lock (poolLock)
140            {
141                byte[] result = new byte[pool.Length];
142                pool.CopyTo(result, 0);
143
144                return result;
145            }
146        }
147
148        /// <summary>
149        /// Inverts the contents of the pool
150        /// </summary>
151        private void InvertPool()
152        {
153            lock (poolLock)
154                unsafe
155                {
156                    fixed (byte* fPool = pool)
157                    {
158                        uint* pPool = (uint*)fPool;
159                        uint poolLength = (uint)(pool.Length / sizeof(uint));
160                        while (poolLength-- != 0)
161                            *pPool = (uint)(*pPool++ ^ uint.MaxValue);
162                    }
163                }
164        }
165
166        /// <summary>
167        /// Mixes the contents of the pool.
168        /// </summary>
169        private void MixPool()
170        {
171            lock (poolLock)
172            {
173                //Mix the last 128 bytes first.
174                const int mixBlockSize = 128;
175                int hashSize = PRF.HashSize / 8;
176                PRF.ComputeHash(pool, pool.Length - mixBlockSize, mixBlockSize).CopyTo(pool, 0);
177
178                //Then mix the following bytes until wraparound is required
179                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);
184
185                //Mix the remaining blocks which require copying from the front
186                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            }
198        }
199
200        /// <summary>
201        /// Adds data which is random to the pool
202        /// </summary>
203        /// <param name="entropy">An array of data which will be XORed with pool
204        /// contents.</param>
205        public unsafe void AddEntropy(byte[] entropy)
206        {
207            lock (poolLock)
208                fixed (byte* pEntropy = entropy)
209                fixed (byte* pPool = pool)
210                {
211                    int size = entropy.Length;
212                    byte* mpEntropy = pEntropy;
213                    while (size > 0)
214                    {
215                        //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);
221                        mpEntropy = mpEntropy + amountToMix;
222                        size -= amountToMix;
223                    }
224                }
225        }
226
227        /// <summary>
228        /// XOR's memory a DWORD at a time.
229        /// </summary>
230        /// <param name="destination">The destination buffer to be XOR'ed</param>
231        /// <param name="source">The source buffer to XOR with</param>
232        /// <param name="size">The size of the source buffer</param>
233        private static unsafe void MemoryXor(byte* destination, byte* source, int size)
234        {
235            // XXX: Further optomisation
236            // check the memory bus frame
237            // use BYTE / WORD / DWORD as required         
238           
239            int wsize = size / sizeof(uint);
240            size -= wsize * sizeof(uint);
241            uint* d = (uint*)destination;
242            uint* s = (uint*)source;
243
244            while (wsize-- > 0)
245                *d++ ^= *s++;
246
247            if (size > 0)
248            {
249                byte* db = (byte*)d,
250                      ds = (byte*)s;
251                while (size-- > 0)
252                    *db++ ^= *ds++;
253            }
254        }
255
256        /// <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>
304        /// The pool of data which we currently maintain.
305        /// </summary>
306        private byte[] pool;
307
308        /// <summary>
309        /// The next position where entropy will be added to the pool.
310        /// </summary>
311        private int poolPosition;
312
313        /// <summary>
314        /// The lock guarding the pool array and the current entropy addition index.
315        /// </summary>
316        private object poolLock = new object();
317
318        /// <summary>
319        /// The thread object.
320        /// </summary>
321        private Thread Thread;
322
323        /// <summary>
324        /// The list of entropy sources registered with the Poller.
325        /// </summary>
326        private List<IEntropySource> EntropySources = new List<IEntropySource>();
327    }
328}
Note: See TracBrowser for help on using the repository browser.