source: trunk/CrypPlugins/RSA/RSA.cs @ 749

Last change on this file since 749 was 749, checked in by kopal, 12 years ago

Some spelling corrections in RSA

File size: 17.8 KB
Line 
1/*                             
2   Copyright 2009 Team CrypTool (Sven Rech,Dennis Nolte,Raoul Falk,Nils Kopal), Uni Duisburg-Essen
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;
21using Cryptool.PluginBase.Cryptography;
22using Cryptool.PluginBase;
23using Cryptool.PluginBase.Miscellaneous;
24using System.ComponentModel;
25using System.Security.Cryptography;
26using System.Threading;
27using System.Collections;
28
29namespace Cryptool.Plugins.RSA
30{
31    [Author("Dennis Nolte, Raoul Falk, Sven Rech, Nils Kopal", null, "Uni Duisburg-Essen", "http://www.uni-due.de")]
32    [PluginInfo(false, "RSA", "RSA En/Decryption", "", "RSA/iconrsa.png", "RSA/Images/encrypt.png", "RSA/Images/decrypt.png")]
33    [EncryptionType(EncryptionType.Asymmetric)]
34    /// <summary>
35    /// This plugin does a RSA encryption/decryption on a Message M / Ciphertext C
36    /// It also encrypts/decrypts text with RSA
37    /// </summary>
38    class RSA : IEncryption
39    {
40        #region private members
41
42        private RSASettings settings = new RSASettings();
43        private BigInteger inputN = new BigInteger(1);
44        private BigInteger inputmc = new BigInteger(1);
45        private BigInteger inputed = new BigInteger(1);
46        private BigInteger outputmc = new BigInteger(1);
47        private byte[] inputText = null;
48        private byte[] outputText = null;
49        private int blocks_done = 0;
50        private ArrayList threads;
51        private bool stopped = true;
52
53        #endregion
54
55        #region events
56
57        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
58        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
59        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
60        public event StatusChangedEventHandler OnPluginStatusChanged;
61
62        #endregion
63
64        #region public
65       
66        /// <summary>
67        /// Notify that a property changed
68        /// </summary>
69        /// <param name="name">property name</param>
70        public void OnPropertyChanged(string name)
71        {
72            EventsHelper.PropertyChanged(PropertyChanged, this, new PropertyChangedEventArgs(name));
73        }
74
75        /// <summary>
76        /// Gets/Sets the Settings of this plugin
77        /// </summary>
78        public ISettings Settings
79        {
80            get { return this.settings; }
81            set { this.settings = (RSASettings)value; }
82        }
83
84        /// <summary>
85        /// Get the Presentation of this plugin
86        /// </summary>
87        public System.Windows.Controls.UserControl Presentation
88        {
89            get { return null; }
90        }
91
92        /// <summary>
93        /// Get the QuickWatchRepresentation of this plugin
94        /// </summary>
95        public System.Windows.Controls.UserControl QuickWatchPresentation
96        {
97            get { return null; }
98        }
99
100        /// <summary>
101        /// Called by the environment before execution
102        /// </summary>
103        public void PreExecution()
104        {
105            stopped = false;
106        }
107
108        /// <summary>
109        /// Called by the environment to execute this plugin
110        /// Does RSA on M/C and encrypt/decrypt the input Text
111        /// This method starts threads to speed RSA up if the user switched on more than one
112        /// thread
113        /// </summary>
114        public void Execute()
115        {
116           
117            //calculate the BigIntegers
118            try{
119                if (this.InputN is object && this.InputED is object && this.InputMC is object && !stopped)   
120                    this.OutputMC = InputMC.modPow(this.InputED, this.InputN);
121            }
122            catch (Exception ex)
123            {
124                GuiLogMessage("RSA could not work because of: " + ex.Message, NotificationLevel.Error);             
125            }
126
127            //
128            // RSA on Texts
129            //
130            if (this.InputText is object && this.InputN is object && this.InputED is object && !stopped)
131            {
132                DateTime startTime = DateTime.Now;
133                GuiLogMessage("starting RSA on texts", NotificationLevel.Info);
134
135                threads = ArrayList.Synchronized(new ArrayList());
136                int blocksize_input = 0;
137                int blocksize_output = 0;
138
139                //calculate block sizes from N         
140                //Encryption
141                if (settings.Action == 0)
142                {
143                    blocksize_input = (int)Math.Floor(this.InputN.log(256));
144                    blocksize_output = (int)Math.Ceiling(this.InputN.log(256));
145                }
146                //Decryption
147                else
148                {
149                    blocksize_input = (int)Math.Ceiling(this.InputN.log(256));
150                    blocksize_output = (int)Math.Floor(this.InputN.log(256));
151                }
152
153                GuiLogMessage("Input blocksize = " + blocksize_input, NotificationLevel.Debug);
154                GuiLogMessage("Output blocksize = " + blocksize_output, NotificationLevel.Debug);
155               
156                if (blocksize_input == 0)
157                {
158                    GuiLogMessage("Input blocksize 0 - RSA can not work", NotificationLevel.Error);
159                    return;
160                }
161
162                if (blocksize_output == 0)
163                {
164                    GuiLogMessage("Input blocksize 0 - RSA can not work", NotificationLevel.Error);
165                    return;
166                }
167
168                //calculate amount of blocks and the difference between the input text
169                //and the blocked input text
170                int blockcount = (int)Math.Ceiling((double)this.InputText.Length / blocksize_input);               
171               
172                GuiLogMessage("Blockcount = " + blockcount, NotificationLevel.Debug);
173               
174                //Generate input and output array of correct block size
175                byte[] output = new byte[blocksize_output * blockcount];
176                blocks_done = 0;
177
178                for (int i = 1; i < this.settings.CoresUsed + 1;i++ ) // CoresUsed starts with 0 (so 0 => use 1 Core)
179                {
180                    ParameterizedThreadStart pts = new ParameterizedThreadStart(this.crypt);
181                    Thread thread = new Thread(pts);
182                    thread.Name = "RSA worker thread " + i;
183                    threads.Add(thread);
184                    thread.Start(new Object[6] { output, blockcount, blocksize_input, blocksize_output, i, thread});
185                    GuiLogMessage("started: " + thread.Name, NotificationLevel.Debug);
186
187                    if (stopped)
188                        return;
189
190                }//end for
191
192                //main thread should work also
193                crypt(new Object[6] { output, blockcount, blocksize_input, blocksize_output, 0, null });
194
195                //Wait for all worker threads to stop
196                //Worker threads will be removed by themselves from the list
197                //in finally block
198                while (threads.Count != 0)
199                {
200                    if (stopped)
201                        return;
202
203                    Thread.Sleep(0);
204                }
205
206                ProgressChanged(1.0, 1.0);
207                output = removeZeros(output);
208                this.OutputText = output;
209
210                DateTime stopTime = DateTime.Now;
211                TimeSpan duration = stopTime - startTime;
212
213                GuiLogMessage("finished RSA on texts in " + duration, NotificationLevel.Info);
214
215            }//end if           
216
217        }//end Execute
218
219        /// <summary>
220        /// Called by the environment after execution of this plugin
221        /// </summary>
222        public void PostExecution()
223        {
224            this.stopped = true;
225        }
226
227        /// <summary>
228        /// Called by the environment to pause this plugin
229        /// </summary>
230        public void Pause()
231        {
232        }
233
234        /// <summary>
235        /// Called by the environment to stop this plugin
236        /// </summary>
237        public void Stop()
238        {
239            this.stopped = true;
240        }
241
242        /// <summary>
243        /// Called by the environment to initialize this plugin
244        /// </summary>
245        public void Initialize()
246        {
247            this.stopped = true;
248        }
249
250        /// <summary>
251        /// Called by the environment to Dispose this plugin
252        /// </summary>
253        public void Dispose()
254        {
255
256        }
257
258        /// <summary>
259        /// Gets/Sets the one part of the public/private key called N
260        /// </summary>
261        [PropertyInfo(Direction.InputData, "Public key / private Key N input", "Enter your public key / private key N here", "", DisplayLevel.Beginner)]
262        public BigInteger InputN
263        {
264            get
265            {
266                return inputN;
267            }
268            set
269            {
270                this.inputN = value;
271                OnPropertyChanged("InputN");
272            }
273        }
274
275        /// <summary>
276        /// Gets/Sets a input message/ciphertext as BigInteger called M / C
277        /// </summary>
278        [PropertyInfo(Direction.InputData, "Message M / ciphertext C input", "Enter your message M / ciphertext C here", "", DisplayLevel.Beginner)]
279        public BigInteger InputMC
280        {
281            get
282            {
283                return inputmc;
284            }
285            set
286            {
287                this.inputmc = value;
288                OnPropertyChanged("InputMC");
289            }
290        }
291
292        /// <summary>
293        /// Gets/Sets the one part of the public/private key called E / D
294        /// </summary>
295        [PropertyInfo(Direction.InputData, "Public key E / private key D input", "Enter your public key E / private key D here", "", DisplayLevel.Beginner)]
296        public BigInteger InputED
297        {
298            get
299            {
300                return inputed;
301            }
302            set
303            {
304                this.inputed = value;
305                OnPropertyChanged("InputED");
306            }
307        }
308
309        /// <summary>
310        /// Gets/Sets a output message/ciphertext as BigInteger called C / M
311        /// </summary>
312        [PropertyInfo(Direction.OutputData, "Cipher C output / message M output", "Your cipher C / message M will be send here", "", DisplayLevel.Beginner)]
313        public BigInteger OutputMC
314        {
315            get
316            {
317                return outputmc;
318            }
319            set
320            {
321                this.outputmc = value;
322                OnPropertyChanged("OutputMC");
323            }
324        }
325
326        /// <summary>
327        /// Gets/Sets a text input for encryption/decryption
328        /// </summary>
329        [PropertyInfo(Direction.InputData, "Text input", "Enter your text here", "", DisplayLevel.Beginner)]
330        public byte[] InputText
331        {
332            get
333            {
334                return inputText;
335            }
336            set
337            {
338                this.inputText = value;
339                //GuiLogMessage("InputText: " + (int)inputText[0] + " " + (int)inputText[1] + " " + (int)inputText[2] + " " + (int)inputText[3] + " ", NotificationLevel.Info);
340                OnPropertyChanged("InputText");
341            }
342        }
343
344        /// <summary>
345        /// Gets/Sets a text output for encrypted/decrypted data
346        /// </summary>       
347        [PropertyInfo(Direction.OutputData, "Text output", "Your text will be send here", "", DisplayLevel.Beginner)]
348        public byte[] OutputText
349        {
350            get
351            {
352                return outputText;
353            }
354            set
355            {
356                this.outputText = value;
357                //GuiLogMessage("OutputText: " + (int)outputText[0] + " " +(int)outputText[1] + " "+(int)outputText[2] + " "+(int)outputText[3] + " ", NotificationLevel.Info);
358                OnPropertyChanged("OutputText");
359            }
360        }
361
362        #endregion
363
364        #region private
365
366        /// <summary>
367        /// Encrypts/Decrypts all blocks belonging to the thread nr
368        /// </summary>
369        /// <param name="parameters">parameters</param>
370        private void crypt(Object parameters)
371        {
372            byte[] output = (byte[])((Object[])parameters)[0];
373            int blockcount = (int)((Object[])parameters)[1];
374            int blocksize_input = (int)((Object[])parameters)[2];
375            int blocksize_output = (int)((Object[])parameters)[3];
376            int threadnr = (int)((Object[])parameters)[4];
377            Thread thread = (Thread)((Object[])parameters)[5];
378
379            try
380            {
381
382                BigInteger bint = new BigInteger();
383               
384                //encrypt/decrypt each block
385                for (int i = threadnr; i < blockcount; i += (this.settings.CoresUsed + 1)) //walk over the blocks
386                // CoresUsed starts with 0 (so 0 => use 1 Core)
387                {
388
389                    //create a big integer from a block
390                    byte[] help = new byte[blocksize_input];
391                    for (int j = 0; j < blocksize_input; j++)
392                    {
393                        if (i * blocksize_input + j < InputText.Length)
394                            help[j] = InputText[i * blocksize_input + j];
395                        if (stopped)
396                            return;
397
398                    }
399                    bint = new BigInteger(help);
400
401                    //Check if the text could be encrypted/decrypted
402                    //this is only possible if the m < N
403                    if (bint > this.InputN)
404                    {
405                        //Go out with an error because encryption/decryption is not possible
406                        GuiLogMessage("N = " + this.InputN + " is not suitable for encrypting this text: M = " + new BigInteger(help) + " > N. Please choose another pair of primes!", NotificationLevel.Error);
407                        return;
408                    }
409
410                    //here we encrypt/decrypt with rsa algorithm
411                    bint = bint.modPow(this.InputED, this.InputN);
412
413                    //create a block from the byte array of the BigInteger
414                    byte[] bytes = bint.getBytes();
415                    int diff = (blocksize_output - (bytes.Length % blocksize_output)) % blocksize_output;
416
417                    for (int j = 0; j < bytes.Length; j++)
418                    {
419                        output[i * blocksize_output + j + diff] = bytes[j];
420                        if (stopped)
421                            return;
422                    }
423
424                    if (stopped)
425                        return;
426
427                    blocks_done++;
428                    ProgressChanged((double)blocks_done / blockcount, 1.0);
429
430                }//end for i
431            }
432            finally
433            {
434                //remove thread from list so that main thread will stop
435                //if all threads are removed
436                if (this.threads != null && thread != null){
437                    threads.Remove(thread);
438                    GuiLogMessage("stopped: " + thread.Name, NotificationLevel.Debug);
439                }
440            }
441
442        }//end crypt
443       
444        /// <summary>
445        /// Remove all '0' from a byte arrays end
446        /// example
447        ///
448        /// { 'a','b','c',0,0 } => { 'a','b','c' }
449        /// </summary>
450        /// <param name="input">byte array</param>
451        /// <returns>byte array</returns>
452        private byte[] removeZeros(byte[] input)
453        {
454            //1. Count zeros
455            int zeros = 0;
456            for (int i=input.Length-1;i>0;i--){
457
458                if (input[i] == 0)
459                {
460                    zeros++;
461                }
462                else
463                {
464                    break;
465                }
466
467            }
468
469            //2. Create new smaller byte array with
470            byte[] output = new byte[input.Length - zeros];
471
472            //3. Copy from input array beginning at the first byte <> 0 to the output array
473            for (int i = 0; i < input.Length - zeros; i++)
474            {
475                output[i] = input[i];
476            }
477
478            return output;
479        }
480
481        /// <summary>
482        /// Change the progress of this plugin
483        /// </summary>
484        /// <param name="value">value</param>
485        /// <param name="max">max</param>
486        private void ProgressChanged(double value, double max)
487        {
488            EventsHelper.ProgressChanged(OnPluginProgressChanged, this, new PluginProgressEventArgs(value, max));
489        }
490
491        /// <summary>
492        /// Logg a message to cryptool
493        /// </summary>
494        /// <param name="p">p</param>
495        /// <param name="notificationLevel">notificationLevel</param>
496        private void GuiLogMessage(string p, NotificationLevel notificationLevel)
497        {
498            EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(p, this, notificationLevel));
499        }
500
501        #endregion
502
503    }//end rsa
504
505}//end namespace
Note: See TracBrowser for help on using the repository browser.