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

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

more speed for bruteforcing by using unsafe code in AES and DES (just temporary)

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