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

Last change on this file since 1892 was 1195, checked in by Sven Rech, 12 years ago

removed unsafe code

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