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

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

it should be possible now to use more opencl devices simultaneously (can't test it, because I only have one).

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