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

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

keysearcher opencl stuff

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