source: trunk/CrypPlugins/DES/DES.cs @ 772

Last change on this file since 772 was 772, checked in by kopal, 12 years ago

implemented KeySearching on DES

File size: 20.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.IO;
6using System.Security.Cryptography;
7using Cryptool.PluginBase;
8using System.ComponentModel;
9using Cryptool.PluginBase.Cryptography;
10using Cryptool.PluginBase.IO;
11using System.Windows.Controls;
12using Cryptool.PluginBase.Control;
13using System.Reflection;
14
15namespace Cryptool.Plugins.Cryptography.Encryption
16{
17    [PluginInfo(false, "DES", "Data Encryption Standard", "DES/DetailedDescription/Description.xaml", "DES/icon.png", "DES/Images/encrypt.png", "DES/Images/decrypt.png")]
18    [EncryptionType(EncryptionType.SymmetricBlock)]
19    public class DES : IEncryption
20    {
21        #region Private variables
22        private DESSettings settings;
23        private CryptoolStream inputStream;
24        private CryptoolStream outputStream;
25        private List<CryptoolStream> listCryptoolStreamsOut = new List<CryptoolStream>();
26        private byte[] inputKey;
27        private byte[] inputIV;
28        private CryptoStream p_crypto_stream;
29        private bool stop = false;
30        private IControlEncryption controlSlave;
31        #endregion
32
33        public DES()
34        {
35            this.settings = new DESSettings();
36            this.settings.OnPluginStatusChanged += settings_OnPluginStatusChanged;
37        }
38
39        void settings_OnPluginStatusChanged(IPlugin sender, StatusEventArgs args)
40        {
41            if(OnPluginStatusChanged != null)OnPluginStatusChanged(this, args);
42        }
43
44        public ISettings Settings
45        {
46            get { return this.settings; }
47            set { this.settings = (DESSettings)value; }
48        }
49
50        [PropertyInfo(Direction.InputData, "Input", "Data to be encrypted or decrypted", null, true, false, DisplayLevel.Beginner, QuickWatchFormat.Hex, null)]
51        public CryptoolStream InputStream
52        {
53            get 
54            {
55                if (inputStream != null)
56                {
57                    CryptoolStream cs = new CryptoolStream();
58                    cs.OpenRead(inputStream.FileName);
59                    listCryptoolStreamsOut.Add(cs);
60                    return cs;
61                }
62                else return null;
63            }
64            set 
65            { 
66              this.inputStream = value;
67              if (value != null) listCryptoolStreamsOut.Add(value);
68              OnPropertyChanged("InputStream");
69            }
70        }
71
72        [PropertyInfo(Direction.InputData, "Key", "Must be 8 bytes.", null, true, false, DisplayLevel.Beginner, QuickWatchFormat.Hex, null)]
73        public byte[] InputKey
74        {
75            get { return this.inputKey; }
76            set
77            {
78                this.inputKey = value;
79                OnPropertyChanged("InputKey");
80            }
81        }
82
83        [PropertyInfo(Direction.InputData, "IV", "IV to be used in chaining modes, must be the same as the Blocksize in bytes (8 bytes).", null, true, false, DisplayLevel.Beginner, QuickWatchFormat.Hex, null)]
84        public byte[] InputIV
85        {
86            get { return this.inputIV; }
87            set
88            {
89                this.inputIV = value;
90                OnPropertyChanged("InputIV");
91            }
92        }
93       
94        [PropertyInfo(Direction.OutputData, "Output stream", "Encrypted or decrypted output data", null, true, false, DisplayLevel.Beginner, QuickWatchFormat.Hex, null)]
95        public CryptoolStream OutputStream
96        {
97            get
98            {
99                if (this.outputStream != null)
100                {
101                    CryptoolStream cs = new CryptoolStream();
102                    listCryptoolStreamsOut.Add(cs);
103                    cs.OpenRead(this.outputStream.FileName);
104                    return cs;
105                }
106                return null;
107            }
108            set
109            {
110                outputStream = value;
111                if (value != null) listCryptoolStreamsOut.Add(value);
112                OnPropertyChanged("OutputStream");
113            }
114        }
115
116        private void ConfigureAlg(SymmetricAlgorithm alg)
117        {
118            //check for a valid key
119            if (this.inputKey == null)
120            {
121                //create a trivial key
122                inputKey = new byte[8];
123                // write a warning to the ouside word
124                GuiLogMessage("WARNING - No key provided. Using 0x000..00!", NotificationLevel.Warning);
125            }
126            alg.Key = this.inputKey;
127
128            //check for a valid IV
129            if (this.inputIV == null)
130            {
131                //create a trivial key
132                inputIV = new byte[alg.BlockSize / 8];
133               GuiLogMessage("WARNING - No IV provided. Using 0x000..00!", NotificationLevel.Warning);
134            }
135            alg.IV = this.inputIV;
136            switch (settings.Mode)
137            { //0="ECB"=default, 1="CBC", 2="CFB", 3="OFB"
138                case 1: alg.Mode = CipherMode.CBC; break;
139                case 2: alg.Mode = CipherMode.CFB; break;
140                case 3: alg.Mode = CipherMode.OFB; break;
141                default: alg.Mode = CipherMode.ECB; break;
142            }
143            switch (settings.Padding)
144            { //0="Zeros"=default, 1="None", 2="PKCS7"
145                case 1: alg.Padding = PaddingMode.None; break;
146                case 2: alg.Padding = PaddingMode.PKCS7; break;
147                case 3: alg.Padding = PaddingMode.ANSIX923; break;
148                case 4: alg.Padding = PaddingMode.ISO10126; break;
149                default: alg.Padding = PaddingMode.Zeros; break;
150            }
151        }
152
153        private void checkForInputStream()
154        {
155            if (settings.Action == 0 && (inputStream == null || (inputStream != null && inputStream.Length == 0)))
156            {
157                //create some input
158                String dummystring = "Dummy string - no input provided - \"Hello DES World\" - dummy string - no input provided!";
159                this.inputStream = new CryptoolStream();
160                this.inputStream.OpenRead(this.GetPluginInfoAttribute().Caption, Encoding.Default.GetBytes(dummystring.ToCharArray()));
161                // write a warning to the ouside word
162                GuiLogMessage("WARNING - No input provided. Using dummy data. (" + dummystring + ")", NotificationLevel.Warning);
163            }
164        }
165
166        public void Execute()
167        {
168            try
169            {
170                //copy inputStream for Slave
171                if (controlSlave is object && InputStream is object && InputIV is object)
172                {
173                    CryptoolStream cs = new CryptoolStream();
174                    cs.OpenRead(inputStream.FileName);
175                    ((DESControl)controlSlave).InputStream = cs;
176                }
177
178                process(settings.Action);
179
180                //Work with slave
181                if (controlSlave is object && InputStream is object && InputIV is object)
182                {
183                    ((DESControl)controlSlave).onStatusChanged();
184
185                }
186            }
187            finally
188            {
189                if (controlSlave is object && ((DESControl)controlSlave).InputStream is object)
190                    ((DESControl)controlSlave).InputStream.Close();
191            }
192        }
193
194        private void process(int action)
195        {
196            //Encrypt/Decrypt Stream
197            try
198            {
199                checkForInputStream();
200                if (inputStream == null || (inputStream != null && inputStream.Length == 0))
201                {
202                    GuiLogMessage("No input given. Not using dummy data in decrypt mode. Aborting now.", NotificationLevel.Error);
203                    return;
204                }
205
206                if (this.inputStream.CanSeek) this.inputStream.Position = 0;
207                SymmetricAlgorithm p_alg = new DESCryptoServiceProvider();
208
209                ConfigureAlg(p_alg);
210
211                ICryptoTransform p_encryptor = null;
212                switch (action)
213                {
214                    case 0:
215                        p_encryptor = p_alg.CreateEncryptor();
216                        break;
217                    case 1:
218                        p_encryptor = p_alg.CreateDecryptor();
219                        break;
220                }
221
222                outputStream = new CryptoolStream();
223                listCryptoolStreamsOut.Add(outputStream);
224                outputStream.OpenWrite(this.GetPluginInfoAttribute().Caption);
225                p_crypto_stream = new CryptoStream((Stream)inputStream, p_encryptor, CryptoStreamMode.Read);
226                byte[] buffer = new byte[p_alg.BlockSize / 8];
227                int bytesRead;
228                int position = 0;
229                GuiLogMessage("Starting encryption [Keysize=" + p_alg.KeySize.ToString() + " Bits, Blocksize=" + p_alg.BlockSize.ToString() + " Bits]", NotificationLevel.Info);
230                DateTime startTime = DateTime.Now;
231                while ((bytesRead = p_crypto_stream.Read(buffer, 0, buffer.Length)) > 0 && !stop)
232                {
233                    outputStream.Write(buffer, 0, bytesRead);
234
235                    if ((int)(inputStream.Position * 100 / inputStream.Length) > position)
236                    {
237                        position = (int)(inputStream.Position * 100 / inputStream.Length);
238                        ProgressChanged(inputStream.Position, inputStream.Length);
239                    }
240                }
241                p_crypto_stream.Flush();
242                outputStream.Close();
243                DateTime stopTime = DateTime.Now;
244                TimeSpan duration = stopTime - startTime;
245                if (!stop)
246                {
247                    GuiLogMessage("Encryption complete! (in: " + inputStream.Length.ToString() + " bytes, out: " + outputStream.Length.ToString() + " bytes)", NotificationLevel.Info);
248                    GuiLogMessage("Wrote data to file: " + outputStream.FileName, NotificationLevel.Info);
249                    GuiLogMessage("Time used: " + duration.ToString(), NotificationLevel.Debug);
250                    OnPropertyChanged("OutputStream");
251                }
252                if (stop)
253                {
254                    GuiLogMessage("Aborted!", NotificationLevel.Info);
255                }
256            }
257            catch (CryptographicException cryptographicException)
258            {
259                p_crypto_stream = null;
260                GuiLogMessage(cryptographicException.Message, NotificationLevel.Error);
261            }
262            catch (Exception exception)
263            {
264                GuiLogMessage(exception.Message, NotificationLevel.Error);
265            }
266            finally
267            {
268                ProgressChanged(1, 1);
269            }
270        }
271
272        public void Encrypt()
273        {
274            //Encrypt Stream
275            process(0);
276        }
277
278        public void Decrypt()
279        {
280            //Decrypt Stream
281            process(1);
282        }
283
284        #region IPlugin Member
285
286        public UserControl Presentation
287        {
288            get { return null; }
289        }
290
291        public UserControl QuickWatchPresentation
292        {
293          get { return null; }
294        }
295
296        public void Initialize()
297        {
298        }
299
300        public void Dispose()
301        {
302            try
303            {
304                stop = false;
305                inputKey = null;
306                inputIV = null;
307
308                foreach (CryptoolStream stream in listCryptoolStreamsOut)
309                {
310                    stream.Close();
311                }
312                listCryptoolStreamsOut.Clear();
313
314                if (p_crypto_stream != null)
315                {
316                    p_crypto_stream.Flush();
317                    p_crypto_stream.Close();
318                    p_crypto_stream = null;
319                }
320            }
321            catch (Exception ex)
322            {
323                GuiLogMessage(ex.Message, NotificationLevel.Error);
324            }
325            this.stop = false;
326        }
327
328        public void Stop()
329        {
330            this.stop = true;
331        }
332
333        public bool isStopped(){
334
335            return this.stop;
336        }
337
338        public void PostExecution()
339        {
340            Dispose();
341        }
342
343        public void PreExecution()
344        {
345            Dispose();
346        }
347
348        #endregion
349
350        #region INotifyPropertyChanged Members
351
352        public event PropertyChangedEventHandler PropertyChanged;
353
354        public void OnPropertyChanged(string name)
355        {
356            if (PropertyChanged != null)
357            {
358                PropertyChanged(this, new PropertyChangedEventArgs(name));
359            }
360        }
361
362        #endregion
363
364        #region IPlugin Members
365
366        public event StatusChangedEventHandler OnPluginStatusChanged;
367
368        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
369        public void GuiLogMessage(string message, NotificationLevel logLevel)
370        {
371          if (OnGuiLogNotificationOccured != null)
372          {
373            OnGuiLogNotificationOccured(this, new GuiLogEventArgs(message, this, logLevel));
374          }
375        }
376
377        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
378        private void ProgressChanged(double value, double max)
379        {
380          if (OnPluginProgressChanged != null)
381          {
382            OnPluginProgressChanged(this, new PluginProgressEventArgs(value, max));
383          }
384        }
385
386        public void Pause()
387        {
388         
389        }
390
391        #endregion
392
393        [PropertyInfo(Direction.ControlSlave, "DES Slave", "Direct access to DES.", "", DisplayLevel.Beginner)]
394        public IControlEncryption ControlSlave
395        {
396          get
397          {
398              if (controlSlave == null)
399                  controlSlave = new DESControl(this);
400              return controlSlave;
401          }
402        }   
403    }
404
405    public class DESControl : IControlEncryption
406    {
407        public event KeyPatternChanged keyPatternChanged;
408        public event IControlStatusChangedEventHandler OnStatusChanged;
409        private DES plugin;
410        private SymmetricAlgorithm des_algorithm = null;
411       
412        public CryptoolStream InputStream{
413            get;set;
414        }
415
416        public DESControl(DES Plugin)
417        {
418            this.plugin = Plugin;
419        }
420
421        #region IControlEncryption Members
422
423        public byte[] Encrypt(byte[] key, int blocksize)
424        {
425            /// not implemented, currently not needed
426            return null;
427        }
428
429        public byte[] Decrypt(byte[] key, int blocksize)
430        {
431            int size = (int)this.InputStream.Length;
432            if (blocksize < size)
433                size = blocksize;
434
435            byte[] input = new byte[size];
436            this.InputStream.Seek(0, 0);
437            for (int i = 0; i < size && i < this.InputStream.Length; i++)
438                input[i] = (byte)this.InputStream.ReadByte();
439
440            Stream inputStream = new MemoryStream(input);           
441                       
442            CryptoStream p_crypto_stream = null;
443            byte[] output = new byte[blocksize];
444
445            //Decrypt Stream
446            try
447            {
448                if (!(des_algorithm is object))
449                {
450                    des_algorithm = new DESCryptoServiceProvider();                   
451                }
452               
453                this.ConfigureAlg(des_algorithm, key);
454               
455                ICryptoTransform p_decryptor;
456                try
457                {
458                    p_decryptor = des_algorithm.CreateDecryptor();
459                }               
460                catch
461                {
462                    //dirty hack to allow weak keys:
463                    MethodInfo mi = des_algorithm.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
464                    object[] Par = { des_algorithm.Key, des_algorithm.Mode, des_algorithm.IV, des_algorithm.FeedbackSize, 0 };
465                    p_decryptor = mi.Invoke(des_algorithm, Par) as ICryptoTransform;
466                }
467
468                p_crypto_stream = new CryptoStream((Stream)inputStream, p_decryptor, CryptoStreamMode.Read);
469
470                byte[] buffer = new byte[des_algorithm.BlockSize / 8];
471                int bytesRead;
472                int position = 0;
473
474                while ((bytesRead = p_crypto_stream.Read(buffer, 0, buffer.Length)) > 0 && !plugin.isStopped())
475                {
476                    for (int i = 0; i < bytesRead; i++)
477                    {
478                        if (position + i < output.Length)
479                        {
480                            output[position + i] = buffer[i];
481                        }
482                        else
483                        {
484                            break;
485                        }
486                    }                   
487                    position += bytesRead;
488                }
489
490                p_crypto_stream.Flush();
491
492            }
493            catch (Exception exception)
494            {
495                plugin.GuiLogMessage(exception.Message, NotificationLevel.Error);
496                plugin.GuiLogMessage(exception.StackTrace, NotificationLevel.Error);
497                des_algorithm = null;   // we got an exception so we do not use this object any more
498            }
499            finally
500            {
501                if(inputStream != null)
502                    inputStream.Close();
503            }
504
505            return output;
506        }
507
508        private void ConfigureAlg(SymmetricAlgorithm alg, byte[] key)
509        {
510            try
511            {
512                alg.Key = key;
513            }
514            catch
515            {
516                //dirty hack to allow weak keys:
517                FieldInfo field = des_algorithm.GetType().GetField("KeyValue", BindingFlags.NonPublic | BindingFlags.Instance);
518                field.SetValue(alg, key);
519            }
520
521            try
522            {
523                alg.IV = this.plugin.InputIV;
524            }
525            catch
526            {
527                //dirty hack to allow weak keys:
528                FieldInfo field = des_algorithm.GetType().GetField("IVValue", BindingFlags.NonPublic | BindingFlags.Instance);
529                field.SetValue(alg, this.plugin.InputIV);
530            }
531
532            switch (((DESSettings)plugin.Settings).Mode)
533            { //0="ECB"=default, 1="CBC", 2="CFB", 3="OFB"
534                case 1: alg.Mode = CipherMode.CBC; break;
535                case 2: alg.Mode = CipherMode.CFB; break;
536                case 3: alg.Mode = CipherMode.OFB; break;
537                default: alg.Mode = CipherMode.ECB; break;
538            }
539            switch (((DESSettings)plugin.Settings).Padding)
540            { //0="Zeros"=default, 1="None", 2="PKCS7"
541                case 1: alg.Padding = PaddingMode.None; break;
542                case 2: alg.Padding = PaddingMode.PKCS7; break;
543                case 3: alg.Padding = PaddingMode.ANSIX923; break;
544                case 4: alg.Padding = PaddingMode.ISO10126; break;
545                default: alg.Padding = PaddingMode.Zeros; break;
546            }
547           
548        }
549
550        /// <summary>
551        /// Called by DES if its status changes
552        /// </summary>
553        public void onStatusChanged()
554        {
555            if (OnStatusChanged != null)
556                OnStatusChanged(this, true);
557        }
558
559        public string getKeyPattern()
560        {
561            return "[0-9A-F][0-9A-F]-[0-9A-F][0-9A-F]-[0-9A-F][0-9A-F]-[0-9A-F][0-9A-F]-"
562                +"[0-9A-F][0-9A-F]-[0-9A-F][0-9A-F]-[0-9A-F][0-9A-F]-[0-9A-F][0-9A-F]";
563        }
564
565        public byte[] getKeyFromString(string key)
566        {
567            byte[] bkey = new byte[8];
568            for (int i = 0; i <= 7; i++)
569            {
570                bkey[i] = Convert.ToByte(key.Substring(i * 3, 2), 16);               
571            }
572            return bkey;
573        }
574
575        #endregion
576    }
577}
Note: See TracBrowser for help on using the repository browser.