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

Last change on this file since 785 was 785, checked in by kopal, 12 years ago
  • some bugfixes in KeySearcher + DES
  • updated Presentation of KeySearcher with ListBox
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                InputStream = null;
192                OutputStream = null;
193            }
194        }
195
196        private void process(int action)
197        {
198            //Encrypt/Decrypt Stream
199            try
200            {
201                checkForInputStream();
202                if (inputStream == null || (inputStream != null && inputStream.Length == 0))
203                {
204                    GuiLogMessage("No input given. Not using dummy data in decrypt mode. Aborting now.", NotificationLevel.Error);
205                    return;
206                }
207
208                if (this.inputStream.CanSeek) this.inputStream.Position = 0;
209                SymmetricAlgorithm p_alg = new DESCryptoServiceProvider();
210
211                ConfigureAlg(p_alg);
212
213                ICryptoTransform p_encryptor = null;
214                switch (action)
215                {
216                    case 0:
217                        p_encryptor = p_alg.CreateEncryptor();
218                        break;
219                    case 1:
220                        p_encryptor = p_alg.CreateDecryptor();
221                        break;
222                }
223
224                outputStream = new CryptoolStream();
225                listCryptoolStreamsOut.Add(outputStream);
226                outputStream.OpenWrite(this.GetPluginInfoAttribute().Caption);
227                p_crypto_stream = new CryptoStream((Stream)inputStream, p_encryptor, CryptoStreamMode.Read);
228                byte[] buffer = new byte[p_alg.BlockSize / 8];
229                int bytesRead;
230                int position = 0;
231                GuiLogMessage("Starting encryption [Keysize=" + p_alg.KeySize.ToString() + " Bits, Blocksize=" + p_alg.BlockSize.ToString() + " Bits]", NotificationLevel.Info);
232                DateTime startTime = DateTime.Now;
233                while ((bytesRead = p_crypto_stream.Read(buffer, 0, buffer.Length)) > 0 && !stop)
234                {
235                    outputStream.Write(buffer, 0, bytesRead);
236
237                    if ((int)(inputStream.Position * 100 / inputStream.Length) > position)
238                    {
239                        position = (int)(inputStream.Position * 100 / inputStream.Length);
240                        ProgressChanged(inputStream.Position, inputStream.Length);
241                    }
242                }
243                p_crypto_stream.Flush();
244                outputStream.Close();
245                DateTime stopTime = DateTime.Now;
246                TimeSpan duration = stopTime - startTime;
247                if (!stop)
248                {
249                    GuiLogMessage("Encryption complete! (in: " + inputStream.Length.ToString() + " bytes, out: " + outputStream.Length.ToString() + " bytes)", NotificationLevel.Info);
250                    GuiLogMessage("Wrote data to file: " + outputStream.FileName, NotificationLevel.Info);
251                    GuiLogMessage("Time used: " + duration.ToString(), NotificationLevel.Debug);
252                    OnPropertyChanged("OutputStream");
253                }
254                if (stop)
255                {
256                    GuiLogMessage("Aborted!", NotificationLevel.Info);
257                }
258            }
259            catch (CryptographicException cryptographicException)
260            {
261                p_crypto_stream = null;
262                GuiLogMessage(cryptographicException.Message, NotificationLevel.Error);
263            }
264            catch (Exception exception)
265            {
266                GuiLogMessage(exception.Message, NotificationLevel.Error);
267            }
268            finally
269            {
270                ProgressChanged(1, 1);
271            }
272        }
273
274        public void Encrypt()
275        {
276            //Encrypt Stream
277            process(0);
278        }
279
280        public void Decrypt()
281        {
282            //Decrypt Stream
283            process(1);
284        }
285
286        #region IPlugin Member
287
288        public UserControl Presentation
289        {
290            get { return null; }
291        }
292
293        public UserControl QuickWatchPresentation
294        {
295          get { return null; }
296        }
297
298        public void Initialize()
299        {
300        }
301
302        public void Dispose()
303        {
304            try
305            {
306                stop = false;
307                inputKey = null;
308                inputIV = null;
309
310                foreach (CryptoolStream stream in listCryptoolStreamsOut)
311                {
312                    stream.Close();
313                }
314                listCryptoolStreamsOut.Clear();
315
316                if (p_crypto_stream != null)
317                {
318                    p_crypto_stream.Flush();
319                    p_crypto_stream.Close();
320                    p_crypto_stream = null;
321                }
322            }
323            catch (Exception ex)
324            {
325                GuiLogMessage(ex.Message, NotificationLevel.Error);
326            }
327            this.stop = false;
328        }
329
330        public void Stop()
331        {
332            this.stop = true;
333        }
334
335        public bool isStopped(){
336
337            return this.stop;
338        }
339
340        public void PostExecution()
341        {
342            Dispose();
343        }
344
345        public void PreExecution()
346        {
347            Dispose();
348        }
349
350        #endregion
351
352        #region INotifyPropertyChanged Members
353
354        public event PropertyChangedEventHandler PropertyChanged;
355
356        public void OnPropertyChanged(string name)
357        {
358            if (PropertyChanged != null)
359            {
360                PropertyChanged(this, new PropertyChangedEventArgs(name));
361            }
362        }
363
364        #endregion
365
366        #region IPlugin Members
367
368        public event StatusChangedEventHandler OnPluginStatusChanged;
369
370        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
371        public void GuiLogMessage(string message, NotificationLevel logLevel)
372        {
373          if (OnGuiLogNotificationOccured != null)
374          {
375            OnGuiLogNotificationOccured(this, new GuiLogEventArgs(message, this, logLevel));
376          }
377        }
378
379        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
380        private void ProgressChanged(double value, double max)
381        {
382          if (OnPluginProgressChanged != null)
383          {
384            OnPluginProgressChanged(this, new PluginProgressEventArgs(value, max));
385          }
386        }
387
388        public void Pause()
389        {
390         
391        }
392
393        #endregion
394
395        [PropertyInfo(Direction.ControlSlave, "DES Slave", "Direct access to DES.", "", DisplayLevel.Beginner)]
396        public IControlEncryption ControlSlave
397        {
398          get
399          {
400              if (controlSlave == null)
401                  controlSlave = new DESControl(this);
402              return controlSlave;
403          }
404        }   
405    }
406
407    public class DESControl : IControlEncryption
408    {
409        public event KeyPatternChanged keyPatternChanged;
410        public event IControlStatusChangedEventHandler OnStatusChanged;
411        private DES plugin;
412        private SymmetricAlgorithm des_algorithm = null;
413       
414        public CryptoolStream InputStream{
415            get;set;
416        }
417
418        public DESControl(DES Plugin)
419        {
420            this.plugin = Plugin;
421        }
422
423        #region IControlEncryption Members
424
425        public byte[] Encrypt(byte[] key, int blocksize)
426        {
427            /// not implemented, currently not needed
428            return null;
429        }
430
431        public byte[] Decrypt(byte[] key, int blocksize)
432        {
433            int size = (int)this.InputStream.Length;
434            if (blocksize < size)
435                size = blocksize;
436
437            byte[] input = new byte[size];
438            this.InputStream.Seek(0, 0);
439            for (int i = 0; i < size && i < this.InputStream.Length; i++)
440                input[i] = (byte)this.InputStream.ReadByte();
441
442            Stream inputStream = new MemoryStream(input);           
443                       
444            CryptoStream p_crypto_stream = null;
445            byte[] output = new byte[blocksize];
446
447            //Decrypt Stream
448            try
449            {
450                if (!(des_algorithm is object))
451                {
452                    des_algorithm = new DESCryptoServiceProvider();                   
453                }
454               
455                this.ConfigureAlg(des_algorithm, key);
456               
457                ICryptoTransform p_decryptor;
458                try
459                {
460                    p_decryptor = des_algorithm.CreateDecryptor();
461                }               
462                catch
463                {
464                    //dirty hack to allow weak keys:
465                    MethodInfo mi = des_algorithm.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
466                    object[] Par = { des_algorithm.Key, des_algorithm.Mode, des_algorithm.IV, des_algorithm.FeedbackSize, 0 };
467                    p_decryptor = mi.Invoke(des_algorithm, Par) as ICryptoTransform;
468                }
469
470                p_crypto_stream = new CryptoStream((Stream)inputStream, p_decryptor, CryptoStreamMode.Read);
471
472                byte[] buffer = new byte[des_algorithm.BlockSize / 8];
473                int bytesRead;
474                int position = 0;
475
476                while ((bytesRead = p_crypto_stream.Read(buffer, 0, buffer.Length)) > 0 && !plugin.isStopped())
477                {
478                    for (int i = 0; i < bytesRead; i++)
479                    {
480                        if (position + i < output.Length)
481                        {
482                            output[position + i] = buffer[i];
483                        }
484                        else
485                        {
486                            break;
487                        }
488                    }                   
489                    position += bytesRead;
490                }
491
492                p_crypto_stream.Flush();
493
494            }
495            catch (Exception exception)
496            {
497                des_algorithm = null;   // we got an exception so we do not use this object any more
498                throw exception;
499            }
500            finally
501            {
502                if(inputStream != null)
503                    inputStream.Close();
504            }
505
506            return output;
507        }
508
509        private void ConfigureAlg(SymmetricAlgorithm alg, byte[] key)
510        {
511            try
512            {
513                alg.Key = key;
514            }
515            catch
516            {
517                //dirty hack to allow weak keys:
518                FieldInfo field = des_algorithm.GetType().GetField("KeyValue", BindingFlags.NonPublic | BindingFlags.Instance);
519                field.SetValue(alg, key);
520            }
521
522            try
523            {
524                alg.IV = this.plugin.InputIV;
525            }
526            catch
527            {
528                //dirty hack to allow weak keys:
529                FieldInfo field = des_algorithm.GetType().GetField("IVValue", BindingFlags.NonPublic | BindingFlags.Instance);
530                field.SetValue(alg, this.plugin.InputIV);
531            }
532
533            switch (((DESSettings)plugin.Settings).Mode)
534            { //0="ECB"=default, 1="CBC", 2="CFB", 3="OFB"
535                case 1: alg.Mode = CipherMode.CBC; break;
536                case 2: alg.Mode = CipherMode.CFB; break;
537                case 3: alg.Mode = CipherMode.OFB; break;
538                default: alg.Mode = CipherMode.ECB; break;
539            }
540            switch (((DESSettings)plugin.Settings).Padding)
541            { //0="Zeros"=default, 1="None", 2="PKCS7"
542                case 1: alg.Padding = PaddingMode.None; break;
543                case 2: alg.Padding = PaddingMode.PKCS7; break;
544                case 3: alg.Padding = PaddingMode.ANSIX923; break;
545                case 4: alg.Padding = PaddingMode.ISO10126; break;
546                default: alg.Padding = PaddingMode.Zeros; break;
547            }
548           
549        }
550
551        /// <summary>
552        /// Called by DES if its status changes
553        /// </summary>
554        public void onStatusChanged()
555        {
556            if (OnStatusChanged != null)
557                OnStatusChanged(this, true);
558        }
559
560        public string getKeyPattern()
561        {
562            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]-"
563                +"[0-9A-F][0-9A-F]-[0-9A-F][0-9A-F]-[0-9A-F][0-9A-F]-[0-9A-F][0-9A-F]";
564        }
565
566        public byte[] getKeyFromString(string key)
567        {
568            byte[] bkey = new byte[8];
569            for (int i = 0; i <= 7; i++)
570            {
571                bkey[i] = Convert.ToByte(key.Substring(i * 3, 2), 16);               
572            }
573            return bkey;
574        }
575
576        #endregion
577    }
578}
Note: See TracBrowser for help on using the repository browser.