source: trunk/CrypPlugins/KeySearcher/KeySearcher.cs @ 2143

Last change on this file since 2143 was 2143, checked in by Sven Rech, 11 years ago

recomitted the keysearcher OpenCL optimization changes (hopefully this will work now...)

File size: 45.8 KB
Line 
1/*                             
2   Copyright 2009 Sven Rech, Nils Kopal, Uni Duisburg-Essen
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Diagnostics;
19using System.IO;
20using System.Linq;
21using System.Text;
22using Cryptool.P2P;
23using Cryptool.P2P.Internal;
24using Cryptool.PluginBase.Analysis;
25using Cryptool.PluginBase;
26using System.Windows.Controls;
27using System.ComponentModel;
28using Cryptool.PluginBase.Control;
29using System.Collections;
30using System.Collections.Generic;
31using System.Threading;
32using System.Windows.Threading;
33using Cryptool.PluginBase.IO;
34using System.Numerics;
35using KeySearcher.Helper;
36using KeySearcher.P2P;
37using KeySearcherPresentation;
38using KeySearcherPresentation.Controls;
39using OpenCLNet;
40
41namespace KeySearcher
42{   
43    [Author("Sven Rech, Nils Kopal, Raoul Falk, Dennis Nolte", "rech@cryptool.org", "Uni Duisburg-Essen", "http://www.uni-due.de")]
44    [PluginInfo(false, "KeySearcher", "Bruteforces a decryption algorithm.", "KeySearcher/DetailedDescription/Description.xaml", "KeySearcher/Images/icon.png")]
45    public class KeySearcher : IAnalysisMisc
46    {
47        /// <summary>
48        /// used for creating the TopList
49        /// </summary>
50        private Queue valuequeue;
51        private double value_threshold;
52        /// <summary>
53        /// the thread with the most keys left
54        /// </summary>
55        private int maxThread;
56        private readonly Mutex maxThreadMutex = new Mutex();
57        private ArrayList threadsStopEvents;
58
59        public bool IsKeySearcherRunning;
60        private KeyQualityHelper keyQualityHelper;
61        private readonly P2PQuickWatchPresentation p2PQuickWatchPresentation;
62        private readonly LocalQuickWatchPresentation localQuickWatchPresentation;
63
64        private OpenCLManager oclManager = null;
65
66        private readonly Stopwatch localBruteForceStopwatch;
67
68        private KeyPattern.KeyPattern pattern;
69        public KeyPattern.KeyPattern Pattern
70        {
71            get
72            {
73                return pattern;
74            }
75            set
76            {
77                pattern = value;
78                if ((settings.Key == null) || ((settings.Key != null) && !pattern.testWildcardKey(settings.Key)))
79                    settings.Key = pattern.giveInputPattern();
80            }
81        }
82
83        internal bool stop;
84
85        #region IControlEncryption + IControlCost + InputFields
86
87        #region IControlEncryption Members
88
89        private IControlEncryption controlMaster;
90        [PropertyInfo(Direction.ControlMaster, "Control Master", "Used for bruteforcing", "", DisplayLevel.Beginner)]
91        public IControlEncryption ControlMaster
92        {
93            get { return controlMaster; }
94            set
95            {
96                if (controlMaster != null)
97                {
98                    controlMaster.keyPatternChanged -= keyPatternChanged;
99                }
100                if (value != null)
101                {
102                    Pattern = new KeyPattern.KeyPattern(value.getKeyPattern());
103                    value.keyPatternChanged += keyPatternChanged;
104                    controlMaster = value;
105                    OnPropertyChanged("ControlMaster");
106
107                }
108                else
109                    controlMaster = null;
110            }
111        }
112
113        #endregion
114
115        #region IControlCost Members
116
117        private IControlCost costMaster;
118        [PropertyInfo(Direction.ControlMaster, "Cost Master", "Used for cost calculation", "", DisplayLevel.Beginner)]
119        public IControlCost CostMaster
120        {
121            get { return costMaster; }
122            set
123            {
124                costMaster = value;
125                keyQualityHelper = new KeyQualityHelper(costMaster);
126            }
127        }
128
129        #endregion
130
131        /* BEGIN: following lines are from Arnie - 2010.01.12 */
132        CryptoolStream csEncryptedData;
133        [PropertyInfo(Direction.InputData, "CS Encrypted Data", "Encrypted data out of an Encryption PlugIn", "", false, false, DisplayLevel.Beginner, QuickWatchFormat.Hex, "")]
134        public virtual CryptoolStream CSEncryptedData
135        {
136            get { return this.csEncryptedData; }
137            set
138            {
139                if (value != this.csEncryptedData)
140                {
141                    this.csEncryptedData = value;
142                    this.encryptedData = GetByteFromCryptoolStream(value);
143                    OnPropertyChanged("CSEncryptedData");
144                }
145            }
146        }
147
148        byte[] encryptedData;
149        [PropertyInfo(Direction.InputData,"Encrypted Data","Encrypted data out of an Encryption PlugIn","",false,false,DisplayLevel.Beginner,QuickWatchFormat.Hex,"")]
150        public virtual byte[] EncryptedData
151        {
152            get { return this.encryptedData; }
153            set
154            {
155                if (value != this.encryptedData)
156                {
157                    this.encryptedData = value;
158                    OnPropertyChanged("EncryptedData");
159                }
160            }
161        }
162
163        /// <summary>
164        /// When the Input-Slot changed, set this variable to true, so the new Stream will be transformed to byte[]
165        /// </summary>
166        private byte[] GetByteFromCryptoolStream(CryptoolStream cryptoolStream)
167        {
168            byte[] encryptedByteData = null;
169
170            if (cryptoolStream != null)
171            {
172                CryptoolStream cs = new CryptoolStream();
173                cs.OpenRead(cryptoolStream.FileName);
174                encryptedByteData = new byte[cs.Length];
175                if(cs.Length > Int32.MaxValue)
176                    throw(new Exception("CryptoolStream length is longer than the Int32.MaxValue"));
177                cs.Read(encryptedByteData, 0, (int)cs.Length);
178            }
179            return encryptedByteData;
180        }
181
182        byte[] initVector;
183        [PropertyInfo(Direction.InputData, "Initialization Vector", "Initialization vector with which the data were encrypted", "", DisplayLevel.Beginner)]
184        public virtual byte[] InitVector
185        {
186            get { return this.initVector; }
187            set
188            {
189                if (value != this.initVector)
190                {
191                    this.initVector = value;
192                    OnPropertyChanged("InitVector");
193                }
194            }
195        }
196        /* END: Lines above are from Arnie - 2010.01.12 */
197
198        private ValueKey top1ValueKey;
199        public virtual ValueKey Top1
200        {
201            set { top1ValueKey = value; OnPropertyChanged("Top1Message"); OnPropertyChanged("Top1Key"); }
202        }
203
204        [PropertyInfo(Direction.OutputData, "Top1 Message", "The best message found", "", DisplayLevel.Beginner)]
205        public virtual byte[] Top1Message
206        {
207            get { return top1ValueKey.decryption; }
208        }
209        [PropertyInfo(Direction.OutputData, "Top1 Key", "The best key found", "", DisplayLevel.Beginner)]
210        public virtual byte[] Top1Key
211        {
212            get
213            {
214                if (top1ValueKey.key != null)
215                {
216                    return top1ValueKey.keya;
217                }
218                else
219                    return null;
220            }
221        }
222
223        #endregion
224
225        #region IPlugin Members
226
227        public event StatusChangedEventHandler OnPluginStatusChanged;
228
229        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
230
231        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
232
233        private KeySearcherSettings settings;
234        private AutoResetEvent connectResetEvent;
235
236        public KeySearcher()
237        {
238            IsKeySearcherRunning = false;
239            if (OpenCL.NumberOfPlatforms > 0)
240            {
241                oclManager = new OpenCLManager();
242                oclManager.AttemptUseBinaries = false;
243                oclManager.AttemptUseSource = true;
244                oclManager.RequireImageSupport = false;
245                var directoryName = Path.Combine(DirectoryHelper.DirectoryLocalTemp, "KeySearcher");
246                oclManager.BinaryPath = Path.Combine(directoryName, "openclbin");
247                oclManager.BuildOptions = "";
248                oclManager.CreateDefaultContext(0, DeviceType.ALL);
249            }
250
251            settings = new KeySearcherSettings(this, oclManager);
252            QuickWatchPresentation = new QuickWatch();
253            localQuickWatchPresentation = ((QuickWatch) QuickWatchPresentation).LocalQuickWatchPresentation;
254            p2PQuickWatchPresentation = ((QuickWatch)QuickWatchPresentation).P2PQuickWatchPresentation;
255            p2PQuickWatchPresentation.UpdateSettings(this, settings);
256
257            settings.PropertyChanged += SettingsPropertyChanged;
258
259            localBruteForceStopwatch = new Stopwatch();
260        }
261
262        void SettingsPropertyChanged(object sender, PropertyChangedEventArgs e)
263        {
264            p2PQuickWatchPresentation.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
265                                                             new Action(UpdateIsP2PEnabledSetting));
266        }
267
268        void UpdateIsP2PEnabledSetting()
269        {
270            ((QuickWatch)QuickWatchPresentation).IsP2PEnabled = settings.UsePeerToPeer;
271            p2PQuickWatchPresentation.UpdateSettings(this, settings);
272        }
273
274        public ISettings Settings
275        {
276            get { return settings; }
277        }
278
279        public UserControl Presentation
280        {
281            get { return QuickWatchPresentation; }
282        }
283
284        public UserControl QuickWatchPresentation
285        {
286            get;
287            private set;
288        }
289
290        public void PreExecution()
291        {
292        }
293
294        // because Encryption PlugIns were changed radical, the new StartPoint is here - Arnie 2010.01.12
295        public virtual void Execute()
296        {
297            IsKeySearcherRunning = true;
298
299            //either byte[] CStream input or CryptoolStream Object input
300            if (encryptedData != null || csEncryptedData != null) //to prevent execution on initialization
301            {
302                if (ControlMaster != null)
303                    process(ControlMaster);
304                else
305                {
306                    GuiLogMessage("You have to connect the KeySearcher with the Decryption Control!", NotificationLevel.Warning);
307                }
308            }
309        }
310
311        public void PostExecution()
312        {
313        }
314
315        public void Pause()
316        {
317        }
318
319        public void Stop()
320        {
321            IsKeySearcherRunning = false;
322            stop = true;
323        }
324
325        public void Initialize()
326        {
327            settings.Initialize();
328        }
329
330        public void Dispose()
331        {
332        }
333
334        #endregion
335
336        #region INotifyPropertyChanged Members
337
338        public event PropertyChangedEventHandler PropertyChanged;
339
340        public void OnPropertyChanged(string name)
341        {
342            if (PropertyChanged != null)
343            {
344                PropertyChanged(this, new PropertyChangedEventArgs(name));
345            }
346        }
347
348        #endregion
349
350        #region whole KeySearcher functionality
351
352        private class ThreadStackElement
353        {
354            public AutoResetEvent ev;
355            public int threadid;
356        }
357
358        #region code for the worker threads
359
360        private void KeySearcherJob(object param)
361        {
362            AutoResetEvent stopEvent = new AutoResetEvent(false);
363            threadsStopEvents.Add(stopEvent);
364
365            object[] parameters = (object[])param;
366            KeyPattern.KeyPattern[] patterns = (KeyPattern.KeyPattern[])parameters[0];
367            int threadid = (int)parameters[1];
368            BigInteger[] doneKeysArray = (BigInteger[])parameters[2];
369            BigInteger[] keycounterArray = (BigInteger[])parameters[3];
370            BigInteger[] keysLeft = (BigInteger[])parameters[4];
371            IControlEncryption sender = (IControlEncryption)parameters[5];
372            int bytesToUse = (int)parameters[6];
373            Stack threadStack = (Stack)parameters[7];
374            bool useOpenCL = (bool)parameters[8];
375
376            KeySearcherOpenCLCode keySearcherOpenCLCode = null;
377            KeySearcherOpenCLSubbatchOptimizer keySearcherOpenCLSubbatchOptimizer = null;
378            if (useOpenCL)
379            {
380                keySearcherOpenCLCode = new KeySearcherOpenCLCode(this, encryptedData, sender, CostMaster, 256 * 256 * 256 * 16);
381                keySearcherOpenCLSubbatchOptimizer = new KeySearcherOpenCLSubbatchOptimizer(oclManager.CQ[settings.OpenCLDevice].Device.MaxWorkItemSizes.Aggregate(1, (x, y) => (x * (int)y)) / 2);
382            }
383
384            try
385            {
386                while (patterns[threadid] != null)
387                {
388                    BigInteger size = patterns[threadid].size();
389                    keysLeft[threadid] = size;
390                   
391                    IKeyTranslator keyTranslator = ControlMaster.getKeyTranslator();
392                    keyTranslator.SetKeys(patterns[threadid]);
393
394                    bool finish = false;
395
396                    do
397                    {
398                        //if we are the thread with most keys left, we have to share them:
399                        keyTranslator = ShareKeys(patterns, threadid, keysLeft, keyTranslator, threadStack);
400
401                        if (!useOpenCL)         //CPU
402                        {
403                            finish = BruteforceCPU(keyTranslator, sender, bytesToUse);
404                        }
405                        else                    //OpenCL
406                        {
407                            try
408                            {
409                                finish = BruteforceOpenCL(keySearcherOpenCLCode, keySearcherOpenCLSubbatchOptimizer, keyTranslator, sender, bytesToUse, parameters);
410                            }
411                            catch (Exception)
412                            {
413                                useOpenCL = false;
414                                continue;
415                            }
416                        }
417                       
418                        int progress = keyTranslator.GetProgress();
419
420                        if (!useOpenCL)
421                        {
422                            doneKeysArray[threadid] += progress;
423                            keycounterArray[threadid] += progress;
424                            keysLeft[threadid] -= progress;
425                        }
426
427                    } while (!finish && !stop);
428
429                    if (stop)
430                        return;
431
432                    //Let's wait until another thread is willing to share with us:
433                    WaitForNewPattern(patterns, threadid, threadStack);
434                }
435            }
436            finally
437            {
438                sender.Dispose();
439                stopEvent.Set();
440            }
441        }
442
443        private unsafe bool BruteforceOpenCL(KeySearcherOpenCLCode keySearcherOpenCLCode, KeySearcherOpenCLSubbatchOptimizer keySearcherOpenCLSubbatchOptimizer, IKeyTranslator keyTranslator, IControlEncryption sender, int bytesToUse, object[] parameters)
444        {
445            int threadid = (int)parameters[1];
446            BigInteger[] doneKeysArray = (BigInteger[])parameters[2];
447            BigInteger[] keycounterArray = (BigInteger[])parameters[3];
448            BigInteger[] keysLeft = (BigInteger[])parameters[4];
449            try
450            {
451                Kernel bruteforceKernel = keySearcherOpenCLCode.GetBruteforceKernel(oclManager, keyTranslator);
452               
453                int deviceIndex = settings.OpenCLDevice;
454               
455                Mem userKey;
456                var key = keyTranslator.GetKey();
457                fixed (byte* ukp = key)
458                    userKey = oclManager.Context.CreateBuffer(MemFlags.USE_HOST_PTR, key.Length, new IntPtr((void*)ukp));
459
460                bruteforceKernel.SetArg(0, userKey);
461
462                int subbatches = keySearcherOpenCLSubbatchOptimizer.GetAmountOfSubbatches(keyTranslator);
463                GuiLogMessage(string.Format("Now using {0} subbatches", subbatches), NotificationLevel.Info);
464
465                int subbatchSize = keyTranslator.GetOpenCLBatchSize() / subbatches;
466                float[] costArray = new float[subbatchSize];
467                Mem costs = oclManager.Context.CreateBuffer(MemFlags.READ_WRITE, costArray.Length * 4);
468                bruteforceKernel.SetArg(1, costs);
469
470                IntPtr[] globalWorkSize = { (IntPtr)subbatchSize };
471
472                keySearcherOpenCLSubbatchOptimizer.BeginMeasurement();
473
474                for (int i = 0; i < subbatches; i++)
475                {
476                    bruteforceKernel.SetArg(2, i * subbatchSize);
477                    oclManager.CQ[deviceIndex].EnqueueNDRangeKernel(bruteforceKernel, 1, null, globalWorkSize, null);
478                    oclManager.CQ[deviceIndex].EnqueueBarrier();
479
480                    Event e;
481                    fixed (float* costa = costArray)
482                        oclManager.CQ[deviceIndex].EnqueueReadBuffer(costs, true, 0, costArray.Length * 4, new IntPtr((void*)costa), 0, null, out e);
483
484                    e.Wait();
485
486                    checkOpenCLResults(keyTranslator, costArray, sender, bytesToUse, i * subbatchSize);
487
488                    doneKeysArray[threadid] += subbatchSize;
489                    keycounterArray[threadid] += subbatchSize;
490                    keysLeft[threadid] -= subbatchSize;
491                }
492
493                keySearcherOpenCLSubbatchOptimizer.EndMeasurement();
494
495                costs.Dispose();
496            }
497            catch (Exception ex)
498            {
499                GuiLogMessage(ex.Message, NotificationLevel.Error);
500                GuiLogMessage("Bruteforcing with OpenCL failed! Using CPU instead.", NotificationLevel.Error);
501                throw new Exception("Bruteforcing with OpenCL failed!");
502            }
503
504            return !keyTranslator.NextOpenCLBatch();
505        }
506
507        private void checkOpenCLResults(IKeyTranslator keyTranslator, float[] costArray, IControlEncryption sender, int bytesToUse, int add)
508        {
509            var op = this.costMaster.getRelationOperator();
510            for (int i = 0; i < costArray.Length; i++)
511            {
512                float cost = costArray[i];
513                if (((op == RelationOperator.LargerThen) && (cost > value_threshold))
514                    || (op == RelationOperator.LessThen) && (cost < value_threshold))
515                {
516                    ValueKey valueKey = new ValueKey { value = cost, key = keyTranslator.GetKeyRepresentation(i + add) };
517                    valueKey.keya = keyTranslator.GetKeyFromRepresentation(valueKey.key);
518                    valueKey.decryption = sender.Decrypt(this.encryptedData, valueKey.keya, InitVector, bytesToUse);
519                    valuequeue.Enqueue(valueKey);
520                }
521            }
522        }
523
524        private bool BruteforceCPU(IKeyTranslator keyTranslator, IControlEncryption sender, int bytesToUse)
525        {
526            bool finish = false;
527            for (int count = 0; count < 256 * 256; count++)
528            {
529                byte[] keya = keyTranslator.GetKey();
530
531                if (!decryptAndCalculate(sender, bytesToUse, keya, keyTranslator))
532                    throw new Exception("Bruteforcing not possible!");
533
534                finish = !keyTranslator.NextKey();
535                if (finish)
536                    break;
537            }
538            return finish;
539        }
540
541        private IKeyTranslator ShareKeys(KeyPattern.KeyPattern[] patterns, int threadid, BigInteger[] keysLeft, IKeyTranslator keyTranslator, Stack threadStack)
542        {
543            BigInteger size;
544            if (maxThread == threadid && threadStack.Count != 0)
545            {
546                try
547                {
548                    maxThreadMutex.WaitOne();
549                    if (maxThread == threadid && threadStack.Count != 0)
550                    {
551                        KeyPattern.KeyPattern[] split = patterns[threadid].split();
552                        if (split != null)
553                        {
554                            patterns[threadid] = split[0];
555                            keyTranslator = ControlMaster.getKeyTranslator();
556                            keyTranslator.SetKeys(patterns[threadid]);
557
558                            ThreadStackElement elem = (ThreadStackElement)threadStack.Pop();
559                            patterns[elem.threadid] = split[1];
560                            elem.ev.Set();    //wake the other thread up                                   
561                            size = patterns[threadid].size();
562                            keysLeft[threadid] = size;
563                        }
564                        maxThread = -1;
565                    }
566                }
567                finally
568                {
569                    maxThreadMutex.ReleaseMutex();
570                }
571            }
572            return keyTranslator;
573        }
574
575        private void WaitForNewPattern(KeyPattern.KeyPattern[] patterns, int threadid, Stack threadStack)
576        {
577            ThreadStackElement el = new ThreadStackElement();
578            el.ev = new AutoResetEvent(false);
579            el.threadid = threadid;
580            patterns[threadid] = null;
581            threadStack.Push(el);
582            GuiLogMessage("Thread waiting for new keys.", NotificationLevel.Debug);
583            el.ev.WaitOne();
584            if (!stop)
585            {
586                GuiLogMessage("Thread waking up with new keys.", NotificationLevel.Debug);
587            }
588        }
589
590        #region bruteforce methods
591
592        private bool decryptAndCalculate(IControlEncryption sender, int bytesToUse, byte[] keya, IKeyTranslator keyTranslator)
593        {
594            ValueKey valueKey;
595
596            try
597            {
598                if (this.encryptedData != null && this.encryptedData.Length > 0)
599                {
600                    valueKey.decryption = sender.Decrypt(this.encryptedData, keya, InitVector, bytesToUse);
601                }
602                else
603                {
604                    GuiLogMessage("Can't bruteforce empty input!", NotificationLevel.Error);
605                    return false;
606                }
607            }
608            catch (Exception ex)
609            {
610                GuiLogMessage("Decryption is not possible: " + ex.Message, NotificationLevel.Error);
611                GuiLogMessage("Stack Trace: " + ex.StackTrace, NotificationLevel.Error);
612                return false;
613            }
614
615            try
616            {
617                valueKey.value = CostMaster.calculateCost(valueKey.decryption);
618            }
619            catch (Exception ex)
620            {
621                GuiLogMessage("Cost calculation is not possible: " + ex.Message, NotificationLevel.Error);
622                return false;
623            }
624
625            if (this.costMaster.getRelationOperator() == RelationOperator.LargerThen)
626            {
627                if (valueKey.value > value_threshold)
628                {
629                    valueKey.key = keyTranslator.GetKeyRepresentation();
630                    valueKey.keya = (byte[])keya.Clone();
631                    valuequeue.Enqueue(valueKey);                   
632                }
633            }
634            else
635            {
636                if (valueKey.value < value_threshold)
637                {
638                    valueKey.key = keyTranslator.GetKeyRepresentation();
639                    valueKey.keya = (byte[])keya.Clone();                 
640                    valuequeue.Enqueue(valueKey);
641                }
642            }
643            return true;
644        }
645
646        #endregion
647
648        #endregion
649
650        public void process(IControlEncryption sender)
651        {
652            if (sender == null || costMaster == null)
653                return;
654            if (!Pattern.testWildcardKey(settings.Key))
655            {
656                GuiLogMessage("Wrong key pattern!", NotificationLevel.Error);
657                return;
658            }
659            Pattern.WildcardKey = settings.Key;
660            this.sender = sender;
661
662            bruteforcePattern(Pattern);
663        }
664
665        internal LinkedList<ValueKey> costList = new LinkedList<ValueKey>();
666        private int bytesToUse;
667        private IControlEncryption sender;
668        private DateTime beginBruteforcing;
669        private DistributedBruteForceManager distributedBruteForceManager;
670
671        // main entry point to the KeySearcher
672        private LinkedList<ValueKey> bruteforcePattern(KeyPattern.KeyPattern pattern)
673        {
674            beginBruteforcing = DateTime.Now;
675            GuiLogMessage("Start bruteforcing pattern '" + pattern.getKey() + "'", NotificationLevel.Debug);
676                       
677            int maxInList = 10;
678            costList = new LinkedList<ValueKey>();
679            fillListWithDummies(maxInList, costList);
680            valuequeue = Queue.Synchronized(new Queue());
681
682            stop = false;
683            if (!pattern.testWildcardKey(settings.Key))
684            {
685                GuiLogMessage("Wrong key pattern!", NotificationLevel.Error);
686                return null;
687            }
688
689            // bytesToUse = 0;
690
691            try
692            {
693                bytesToUse = CostMaster.getBytesToUse();
694            }
695            catch (Exception ex)
696            {
697                GuiLogMessage("Bytes used not valid: " + ex.Message, NotificationLevel.Error);
698                return null;
699            }
700
701            if (settings.UsePeerToPeer)
702            {
703                BruteForceWithPeerToPeerSystem();
704                return null;
705            }
706
707            return BruteForceWithLocalSystem(pattern);
708        }
709
710        private void BruteForceWithPeerToPeerSystem()
711        {
712            GuiLogMessage("Launching p2p based bruteforce logic...", NotificationLevel.Info);
713
714            try
715            {
716                distributedBruteForceManager = new DistributedBruteForceManager(this, pattern, settings,
717                                                                                keyQualityHelper,
718                                                                                p2PQuickWatchPresentation);
719                distributedBruteForceManager.Execute();
720            }
721            catch (NotConnectedException)
722            {
723                GuiLogMessage("P2P not connected.", NotificationLevel.Error);
724            }
725        }
726
727        internal LinkedList<ValueKey> BruteForceWithLocalSystem(KeyPattern.KeyPattern pattern, bool redirectResultsToStatisticsGenerator = false)
728        {
729            if (!redirectResultsToStatisticsGenerator)
730            {
731                localQuickWatchPresentation.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(SetStartDate));
732                localBruteForceStopwatch.Start();
733            }
734
735            BigInteger size = pattern.size();
736            KeyPattern.KeyPattern[] patterns = splitPatternForThreads(pattern);
737            if (patterns == null || patterns.Length == 0)
738            {
739                GuiLogMessage("No ressources to BruteForce available. Check the KeySearcher settings!", NotificationLevel.Error);
740                throw new Exception("No ressources to BruteForce available. Check the KeySearcher settings!");
741            }
742
743            BigInteger[] doneKeysA = new BigInteger[patterns.Length];
744            BigInteger[] keycounters = new BigInteger[patterns.Length];
745            BigInteger[] keysleft = new BigInteger[patterns.Length];
746            Stack threadStack = Stack.Synchronized(new Stack());
747            threadsStopEvents = ArrayList.Synchronized(new ArrayList());
748            StartThreads(sender, bytesToUse, patterns, doneKeysA, keycounters, keysleft, threadStack);
749
750            DateTime lastTime = DateTime.Now;
751
752            //update message:
753            while (!stop)
754            {
755                Thread.Sleep(2000);
756
757                updateToplist();
758
759                #region calculate global counters from local counters
760                BigInteger keycounter = 0;
761                BigInteger doneKeys = 0;
762                foreach (BigInteger dk in doneKeysA)
763                    doneKeys += dk;
764                foreach (BigInteger kc in keycounters)
765                    keycounter += kc;
766                #endregion
767
768                if (keycounter > size)
769                    GuiLogMessage("There must be an error, because we bruteforced too much keys...", NotificationLevel.Error);
770
771                #region determination of the thread with most keys
772                if (size - keycounter > 1000)
773                {
774                    try
775                    {
776                        maxThreadMutex.WaitOne();
777                        BigInteger max = 0;
778                        int id = -1;
779                        for (int i = 0; i < patterns.Length; i++)
780                            if (keysleft[i] != null && keysleft[i] > max)
781                            {
782                                max = keysleft[i];
783                                id = i;
784                            }
785                        maxThread = id;
786                    }
787                    finally
788                    {
789                        maxThreadMutex.ReleaseMutex();
790                    }
791                }
792                #endregion
793
794                long keysPerSecond = (long)((long)doneKeys/(DateTime.Now - lastTime).TotalSeconds);
795                lastTime = DateTime.Now;
796                if (redirectResultsToStatisticsGenerator)
797                {
798                    distributedBruteForceManager.StatisticsGenerator.ShowProgress(costList, size, keycounter, keysPerSecond);
799                }
800                else
801                {
802                    showProgress(costList, size, keycounter, keysPerSecond);                   
803                }
804               
805
806                #region set doneKeys to 0
807                doneKeys = 0;
808                for (int i = 0; i < doneKeysA.Length; i++)
809                    doneKeysA[i] = 0;
810                #endregion
811
812                if (keycounter >= size)
813                    break;
814            }//end while
815
816            showProgress(costList, 1, 1, 1);
817
818            //wake up all sleeping threads, so they can stop:
819            while (threadStack.Count != 0)
820                ((ThreadStackElement)threadStack.Pop()).ev.Set();
821
822            //wait until all threads finished:
823            foreach (AutoResetEvent stopEvent in threadsStopEvents)
824            {
825                stopEvent.WaitOne();
826            }
827
828            if (!stop && !redirectResultsToStatisticsGenerator)
829                ProgressChanged(1, 1);
830
831            /* BEGIN: For evaluation issues - added by Arnold 2010.03.17 */
832            TimeSpan bruteforcingTime = DateTime.Now.Subtract(beginBruteforcing);
833            StringBuilder sbBFTime = new StringBuilder();
834            if (bruteforcingTime.Days > 0)
835                sbBFTime.Append(bruteforcingTime.Days.ToString() + " days ");
836            if (bruteforcingTime.Hours > 0)
837            {
838                if (bruteforcingTime.Hours <= 9)
839                    sbBFTime.Append("0");
840                sbBFTime.Append(bruteforcingTime.Hours.ToString() + ":");
841            }
842            if (bruteforcingTime.Minutes <= 9)
843                sbBFTime.Append("0");
844            sbBFTime.Append(bruteforcingTime.Minutes.ToString() + ":");
845            if (bruteforcingTime.Seconds <= 9)
846                sbBFTime.Append("0");
847            sbBFTime.Append(bruteforcingTime.Seconds.ToString() + "-");
848            if (bruteforcingTime.Milliseconds <= 9)
849                sbBFTime.Append("00");
850            if (bruteforcingTime.Milliseconds <= 99)
851                sbBFTime.Append("0");
852            sbBFTime.Append(bruteforcingTime.Milliseconds.ToString());
853
854            GuiLogMessage("Ended bruteforcing pattern '" + pattern.getKey() + "'. Bruteforcing TimeSpan: " + sbBFTime.ToString(), NotificationLevel.Debug);
855            /* END: For evaluation issues - added by Arnold 2010.03.17 */
856
857            return costList;
858        }
859
860
861
862        private void SetStartDate()
863        {
864            localQuickWatchPresentation.startTime.Content = DateTime.Now.ToString("g", Thread.CurrentThread.CurrentCulture); ;
865        }
866
867        internal void showProgress(LinkedList<ValueKey> costList, BigInteger size, BigInteger keycounter, long keysPerSecond)
868        {
869            System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
870
871            LinkedListNode<ValueKey> linkedListNode;
872            ProgressChanged((double)keycounter / (double) size, 1.0);
873
874            if (localQuickWatchPresentation.IsVisible && keysPerSecond != 0 && !stop)
875            {
876                double time = (Math.Pow(10, BigInteger.Log((size - keycounter), 10) - Math.Log10(keysPerSecond)));
877                TimeSpan timeleft = new TimeSpan(-1);
878
879                try
880                {
881                    if (time / (24 * 60 * 60) <= int.MaxValue)
882                    {
883                        int days = (int)(time / (24 * 60 * 60));
884                        time = time - (days * 24 * 60 * 60);
885                        int hours = (int)(time / (60 * 60));
886                        time = time - (hours * 60 * 60);
887                        int minutes = (int)(time / 60);
888                        time = time - (minutes * 60);
889                        int seconds = (int)time;
890
891                        timeleft = new TimeSpan(days, hours, minutes, (int)seconds, 0);
892                    }
893                }
894                catch
895                {
896                    //can not calculate time span
897                }
898
899                localQuickWatchPresentation.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
900                {
901                    localQuickWatchPresentation.elapsedTime.Content = localBruteForceStopwatch.Elapsed;
902                    localQuickWatchPresentation.keysPerSecond.Content = String.Format("{0:N}", keysPerSecond);
903                    if (timeleft != new TimeSpan(-1))
904                    {
905                        localQuickWatchPresentation.timeLeft.Content = "" + timeleft;
906                        try
907                        {
908                            localQuickWatchPresentation.endTime.Content = "" + DateTime.Now.Add(timeleft);
909                        }
910                        catch
911                        {
912                            localQuickWatchPresentation.endTime.Content = "in a galaxy far, far away...";
913                        }
914                    }
915                    else
916                    {
917                        localQuickWatchPresentation.timeLeft.Content = "incalculable :-)";
918                        localQuickWatchPresentation.endTime.Content = "in a galaxy far, far away...";
919                    }
920
921                    localQuickWatchPresentation.entries.Clear();
922                    linkedListNode = costList.First;
923                   
924                    int i = 0;
925                    while (linkedListNode != null)
926                    {
927                        i++;
928
929                        ResultEntry entry = new ResultEntry();
930                        entry.Ranking = "" + i;
931                        entry.Value = "" + Math.Round(linkedListNode.Value.value,3);
932                        entry.Key = linkedListNode.Value.key;
933                        entry.Text = enc.GetString(linkedListNode.Value.decryption);
934
935                        localQuickWatchPresentation.entries.Add(entry);
936                        linkedListNode = linkedListNode.Next;
937                    }
938                }
939                , null);
940            }//end if
941
942
943            else if (!stop && localQuickWatchPresentation.IsVisible)
944            {
945
946                localQuickWatchPresentation.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
947                {
948                    localQuickWatchPresentation.entries.Clear();
949                    linkedListNode = costList.First;                   
950                    int i = 0;
951
952                    while (linkedListNode != null)
953                    {
954                        i++;
955
956                        ResultEntry entry = new ResultEntry();
957                        entry.Ranking = "" + i;
958                        entry.Value = "" + Math.Round(linkedListNode.Value.value, 3);
959                        entry.Key = linkedListNode.Value.key;
960                        entry.Text = enc.GetString(linkedListNode.Value.decryption);
961
962                        localQuickWatchPresentation.entries.Add(entry);
963                        linkedListNode = linkedListNode.Next;
964                    }
965                }
966                , null);
967            }
968        }
969
970        #region For TopList
971
972        private void fillListWithDummies(int maxInList, LinkedList<ValueKey> costList)
973        {
974            ValueKey valueKey = new ValueKey();
975            if (this.costMaster.getRelationOperator() == RelationOperator.LessThen)
976                valueKey.value = double.MaxValue;
977            else
978                valueKey.value = double.MinValue;
979            valueKey.key = "dummykey";
980            valueKey.decryption = new byte[0];
981            value_threshold = valueKey.value;
982            LinkedListNode<ValueKey> node = costList.AddFirst(valueKey);
983            for (int i = 1; i < maxInList; i++)
984            {
985                node = costList.AddAfter(node, valueKey);
986            }
987        }
988
989        internal void IntegrateNewResults(LinkedList<ValueKey> updatedCostList)
990        {
991            foreach (var valueKey in updatedCostList)
992            {
993                if (keyQualityHelper.IsBetter(valueKey.value, value_threshold))
994                {
995                    valuequeue.Enqueue(valueKey);
996                }
997            }
998
999            updateToplist();
1000        }
1001
1002        internal void updateToplist()
1003        {
1004            LinkedListNode<ValueKey> node;
1005            while (valuequeue.Count != 0)
1006            {
1007                ValueKey vk = (ValueKey)valuequeue.Dequeue();
1008
1009                //if (costList.Contains(vk)) continue;
1010                var result = costList.Where(valueKey => valueKey.key == vk.key);
1011                if (result.Count() > 0)
1012                {
1013                    continue;
1014                }
1015
1016                if (this.costMaster.getRelationOperator() == RelationOperator.LargerThen)
1017                {
1018                    if (vk.value > costList.Last().value)
1019                    {
1020                        node = costList.First;
1021                        while (node != null)
1022                        {
1023                            if (vk.value > node.Value.value)
1024                            {
1025                                if (node == costList.First)
1026                                    Top1 = vk;
1027                                costList.AddBefore(node, vk);
1028                                costList.RemoveLast();
1029                                value_threshold = costList.Last.Value.value;
1030                                break;
1031                            }
1032                            node = node.Next;
1033                        }//end while
1034                    }//end if
1035                }
1036                else
1037                {
1038                    if (vk.value < costList.Last().value)
1039                    {
1040                        node = costList.First;
1041                        while (node != null)
1042                        {
1043                            if (vk.value < node.Value.value)
1044                            {
1045                                if (node == costList.First)
1046                                    Top1 = vk;
1047                                costList.AddBefore(node, vk);
1048                                costList.RemoveLast();
1049                                value_threshold = costList.Last.Value.value;
1050                                break;
1051                            }
1052                            node = node.Next;
1053                        }//end while
1054                    }//end if
1055                }
1056            }
1057        }
1058
1059        #endregion
1060
1061        private void StartThreads(IControlEncryption sender, int bytesToUse, KeyPattern.KeyPattern[] patterns, BigInteger[] doneKeysA, BigInteger[] keycounters, BigInteger[] keysleft, Stack threadStack)
1062        {
1063            for (int i = 0; i < patterns.Length; i++)
1064            {
1065                WaitCallback worker = new WaitCallback(KeySearcherJob);
1066                doneKeysA[i] = new BigInteger();
1067                keycounters[i] = new BigInteger();
1068                bool useOpenCL = false;
1069
1070                if (settings.UseOpenCL && (i == patterns.Length - 1))     //Last thread is the OpenCL thread
1071                    useOpenCL = true;
1072
1073                ThreadPool.QueueUserWorkItem(worker, new object[] { patterns, i, doneKeysA, keycounters, keysleft, sender, bytesToUse, threadStack, useOpenCL });
1074            }
1075        }
1076
1077        private KeyPattern.KeyPattern[] splitPatternForThreads(KeyPattern.KeyPattern pattern)
1078        {
1079            int threads = settings.CoresUsed;
1080            if (settings.UseOpenCL)
1081                threads++;
1082
1083            if (threads < 1)
1084                return null;
1085
1086            KeyPattern.KeyPattern[] patterns = new KeyPattern.KeyPattern[threads];
1087            if (threads > 1)
1088            {
1089                KeyPattern.KeyPattern[] patterns2 = pattern.split();
1090                if (patterns2 == null)
1091                {
1092                    patterns2 = new KeyPattern.KeyPattern[1];
1093                    patterns2[0] = pattern;
1094                    return patterns2;
1095                }
1096                patterns[0] = patterns2[0];
1097                patterns[1] = patterns2[1];
1098                int p = 1;
1099                threads -= 2;
1100
1101                while (threads > 0)
1102                {
1103                    int maxPattern = -1;
1104                    BigInteger max = 0;
1105                    for (int i = 0; i <= p; i++)
1106                        if (patterns[i].size() > max)
1107                        {
1108                            max = patterns[i].size();
1109                            maxPattern = i;
1110                        }
1111                    KeyPattern.KeyPattern[] patterns3 = patterns[maxPattern].split();
1112                    if (patterns3 == null)
1113                    {
1114                        patterns3 = new KeyPattern.KeyPattern[p+1];
1115                        for (int i = 0; i <= p; i++)
1116                            patterns3[i] = patterns[i];
1117                        return patterns3;
1118                    }
1119                    patterns[maxPattern] = patterns3[0];
1120                    patterns[++p] = patterns3[1];
1121                    threads--;
1122                }
1123            }
1124            else
1125                patterns[0] = pattern;
1126            return patterns;
1127        }
1128
1129        private void keyPatternChanged()
1130        {
1131            Pattern = new KeyPattern.KeyPattern(controlMaster.getKeyPattern());
1132        }
1133
1134        // added by Arnie - 2009.12.07
1135        public delegate void BruteforcingEnded(LinkedList<ValueKey> top10List);
1136        /// <summary>
1137        /// This event gets thrown after Bruteforcing had ended. This is no evidence, that bruteforcing was successful.
1138        /// But when the returned List is filled, we have (at least a part) of the possible best keys
1139        /// </summary>
1140        public event BruteforcingEnded OnBruteforcingEnded;
1141
1142        // added by Arnie -2009.12.02
1143        // for inheritance reasons
1144        public void BruteforcePattern(KeyPattern.KeyPattern pattern, byte[] encryptedData, byte[] initVector, IControlEncryption encryptControl, IControlCost costControl)
1145        {
1146            /* Begin: New stuff because of changing the IControl data flow - Arnie 2010.01.18 */
1147            this.encryptedData = encryptedData;
1148            this.initVector = initVector;
1149            /* End: New stuff because of changing the IControl data flow - Arnie 2010.01.18 */
1150
1151            this.sender = encryptControl;
1152            LinkedList<ValueKey> lstRet = bruteforcePattern(pattern);
1153            if(OnBruteforcingEnded != null)
1154                OnBruteforcingEnded(lstRet);
1155        }
1156
1157        #endregion
1158
1159        public void GuiLogMessage(string message, NotificationLevel loglevel)
1160        {
1161            if (OnGuiLogNotificationOccured != null)
1162                OnGuiLogNotificationOccured(this, new GuiLogEventArgs(message, this, loglevel));
1163        }
1164
1165        public void ProgressChanged(double value, double max)
1166        {
1167            if (OnPluginProgressChanged != null)
1168            {
1169                OnPluginProgressChanged(this, new PluginProgressEventArgs(value, max));
1170
1171            }
1172        }
1173
1174        /// <summary>
1175        /// used for delivering the results from the worker threads to the main thread:
1176        /// </summary>
1177        public struct ValueKey
1178        {
1179            public double value;
1180            public String key;
1181            public byte[] decryption;
1182            public byte[] keya;
1183        };
1184    }
1185
1186    /// <summary>
1187    /// Represents one entry in our result list
1188    /// </summary>
1189    public class ResultEntry
1190    {
1191        public string Ranking { get; set; }
1192        public string Value { get; set; }
1193        public string Key { get; set; }
1194        public string Text { get; set; }
1195
1196    }
1197}
Note: See TracBrowser for help on using the repository browser.