source: trunk/CrypPlugins/AES/AES.cs @ 1157

Last change on this file since 1157 was 1157, checked in by Arno Wacker, 12 years ago

AnotherEditor

  • Yet another Invoke during a single log message changed into BeginInvoke

IControlEncryption

  • Removed obsolete signature

CryptoolStream

  • Added a try-catch when deleting a file. An exception occurs when the file is locked. Clearly, in this case there not much one can do.. the file remains on the disk. Waiting for CStream...

AES, DES, SDES

  • Cleanup of IControl interface and general code cleanup
  • Fixed compatibility with KeySearcher - now all three should work again. (However, kind of slow)

StreamToStringConverter

  • Updated license

Sample update

  • KeySearcher-Sample-DES.cte, KeySearcher-Sample-DES.cte, KeySearcher-Sample-SDES.cte: Compatibility with IControl changes and slight rearrangement.
  • P2P-DES-BruteforceManger.cte, P2P-DES-BruteforceWorker.cte: Compatibility

New binaries

  • CrypWin.exe
  • AnotherEditor.dll
File size: 25.3 KB
Line 
1/*                              Apache License
2                           Version 2.0, January 2004
3                        http://www.apache.org/licenses/
4
5   Copyright [2008] [Dr. Arno Wacker, University of Duisburg-Essen]
6
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10
11       http://www.apache.org/licenses/LICENSE-2.0
12
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18*/
19
20using System;
21using System.Collections.Generic;
22using System.Linq;
23using System.Text;
24using System.IO;
25using System.Security.Cryptography;
26using Cryptool.PluginBase;
27using System.ComponentModel;
28using Cryptool.PluginBase.Cryptography;
29using Cryptool.PluginBase.IO;
30using System.Windows.Controls;
31using System.Runtime.CompilerServices;
32using Cryptool.PluginBase.Miscellaneous;
33using System.Runtime.Remoting.Contexts;
34using Cryptool.PluginBase.Control;
35using System.Reflection;
36
37namespace Cryptool.Plugins.Cryptography.Encryption
38{
39    [Author("Dr. Arno Wacker", "arno.wacker@cryptool.org", "Uni Duisburg", "http://www.uni-duisburg-essen.de")]
40    [PluginInfo(false, "AES", "Advanced Encryption Standard (Rijndael)", "AES/DetailedDescription/Description.xaml", "AES/Images/AES.png", "AES/Images/encrypt.png", "AES/Images/decrypt.png", "AES/Images/Rijndael.png")]
41    [EncryptionType(EncryptionType.SymmetricBlock)]
42    public class AES : ContextBoundObject, IEncryption
43    {
44        #region Private variables
45        private AESSettings settings;
46        private CryptoolStream inputStream;
47        private CryptoolStream outputStream;
48        private byte[] inputKey;
49        private byte[] inputIV;
50        private CryptoStream p_crypto_stream;
51        private bool stop = false;
52        private List<CryptoolStream> listCryptoolStreamsOut = new List<CryptoolStream>();
53        #endregion
54
55        public AES()
56        {
57            this.settings = new AESSettings();
58            this.settings.OnPluginStatusChanged += settings_OnPluginStatusChanged;
59        }
60
61        void settings_OnPluginStatusChanged(IPlugin sender, StatusEventArgs args)
62        {
63          if (OnPluginStatusChanged != null) OnPluginStatusChanged(this, args);
64        }
65
66        public ISettings Settings
67        {
68            get { return this.settings; }
69            set { this.settings = (AESSettings)value; }
70        }
71
72        [PropertyInfo(Direction.InputData, "Input", "Data to be encrypted or decrypted", "", true, false, DisplayLevel.Beginner, QuickWatchFormat.Hex, null)]
73        public CryptoolStream InputStream
74        {
75            get 
76            {
77              if (inputStream != null)
78              {
79                CryptoolStream cs = new CryptoolStream();
80                cs.OpenRead(inputStream.FileName);
81                listCryptoolStreamsOut.Add(cs);
82                return cs;
83              }
84              else return null;
85            }
86            set 
87            { 
88              this.inputStream = value;
89              if (value != null) listCryptoolStreamsOut.Add(value);
90              OnPropertyChanged("InputStream");
91            }
92        }
93
94        [PropertyInfo(Direction.InputData, "Key", "The provided key should be 16, 24 or 32 bytes, dependig on the settings. Too short/long keys will be extended/truncated!", "", true, false, DisplayLevel.Beginner, QuickWatchFormat.Hex, null)]
95        public byte[] InputKey
96        {
97            get { return this.inputKey; }
98            set 
99            { 
100              this.inputKey = value;
101              OnPropertyChanged("InputKey");
102            }
103        }
104
105        [PropertyInfo(Direction.InputData, "IV", "The initialisation vector (IV) which is used in chaining modes. It always must be the same as the blocksize.", "", false, false, DisplayLevel.Professional, QuickWatchFormat.Hex, null)]
106        public byte[] InputIV
107        {
108            get { return this.inputIV; }
109            set 
110            { 
111              this.inputIV = value;
112              OnPropertyChanged("InputIV");
113            }
114        }
115
116        [PropertyInfo(Direction.OutputData, "Output stream", "Encrypted or decrypted output data", "", true, false, DisplayLevel.Beginner, QuickWatchFormat.Hex, null)]
117        public CryptoolStream OutputStream
118        {
119            get 
120            {
121              if (this.outputStream != null)
122              {
123                CryptoolStream cs = new CryptoolStream();
124                listCryptoolStreamsOut.Add(cs);
125                cs.OpenRead(this.outputStream.FileName);
126                return cs;
127              }
128              return null;
129            }
130            set 
131            {
132              outputStream = value;
133              if (value != null) listCryptoolStreamsOut.Add(value);
134              OnPropertyChanged("OutputStream");
135            }
136        }
137
138        private void ConfigureAlg(SymmetricAlgorithm alg)
139        {
140            // first set all paramter, then assign input values!
141            switch (settings.Mode)
142            { //0="ECB"=default, 1="CBC", 2="CFB", 3="OFB"
143                case 1: alg.Mode = CipherMode.CBC; break;
144                case 2: alg.Mode = CipherMode.CFB; break;
145                // case 3: alg.Mode = CipherMode.OFB; break;
146                default: alg.Mode = CipherMode.ECB; break;
147            }
148
149            switch (settings.Padding)
150            { //0="Zeros"=default, 1="None", 2="PKCS7" , 3="ANSIX923", 4="ISO10126"
151                case 1: alg.Padding = PaddingMode.None; break;
152                case 2: alg.Padding = PaddingMode.PKCS7; break;
153                case 3: alg.Padding = PaddingMode.ANSIX923; break;
154                case 4: alg.Padding = PaddingMode.ISO10126; break;
155                default: alg.Padding = PaddingMode.Zeros; break;
156            }
157            if (settings.CryptoAlgorithm == 1)
158            {
159                switch (settings.Blocksize)
160                {
161                    case 1: alg.BlockSize = 192; break;
162                    case 2: alg.BlockSize = 256; break;
163                    default:
164                        alg.BlockSize = 128;
165                        break;
166                }
167            }
168
169            //check for a valid key
170            if (this.inputKey == null)
171            {               
172                //create a trivial key
173                inputKey = new byte[16];
174                // write a warning to the ouside word
175                GuiLogMessage("ERROR: No key provided. Using 0x000..00!", NotificationLevel.Error);
176            }
177
178            int keySizeInBytes = (16 + settings.Keysize * 8);
179
180            //prepare a long enough key
181            byte[] key = new byte[keySizeInBytes];
182
183            // copy the input key into the temporary key array
184            Array.Copy(inputKey, key, Math.Min(inputKey.Length, key.Length));
185
186            // Note: the SymmetricAlgorithm.Key setter clones the passed byte[] array and keeps his own copy
187            alg.Key = key;
188
189            if (inputKey.Length > keySizeInBytes)
190            {
191                GuiLogMessage("Overlength (" + inputKey.Length * 8 + " Bits) key provided. Removing trailing bytes to fit the desired key length of " + (keySizeInBytes * 8) + " Bits: " + bytesToHexString(key), NotificationLevel.Warning);
192            }
193
194            if (inputKey.Length < keySizeInBytes)
195            {
196                GuiLogMessage("Short (" + inputKey.Length * 8 + " Bits) key provided. Adding zero bytes to fill up to the desired key length of " + (keySizeInBytes * 8) + " Bits: " + bytesToHexString(key), NotificationLevel.Warning);
197            }
198
199            //check for a valid IV
200            if (this.inputIV == null)
201            {
202                //create a trivial key
203                inputIV = new byte[alg.BlockSize / 8];
204                GuiLogMessage("NOTE: No IV provided. Using 0x000..00!", NotificationLevel.Info);
205            }
206            alg.IV = this.inputIV;
207        }
208
209        private string bytesToHexString(byte[] array)
210        {
211            StringBuilder sb = new StringBuilder();
212            foreach (byte b in array)
213            {
214                sb.Append(b.ToString("X2"));
215            }
216            return sb.ToString();
217        }
218
219        private void checkForInputStream()
220        {
221            if (settings.Action == 0 && (inputStream == null || (inputStream != null && inputStream.Length == 0)))
222            {
223                //create some input
224                String dummystring = "Dummy string - no input provided - \"Hello AES World\" - dummy string - no input provided!";
225                this.inputStream = new CryptoolStream();
226                this.inputStream.OpenRead(Encoding.Default.GetBytes(dummystring.ToCharArray()));
227                // write a warning to the ouside word
228                GuiLogMessage("WARNING: No input provided. Using dummy data. (" + dummystring + ")", NotificationLevel.Warning);
229            }
230        }
231
232        public void Execute()
233        {
234            process(settings.Action);
235        }
236
237        public bool isStopped()
238        {
239
240            return this.stop;
241        }
242
243        private void process(int action)
244        {
245            //Encrypt/Decrypt Stream
246          try
247          {
248            checkForInputStream();
249            if (inputStream == null || inputStream.Length == 0)
250            {
251              GuiLogMessage("No input given. Not using dummy data in decrypt mode. Aborting now.", NotificationLevel.Error);
252              return;
253            }
254
255            if (this.inputStream.CanSeek) this.inputStream.Position = 0;
256            SymmetricAlgorithm p_alg = null;
257            if (settings.CryptoAlgorithm == 1)
258            { p_alg = new RijndaelManaged(); }
259            else
260            { p_alg = new AesCryptoServiceProvider(); }
261
262            ConfigureAlg(p_alg);
263
264            ICryptoTransform p_encryptor = null;
265            switch (action)
266            {
267              case 0:
268                p_encryptor = p_alg.CreateEncryptor();
269                break;
270              case 1:
271                p_encryptor = p_alg.CreateDecryptor();
272                break;
273            }
274
275            outputStream = new CryptoolStream();
276            listCryptoolStreamsOut.Add(outputStream);
277            outputStream.OpenWrite();
278            p_crypto_stream = new CryptoStream((Stream)inputStream, p_encryptor, CryptoStreamMode.Read);
279            byte[] buffer = new byte[p_alg.BlockSize / 8];
280            int bytesRead;
281            int position = 0;
282            string mode = action == 0 ? "encryption" : "decryption";
283            GuiLogMessage("Starting " + mode + " [Keysize=" + p_alg.KeySize.ToString() + " Bits, Blocksize=" + p_alg.BlockSize.ToString() + " Bits]", NotificationLevel.Info);
284            DateTime startTime = DateTime.Now;
285            while ((bytesRead = p_crypto_stream.Read(buffer, 0, buffer.Length)) > 0 && !stop)
286            {
287              outputStream.Write(buffer, 0, bytesRead);
288
289              if ((int)(inputStream.Position * 100 / inputStream.Length) > position)
290              {
291                position = (int)(inputStream.Position * 100 / inputStream.Length);
292                ProgressChanged(inputStream.Position, inputStream.Length);
293              }
294            }
295
296
297            long outbytes = outputStream.Length;
298            p_crypto_stream.Flush();           
299            // p_crypto_stream.Close();
300            DateTime stopTime = DateTime.Now;
301            TimeSpan duration = stopTime - startTime;
302            // (outputStream as CryptoolStream).FinishWrite();
303
304            if (!stop)
305            {
306                mode = action == 0 ? "Encryption" : "Decryption";
307                GuiLogMessage(mode + " complete! (in: " + inputStream.Length.ToString() + " bytes, out: " + outbytes.ToString() + " bytes)", NotificationLevel.Info);
308                GuiLogMessage("Wrote data to file: " + outputStream.FileName, NotificationLevel.Info);
309                GuiLogMessage("Time used: " + duration.ToString(), NotificationLevel.Debug);
310                outputStream.Close();
311                OnPropertyChanged("OutputStream");
312            }
313            CryptoolStream test = outputStream;
314            if (stop)
315            {
316                outputStream.Close();
317                GuiLogMessage("Aborted!", NotificationLevel.Info);
318            }
319          }
320          catch (CryptographicException cryptographicException)
321          {
322            // TODO: For an unknown reason p_crypto_stream can not be closed after exception.
323            // Trying so makes p_crypto_stream throw the same exception again. So in Dispose
324            // the error messages will be doubled.
325            // As a workaround we set p_crypto_stream to null here.
326            p_crypto_stream = null;
327            GuiLogMessage(cryptographicException.Message, NotificationLevel.Error);
328          }
329          catch (Exception exception)
330          {
331            GuiLogMessage(exception.Message, NotificationLevel.Error);
332          }
333          finally
334          {
335              ProgressChanged(1, 1);
336          }
337        }
338
339        public void Encrypt()
340        {
341            //Encrypt Stream
342            process(0);
343        }
344       
345        public void Decrypt()
346        {
347            //Decrypt Stream
348            process(1);
349        }
350
351        #region IPlugin Member
352
353
354        public System.Windows.Controls.UserControl Presentation
355        {
356          get { return null; }
357        }
358
359        public UserControl QuickWatchPresentation
360        {
361          get { return null; }
362        }
363
364        public void Initialize()
365        {           
366        }
367
368        public void Dispose()
369        {
370          try
371          {
372            stop = false;
373            inputKey = null;
374            inputIV = null;
375            outputStream = null;
376            inputStream = null;
377
378            //if (inputStream != null)
379            //{
380            //  inputStream.Flush();
381            //  inputStream.Close();
382            //  inputStream = null;
383            //}
384            //if (outputStream != null)
385            //{
386            //  outputStream.Flush();
387            //  outputStream.Close();
388            //  outputStream = null;
389            //}
390            foreach (CryptoolStream stream in listCryptoolStreamsOut)
391            {
392              stream.Close();
393            }
394            listCryptoolStreamsOut.Clear();
395
396            if (p_crypto_stream != null)
397            {
398              p_crypto_stream.Flush();
399              p_crypto_stream.Close();
400              p_crypto_stream = null;
401            }
402          }
403          catch (Exception ex)
404          {         
405             GuiLogMessage(ex.Message, NotificationLevel.Error);
406          }
407          this.stop = false;
408        }
409
410        public void Stop()
411        {
412          this.stop = true;
413        }
414
415        public void PostExecution()
416        {
417          Dispose();
418        }
419
420        public void PreExecution()
421        {
422          Dispose();
423        }
424
425        #endregion
426
427        #region INotifyPropertyChanged Members
428
429        public event PropertyChangedEventHandler PropertyChanged;
430
431        public void OnPropertyChanged(string name)
432        {
433          EventsHelper.PropertyChanged(PropertyChanged, this, new PropertyChangedEventArgs(name));
434          //if (PropertyChanged != null)
435          //{
436          //  PropertyChanged(this, new PropertyChangedEventArgs(name));
437          //}
438        }
439
440        #endregion
441
442        #region IPlugin Members
443
444        public event StatusChangedEventHandler OnPluginStatusChanged;       
445
446        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
447        private void GuiLogMessage(string message, NotificationLevel logLevel)
448        {
449          EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(message, this, logLevel));
450        }
451
452        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
453        private void ProgressChanged(double value, double max)
454        {
455          EventsHelper.ProgressChanged(OnPluginProgressChanged, this, new PluginProgressEventArgs(value, max));
456        }
457       
458        public void Pause()
459        {
460         
461        }
462
463        #endregion
464
465        private IControlEncryption controlSlave;
466        [PropertyInfo(Direction.ControlSlave, "AES Slave", "AES Slave", "", DisplayLevel.Experienced)]
467        public IControlEncryption ControlSlave
468        {
469          get 
470          {
471              if (controlSlave == null)
472                  controlSlave = new AESControl(this);
473              return controlSlave; 
474          }
475        }     
476    }
477
478    public class AESControl : IControlEncryption
479    {
480        public event KeyPatternChanged keyPatternChanged;
481        public event IControlStatusChangedEventHandler OnStatusChanged;
482
483        private AES plugin;
484     
485        public AESControl(AES Plugin)
486        {
487            this.plugin = Plugin;
488        }
489
490        #region IControlEncryption Members
491
492        public byte[] Encrypt(byte[] key, int blocksize)
493        {
494            /// not implemented, currently not needed
495            return null;
496        }
497
498       
499
500        public byte[] Decrypt(byte[] ciphertext, byte[] key)
501        {
502            CryptoStream crypto_stream = null;
503            byte[] output = new byte[ciphertext.Length];
504
505
506            SymmetricAlgorithm aes_algorithm = null;
507
508            //Decrypt Stream
509            try
510            {
511                if (!(aes_algorithm is object))
512                {
513                    if (((AESSettings)plugin.Settings).CryptoAlgorithm == 1)
514                    { aes_algorithm = new RijndaelManaged(); }
515                    else
516                    { aes_algorithm = new AesCryptoServiceProvider(); }
517                }
518
519                this.ConfigureAlg(aes_algorithm, key);
520
521                ICryptoTransform p_decryptor;
522                try
523                {
524                    p_decryptor = aes_algorithm.CreateDecryptor();
525                }
526                catch
527                {
528                    //dirty hack to allow weak keys:
529                    MethodInfo mi = aes_algorithm.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
530                    object[] Par = { aes_algorithm.Key, aes_algorithm.Mode, aes_algorithm.IV, aes_algorithm.FeedbackSize, 0 };
531                    p_decryptor = mi.Invoke(aes_algorithm, Par) as ICryptoTransform;
532                }
533
534                crypto_stream = new CryptoStream(new MemoryStream(ciphertext), p_decryptor, CryptoStreamMode.Read);
535
536                byte[] buffer = new byte[aes_algorithm.BlockSize / 8];
537                int bytesRead;
538                int position = 0;
539
540                while ((bytesRead = crypto_stream.Read(buffer, 0, buffer.Length)) > 0 && !plugin.isStopped())
541                {
542                    for (int i = 0; i < bytesRead; i++)
543                    {
544                        if (position + i < output.Length)
545                        {
546                            output[position + i] = buffer[i];
547                        }
548                        else
549                        {
550                            break;
551                        }
552                    }
553                    position += bytesRead;
554                }
555
556            }
557            catch (Exception exception)
558            {
559                aes_algorithm = null;   // we got an exception so we do not use this object any more
560                throw exception;
561            }
562
563            return output;
564        }
565
566     
567
568        private void ConfigureAlg(SymmetricAlgorithm alg, byte[] key)
569        {
570            try
571            {
572                alg.Key = key;
573            }
574            catch
575            {
576                //dirty hack to allow weak keys:
577                FieldInfo field = alg.GetType().GetField("KeyValue", BindingFlags.NonPublic | BindingFlags.Instance);
578                field.SetValue(alg, key);
579            }
580
581            //try
582            //{
583            //    alg.IV = this.plugin.InputIV;
584            //}
585            //catch
586            //{
587            //    //dirty hack to allow weak keys:
588            //    FieldInfo field = aes_algorithm.GetType().GetField("IVValue", BindingFlags.NonPublic | BindingFlags.Instance);
589            //    field.SetValue(alg, this.plugin.InputIV);
590            //}
591            alg.IV = new byte[alg.BlockSize / 8];
592
593
594            switch (((AESSettings)plugin.Settings).Mode)
595            { //0="ECB"=default, 1="CBC", 2="CFB", 3="OFB"
596                case 1: alg.Mode = CipherMode.CBC; break;
597                case 2: alg.Mode = CipherMode.CFB; break;
598                case 3: alg.Mode = CipherMode.OFB; break;
599                default: alg.Mode = CipherMode.ECB; break;
600            }
601
602            alg.Padding = PaddingMode.Zeros;
603
604            //switch (((AESSettings)plugin.Settings).Padding)
605            //{ //0="Zeros"=default, 1="None", 2="PKCS7"
606            //    case 1: alg.Padding = PaddingMode.None; break;
607            //    case 2: alg.Padding = PaddingMode.PKCS7; break;
608            //    case 3: alg.Padding = PaddingMode.ANSIX923; break;
609            //    case 4: alg.Padding = PaddingMode.ISO10126; break;
610            //    default: alg.Padding = PaddingMode.Zeros; break;
611            //}
612           
613        }
614       
615        public string getKeyPattern()
616        {
617            int bytes = 0;
618            switch (((AESSettings)plugin.Settings).Keysize)
619            {
620                case 0:
621                    bytes = 16;
622                    break;
623                case 1:
624                    bytes = 24;
625                    break;
626                case 2:
627                    bytes = 32;
628                    break;
629            }
630            string pattern = "";
631            for (int i = 1; i < bytes; i++)
632                pattern += "[0-9A-F][0-9A-F]-";
633            pattern += "[0-9A-F][0-9A-F]";
634            return pattern;
635        }
636
637        public byte[] getKeyFromString(string key, ref int[] arrayPointers, ref int[] arraySuccessors, ref int[] arrayUppers)
638        {
639            int bytes = 0;
640            switch (((AESSettings)plugin.Settings).Keysize)
641            {
642                case 0:
643                    bytes = 16;
644                    break;
645                case 1:
646                    bytes = 24;
647                    break;
648                case 2:
649                    bytes = 32;
650                    break;
651            }
652            byte[] bkey = new byte[bytes];
653            int counter = 0;
654            bool allocated = false;
655            for (int i = 0; i < bytes; i++)
656            {
657                try
658                {
659                    string substr = key.Substring(i * 3, 2);
660                    if (!allocated && (substr[0] == '*' || substr[1] == '*'))
661                    {
662                        arrayPointers = new int[bytes];
663                        for (int j = 0; j < bytes; j++)
664                            arrayPointers[j] = -1;
665                        arraySuccessors = new int[bytes];
666                        arrayUppers = new int[bytes];
667                        allocated = true;
668                    }
669                    if (substr[0] != '*' && substr[1] != '*')
670                        bkey[i] = Convert.ToByte(substr, 16);
671                    else if (substr[0] == '*' && substr[1] == '*')
672                    {
673                        bkey[i] = 0;
674                        arrayPointers[counter] = i;
675                        arraySuccessors[counter] = 1;
676                        arrayUppers[counter] = 255;
677                        counter++;
678                    }
679                    else if (substr[0] != '*' && substr[1] == '*')
680                    {
681                        bkey[i] = Convert.ToByte(substr[0] + "0", 16);
682                        arrayPointers[counter] = i;
683                        arraySuccessors[counter] = 1;
684                        arrayUppers[counter] = Convert.ToByte(substr[0] + "F", 16);
685                        counter++;
686                    }
687                    else if (substr[0] == '*' && substr[1] != '*')
688                    {
689                        bkey[i] = Convert.ToByte("0" + substr[1], 16);
690                        arrayPointers[counter] = i;
691                        arraySuccessors[counter] = 16;
692                        arrayUppers[counter] = Convert.ToByte("F" + substr[1], 16);
693                        counter++;
694                    }
695                }
696                catch (Exception ex)
697                {
698                    return null;
699                }
700            }
701            return bkey;
702        }
703
704        public IControlEncryption clone()
705        {
706            AESControl aes = new AESControl(plugin);
707            return aes;
708        }
709
710        public void Dispose()
711        {
712        }
713
714        #endregion
715
716        #region IControlEncryption Member
717
718
719        public void changeSettings(string setting, object value)
720        {
721           
722        }
723
724        #endregion
725    }
726}
Note: See TracBrowser for help on using the repository browser.