source: trunk/CrypPlugins/TEA/TEA.cs @ 2220

Last change on this file since 2220 was 1042, checked in by Sören Rinne, 12 years ago
  • bugfixing
  • replaced all licenses with the short version
File size: 23.7 KB
Line 
1/*
2   Copyright 2009 Sören Rinne, Ruhr-Universität Bochum, Germany
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Collections.Generic;
19using System.Linq;
20using System.Text;
21
22using Cryptool.PluginBase;
23using System.IO;
24using System.ComponentModel;
25using Cryptool.PluginBase.Cryptography;
26using Cryptool.PluginBase.IO;
27using System.Windows.Controls;
28using Cryptool.PluginBase.Miscellaneous;
29using System.Security.Cryptography;
30
31namespace Cryptool.TEA
32{
33    [Author("Soeren Rinne", "soeren.rinne@cryptool.de", "Ruhr-Universitaet Bochum, Chair for Embedded Security (EmSec)", "http://www.crypto.ruhr-uni-bochum.de/")]
34    [PluginInfo(false, "TEA", "Tiny Encryption Algorithm", "TEA/DetailedDescription/Description.xaml", "TEA/Images/tea.png", "TEA/Images/encrypt.png", "TEA/Images/decrypt.png", "TEA/Images/encryptX.png", "TEA/Images/decryptX.png")]
35    [EncryptionType(EncryptionType.SymmetricBlock)]
36    public class TEA : IEncryption
37    {
38        #region IPlugin Members
39
40        private TEASettings settings;
41        private CryptoolStream inputStream;
42        private CryptoolStream outputStream;
43        private byte[] inputKey;
44        private bool stop = false;
45        private List<CryptoolStream> listCryptoolStreamsOut = new List<CryptoolStream>();
46
47        #endregion
48
49        public TEA()
50        {
51            this.settings = new TEASettings();
52            //((TEASettings)(this.settings)).LogMessage += TEA_LogMessage;
53        }
54
55        public ISettings Settings
56        {
57            get { return (ISettings)this.settings; }
58            set { this.settings = (TEASettings)value; }
59        }
60
61        [PropertyInfo(Direction.InputData, "Input", "Data to be encrypted or decrypted.", "", true, false, DisplayLevel.Beginner, QuickWatchFormat.Hex, null)]
62        public CryptoolStream InputStream
63        {
64            get 
65            {
66              if (inputStream != null)
67              {
68                CryptoolStream cs = new CryptoolStream();
69                cs.OpenRead(inputStream.FileName);
70                listCryptoolStreamsOut.Add(cs);
71                return cs;
72              }
73              else return null;
74            }
75            set 
76            { 
77              this.inputStream = value;
78              if (value != null) listCryptoolStreamsOut.Add(value);
79              OnPropertyChanged("InputStream");
80            }
81        }
82
83        [PropertyInfo(Direction.InputData, "Key", "Must be 16 bytes (128 bit).", "", true, false, DisplayLevel.Beginner, QuickWatchFormat.Hex, null)]
84        public byte[] InputKey
85        {
86            get { return this.inputKey; }
87            set
88            {
89                this.inputKey = value;
90                OnPropertyChanged("InputKey");
91            }
92        }
93
94        [PropertyInfo(Direction.OutputData, "Output stream", "Encrypted or decrypted output data", "", 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        public void Dispose()
117        {
118            try
119            {
120                stop = false;
121                inputKey = null;
122                outputStream = null;
123                inputStream = null;
124
125                if (inputStream != null)
126                {
127                    inputStream.Flush();
128                    inputStream.Close();
129                    inputStream = null;
130                }
131                if (outputStream != null)
132                {
133                    outputStream.Flush();
134                    outputStream.Close();
135                    outputStream = null;
136                }
137                foreach (CryptoolStream stream in listCryptoolStreamsOut)
138                {
139                    stream.Close();
140                }
141                listCryptoolStreamsOut.Clear();
142            }
143            catch (Exception ex)
144            {
145                GuiLogMessage(ex.Message, NotificationLevel.Error);
146            }
147            this.stop = false;
148        }
149
150        private void checkForInputStream()
151        {
152            if (settings.Action == 0 && (inputStream == null || (inputStream != null && inputStream.Length == 0)))
153            {
154                //create some input
155                String dummystring = "12345678";
156                this.inputStream = new CryptoolStream();
157                this.inputStream.OpenRead(this.GetPluginInfoAttribute().Caption, Encoding.Default.GetBytes(dummystring.ToCharArray()));
158                // write a warning to the outside world
159                GuiLogMessage("WARNING - No input provided. Using dummy data. (" + dummystring + ")", NotificationLevel.Warning);
160            }
161        }
162
163        public void Execute()
164        {
165            process(settings.Action, settings.Padding);
166        }
167
168        private void process(int action, int padding)
169        {
170            //Encrypt/Decrypt Stream
171            try
172            {               
173                checkForInputStream();
174
175                if (inputStream == null || (inputStream != null && inputStream.Length == 0))
176                {
177                    GuiLogMessage("No input given. Not using dummy data in decrypt mode. Aborting now.", NotificationLevel.Error);
178                    return;
179                }
180
181                if (this.inputStream.CanSeek) this.inputStream.Position = 0;
182
183                outputStream = new CryptoolStream();
184                listCryptoolStreamsOut.Add(outputStream);
185                outputStream.OpenWrite(this.GetPluginInfoAttribute().Caption);
186
187                long inputbytes = inputStream.Length;
188                GuiLogMessage("inputStream length [bytes]: " + inputStream.Length.ToString(), NotificationLevel.Debug);
189               
190                int bytesRead = 0;
191                int blocksRead = 0;
192                int position;
193                int blocks;
194
195                // get number of blocks
196                if (((int)inputbytes % 8) == 0)
197                {
198                    blocks = (int)inputbytes / 8;
199                }
200                else
201                {
202                    blocks = (int)Math.Round(inputbytes / 8 + 0.4, 0) + 1;
203                }
204
205                byte[] inputbuffer = new byte[8 * blocks];
206                byte[] outputbuffer = new byte[4];
207                GuiLogMessage("# of blocks: " + blocks.ToString(), NotificationLevel.Debug);
208
209                //read input
210                //GuiLogMessage("Current position: " + inputStream.Position.ToString(), NotificationLevel.Debug);
211                for (blocksRead = 0; blocksRead <= blocks - 1; blocksRead++)
212                {
213                    for (position = bytesRead; position <= (blocksRead * 8 + 7); position++)
214                    {
215                        // no padding to do
216                        if (position < inputbytes)
217                        {
218                            inputbuffer[position] = (byte)inputStream.ReadByte();
219                        }
220                        else // padding to do!
221                        {
222                            if (padding == 0)
223                            {
224                                // padding with zeros
225                                inputbuffer[position] = 48; 
226                            }
227                            else if (padding == 2)
228                            {
229                                // padding with PKCS7
230                                int temp = 8 - (int)inputbytes % 8 + 48;
231                                inputbuffer[position] = (byte)temp;
232                            }
233                            else
234                            {
235                                // no padding
236                                inputbuffer[position] = (byte)inputStream.ReadByte();
237                                GuiLogMessage("Byte is: " + inputbuffer[position].ToString(), NotificationLevel.Info);
238                            }
239                        }
240                        bytesRead++;
241                        //GuiLogMessage("Current position: " + inputStream.Position.ToString(), NotificationLevel.Debug);
242                        //GuiLogMessage("Content of buffer[" + position + "]: " + buffer[position].ToString(), NotificationLevel.Debug);
243                    }
244                }
245
246                //GuiLogMessage("vector[0] before coding: " + vector[0].ToString(), NotificationLevel.Debug);
247                //GuiLogMessage("vector[1] before coding: " + vector[1].ToString(), NotificationLevel.Debug);
248
249                uint[] key = new uint[4];
250                long[] longKey = new long[4];
251                long keybytes = inputKey.Length;
252                GuiLogMessage("inputKey length [byte]: " + keybytes.ToString(), NotificationLevel.Debug);
253
254                if (keybytes != 16)
255                {
256                    GuiLogMessage("Given key has false length. Please provide a key with 128 Bits length. Aborting now.", NotificationLevel.Error);
257                    return;
258                }
259                else
260                {
261                    if (settings.Version != 2)
262                    {
263                        key[0] = BitConverter.ToUInt32(inputKey, 0);
264                        key[1] = BitConverter.ToUInt32(inputKey, 4);
265                        key[2] = BitConverter.ToUInt32(inputKey, 8);
266                        key[3] = BitConverter.ToUInt32(inputKey, 12);
267                    }
268                    else
269                    {
270                        longKey[0] = (long)BitConverter.ToUInt32(inputKey, 0);
271                        longKey[1] = (long)BitConverter.ToUInt32(inputKey, 4);
272                        longKey[2] = (long)BitConverter.ToUInt32(inputKey, 8);
273                        longKey[3] = (long)BitConverter.ToUInt32(inputKey, 12);
274                    }
275                }
276
277                //encryption or decryption
278                //GuiLogMessage("Action is: " + action, NotificationLevel.Debug);
279                DateTime startTime = DateTime.Now;
280               
281                uint[] vector = new uint[2];
282                long[] longVector = new long[2];
283
284                if (action == 0)
285                {
286                    GuiLogMessage("Starting encryption [Keysize=128 Bits, Blocksize=64 Bits]", NotificationLevel.Info);
287                    for (int i = 0; i <= blocks-1; i++)
288                    {
289                        vector[0] = BitConverter.ToUInt32(inputbuffer, (i * 8));
290                        vector[1] = BitConverter.ToUInt32(inputbuffer, (i * 8 + 4));
291
292                        // see in settings which version of TEA to use
293                        if (settings.Version == 0)
294                        {
295                            encode_tea(vector, key);
296                            StatusChanged((int)TEAImage.Encode);
297                        }
298                        else if (settings.Version == 1)
299                        {
300                            encode_xtea((uint)settings.Rounds, vector, key);
301                            StatusChanged((int)TEAImage.EncodeX);
302                        }
303                        else if (settings.Version == 2)
304                        {
305                            btea(vector, 2, key);
306                            StatusChanged((int)TEAImage.EncodeX);
307                        }
308
309                        //write buffer to output stream
310                        outputbuffer = BitConverter.GetBytes(vector[0]);
311                        outputStream.Write(outputbuffer, 0, 4);
312                        outputbuffer = BitConverter.GetBytes(vector[1]);
313                        outputStream.Write(outputbuffer, 0, 4);
314                    }
315                } else if (action == 1) {
316                    GuiLogMessage("Starting decryption [Keysize=128 Bits, Blocksize=64 Bits]", NotificationLevel.Info);
317                    for (int i = 0; i <= blocks-1; i++)
318                    {
319                        vector[0] = BitConverter.ToUInt32(inputbuffer, i * 8);
320                        vector[1] = BitConverter.ToUInt32(inputbuffer, i * 8 + 4);
321
322                        // see in settings which version of TEA to use
323                        if (settings.Version == 0)
324                        {
325                            decode_tea(vector, key);
326                            StatusChanged((int)TEAImage.Decode);
327                        }
328                        else if (settings.Version == 1)
329                        {
330                            decode_xtea((uint)settings.Rounds, vector, key);
331                            StatusChanged((int)TEAImage.DecodeX);
332                        }
333                        else if (settings.Version == 2)
334                        {
335                            btea(vector, -2, key);
336                            StatusChanged((int)TEAImage.DecodeX);
337                        }
338
339                        //write buffer to output stream
340                        outputbuffer = BitConverter.GetBytes(vector[0]);
341                        outputStream.Write(outputbuffer, 0, 4);
342                        outputbuffer = BitConverter.GetBytes(vector[1]);
343                        outputStream.Write(outputbuffer, 0, 4);
344                    }
345                }
346
347                //GuiLogMessage("vector[0] after coding: " + vector[0], NotificationLevel.Debug);
348                //GuiLogMessage("vector[1] after coding: " + vector[1], NotificationLevel.Debug);
349
350                /*while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0 && !stop)
351                {
352                    outputStream.Write(buffer, 0, bytesRead);
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                long outbytes = outputStream.Length;
361                DateTime stopTime = DateTime.Now;
362                TimeSpan duration = stopTime - startTime;
363                //(outputStream as CryptoolStream).FinishWrite();
364
365                if (!stop)
366                {
367                    if (action == 0)
368                    {
369                        GuiLogMessage("Encryption complete! (in: " + inputStream.Length.ToString() + " bytes, out: " + outbytes.ToString() + " bytes)", NotificationLevel.Info);
370                    }
371                    else
372                    {
373                        GuiLogMessage("Decryption complete! (in: " + inputStream.Length.ToString() + " bytes, out: " + outbytes.ToString() + " bytes)", NotificationLevel.Info);
374                    }
375                    GuiLogMessage("Wrote data to file: " + outputStream.FileName, NotificationLevel.Debug);
376                    GuiLogMessage("Time used: " + duration.ToString(), NotificationLevel.Debug);
377                    outputStream.Close();
378                    OnPropertyChanged("OutputStream");
379                }
380
381                if (stop)
382                {
383                    outputStream.Close();
384                    GuiLogMessage("Aborted!", NotificationLevel.Info);
385                }
386            }
387            /*catch (CryptographicException cryptographicException)
388            {
389                // TODO: For an unknown reason p_crypto_stream can not be closed after exception.
390                // Trying so makes p_crypto_stream throw the same exception again. So in Dispose
391                // the error messages will be doubled.
392                // As a workaround we set p_crypto_stream to null here.
393                p_crypto_stream = null;
394                //GuiLogMessage(cryptographicException.Message, NotificationLevel.Error);
395            }*/
396            catch (Exception exception)
397            {
398                GuiLogMessage(exception.Message, NotificationLevel.Error);
399            }
400            finally
401            {
402                ProgressChanged(1, 1);
403            }
404        }
405
406        private void encode_tea(uint[] v, uint[] k)
407        {
408            uint y = v[0];
409            uint z = v[1];
410
411            uint k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
412
413            uint sum = 0;
414            uint delta = 0x9e3779b9;
415            uint n = 64;
416
417            while (n-- > 0)
418            {
419                /*
420                 sum += delta;
421                 v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
422                 v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
423                */
424                sum += delta;
425                y += ((z << 4) + k0) ^ (z + sum) ^ ((z >> 5) + k1);
426                z += ((y << 4) + k2) ^ (y + sum) ^ ((y >> 5) + k3);
427            }
428
429            v[0] = y;
430            v[1] = z;
431        }
432
433        private void decode_tea(uint[] v, uint[] k)
434        {
435            uint n = 64;
436            uint sum = 0x8DDE6E40; // for 64 rounds, for 32 rounds it would be 0xC6EF3720
437
438            uint k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
439            uint y = v[0];
440            uint z = v[1];
441            uint delta = 0x9e3779b9;
442
443            while (n-- > 0)
444            {
445                /*
446                 v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
447                 v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
448                 sum -= delta;
449                */
450                z -= ((y << 4) + k2) ^ (y + sum) ^ ((y >> 5) + k3);
451                y -= ((z << 4) + k0) ^ (z + sum) ^ ((z >> 5) + k1);
452                sum -= delta;
453            }
454
455            v[0] = y;
456            v[1] = z;
457        }
458
459        private void encode_xtea(uint rounds, uint[] v, uint[] k)
460        {
461            uint y = v[0];
462            uint z = v[1];
463
464            uint sum = 0;
465            uint delta = 0x9e3779b9;
466            uint n = rounds;
467
468            while (n-- > 0)
469            {
470                y += (z << 4 ^ z >> 5) + z ^ sum + k[sum & 3];
471                sum += delta;
472                z += (y << 4 ^ y >> 5) + y ^ sum + k[sum >> 11 & 3];
473            }
474
475            v[0] = y;
476            v[1] = z;
477        }
478
479        private void decode_xtea(uint rounds, uint[] v, uint[] k)
480        {
481            uint n = rounds;
482            uint sum;
483            uint y = v[0];
484            uint z = v[1];
485            uint delta = 0x9e3779b9;
486
487            sum = delta * n;
488
489            while (n-- > 0)
490            {
491                z -= (y << 4 ^ y >> 5) + y ^ sum + k[sum >> 11 & 3];
492                sum -= delta;
493                y -= (z << 4 ^ z >> 5) + z ^ sum + k[sum & 3];
494            }
495
496            v[0] = y;
497            v[1] = z;
498        }
499
500        private uint btea(uint[] v, int n, uint[] k) {
501            int m = n;
502            if (n < -1) m = -n;
503            uint z=v[m-1], y=v[0], sum=0, e, DELTA=0x9e3779b9;
504           
505            int p, q;
506
507            uint MX;
508
509            if (n > 1) {          /* Coding Part */
510              q = 6 + 52/n;
511              while (q-- > 0) {
512                sum += DELTA;
513                e = (sum >> 2) & 3;
514                for (p=0; p<n-1; p++) {
515                    y = v[p+1];
516                    MX = (z>>5^y<<2) + (y>>3^z<<4)^(sum^y) + (k[p&3^e]^z);
517                    z = v[p] += MX;
518                }
519                y = v[0];
520                GuiLogMessage("y: " + y.ToString("X"), NotificationLevel.Info);
521                MX = (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
522                z = v[n-1] += MX;
523                GuiLogMessage("z: " + z.ToString("X"), NotificationLevel.Info);
524              }
525
526              GuiLogMessage("v[n-1]: " + v[n - 1].ToString("X"), NotificationLevel.Info);
527              GuiLogMessage("v[0]: " + v[0].ToString("X"), NotificationLevel.Info);
528
529              return 0 ; 
530            } else if (n < -1) {  /* Decoding Part */
531              n = -n;
532              q = 6 + 52/n;
533              sum = (uint)q*DELTA ;
534              while (sum != 0) {
535                e = (sum >> 2) & 3;
536                for (p = n - 1; p > 0; p--)
537                {
538                    z = v[p - 1];
539                    MX = (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
540                    y = v[p] -= MX;
541                }
542                z = v[n - 1];
543                MX = (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
544                y = v[0] -= MX;
545                sum -= DELTA;
546              }
547              return 0;
548            }
549            return 1;
550        }
551
552
553        public void Encrypt()
554        {
555            //Encrypt Stream
556            process(0, settings.Padding);
557        }
558
559        public void Decrypt()
560        {
561            //Decrypt Stream
562            process(1, settings.Padding);
563        }
564
565        public void Initialize()
566        {
567        }
568
569        public event StatusChangedEventHandler OnPluginStatusChanged;
570
571        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
572        private void GuiLogMessage(string message, NotificationLevel logLevel)
573        {
574            EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(message, this, logLevel));
575        }
576
577        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
578        private void ProgressChanged(double value, double max)
579        {
580            EventsHelper.ProgressChanged(OnPluginProgressChanged, this, new PluginProgressEventArgs(value, max));
581        }
582
583        public void Pause()
584        {
585        }
586
587        public void PostExecution()
588        {
589            Dispose();
590        }
591
592        public void PreExecution()
593        {
594            Dispose();
595        }
596
597        public UserControl Presentation
598        {
599            get { return null; }
600        }
601
602        public UserControl QuickWatchPresentation
603        {
604            get { return null; }
605        }
606
607        public void Stop()
608        {
609            this.stop = true;
610        }
611
612        #region INotifyPropertyChanged Members
613
614        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
615
616        public void OnPropertyChanged(string name)
617        {
618            EventsHelper.PropertyChanged(PropertyChanged, this, new PropertyChangedEventArgs(name));
619            /*if (PropertyChanged != null)
620            {
621              PropertyChanged(this, new PropertyChangedEventArgs(name));
622            }*/
623        }
624
625        private void StatusChanged(int imageIndex)
626        {
627            EventsHelper.StatusChanged(OnPluginStatusChanged, this, new StatusEventArgs(StatusChangedMode.ImageUpdate, imageIndex));
628        }
629
630        #endregion
631    }
632
633    enum TEAImage
634    {
635        Default,
636        Encode,
637        Decode,
638        EncodeX,
639        DecodeX
640    }
641}
Note: See TracBrowser for help on using the repository browser.