source: trunk/CrypPlugins/Enigma/EnigmaCore.cs @ 2801

Last change on this file since 2801 was 2801, checked in by weyers, 11 years ago

EnigmaPresentation - EnigmaSettings synchronisation, EnigmaPresentation input management updated

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to URL Author Date Rev Id
File size: 15.7 KB
Line 
1/*
2   Copyright 2008 Dr. Arno Wacker, University of 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;
21
22//Cryptool 2.0 specific includes
23using Cryptool.PluginBase;
24using Cryptool.PluginBase.Miscellaneous;
25using System.Diagnostics;
26
27
28namespace Cryptool.Enigma
29{
30
31    internal partial class EnigmaCore
32    {
33
34        #region Private structs/classes
35
36        private struct internalConfigStruct
37        {
38            public string PlugBoard;
39            public int Rotor1;
40            public int Rotor2;
41            public int Rotor3;
42            public int Rotor4;
43            public int Reflector;
44            public int Rotor1pos;
45            public int Rotor2pos;
46            public int Rotor3pos;
47            public int Rotor4pos;
48            public int Ring1pos;
49            public int Ring2pos;
50            public int Ring3pos;
51            public int Ring4pos;
52        }
53
54        #endregion
55
56        #region Private member variables
57
58        private Enigma pluginFacade;
59        private EnigmaSettings settings;
60
61        private internalConfigStruct iCfg;
62
63        private string rotor1For, rotor2For, rotor3For, rotor4For; // forward susbstitution strings for the rotors   
64        private string rotor1Rev, rotor2Rev, rotor3Rev, rotor4Rev; // reverse susbstitution strings for the rotors
65        private string reflector;
66
67        string rotor1notches, rotor2notches, rotor3notches; // rotor notches
68
69
70        #endregion
71
72        #region Properties
73
74        public string Key
75        { 
76            get {return currentKeyString();} 
77        }
78
79        public string Plugs { get { return getPlugs(); } }
80
81        public string Plugboard { get { return iCfg.PlugBoard; } }
82
83        public int Ring1 { get { return iCfg.Ring1pos; } }
84        public int Ring2 { get { return iCfg.Ring2pos; } }
85        public int Ring3 { get { return iCfg.Ring3pos; } }
86        public int Ring4 { get { return iCfg.Ring4pos; } }
87
88        public int Rotor1 { get { return iCfg.Rotor1; } }
89        public int Rotor2 { get { return iCfg.Rotor2; } }
90        public int Rotor3 { get { return iCfg.Rotor3; } }
91        public int Rotor4 { get { return iCfg.Rotor4; } }
92
93        public VerboseLevels VerboseLevel { get; set; }
94
95        #endregion
96
97        public EnigmaCore(Enigma facade)
98        {
99            pluginFacade = facade;
100            settings = (EnigmaSettings)pluginFacade.Settings;
101            iCfg = new internalConfigStruct();
102        }
103
104
105        /// <summary>
106        /// Encrypts or decrypts a string with the given key (rotor positions)
107        /// Unknown symbols are ignored (=retuned unchanged) and case is preserved.
108        /// </summary>
109        /// <param name="rotor1Pos">Position of rotor 1 (fastest)</param>
110        /// <param name="rotor2Pos">Position of rotor 2 (middle)</param>
111        /// <param name="rotor3Pos">Position of rotor 3 (slowest)</param>
112        /// <param name="rotor4Pos">Position of rotor 4 (extra rotor for M4)</param>
113        /// <param name="input">The text for en/decryption. All letters which are not in the alphabet are returned unprocessed.</param>
114        /// <returns>The encrypted/decrypted string</returns>
115        public string Encrypt(int rotor1Pos, int rotor2Pos, int rotor3Pos, int rotor4Pos, string input)
116        {
117
118            if (!Stopwatch.IsHighResolution)
119                logMessage("No high resolution timer available. Time measurements will be inaccurate!", NotificationLevel.Warning);
120
121
122            // Start the stopwatch
123            Stopwatch sw = Stopwatch.StartNew();
124
125            // set the current key, i.e. the rotor positions
126            iCfg.Rotor1pos = rotor1Pos;
127            iCfg.Rotor2pos = rotor2Pos;
128            iCfg.Rotor3pos = rotor3Pos;
129            iCfg.Rotor4pos = rotor4Pos;
130
131            // now perform the enigma operation for each character
132            char[] result = new char[input.Length];
133
134            for (int i = 0; i < input.Length; i++)
135            {
136                result[i] = enigmacrypt(input[i]);
137
138                //update the status, if we are not in anylzing mode
139                // this must be deactivated during analysis, since it takes a lot of time
140                if (settings.Action == 0 && !pluginFacade.Presentation.IsVisible)
141                    pluginFacade.ShowProgress(i, input.Length);
142            }
143
144            // Stop the stopwatch
145            sw.Stop();
146
147            // Print some info on the console, if not in analyzing mode.
148            if (settings.Action == 0)
149                logMessage(String.Format("Enigma processing done! Processed {0} characters in {1} ms!", input.Length, sw.ElapsedMilliseconds), NotificationLevel.Info);
150
151            return new string(result);
152        }
153
154        /// <summary>
155        /// This method set the internal configuration of the enigma, i.e.
156        /// The used rotors, their ring position and the current plugboard substitution
157        /// </summary>
158        /// <param name="rotor1">The rightmost (fastest) rotor</param>
159        /// <param name="rotor2">The middle rotor</param>
160        /// <param name="rotor3">The leftmost (slowest) rotor</param>
161        /// <param name="rotor4">The extra rotor for the M4</param>
162        /// <param name="ring1Pos">The ring position for the rightmost (fastest) rotor</param>
163        /// <param name="ring2Pos">The ring position for the middle rotor</param>
164        /// <param name="ring3Pos">The ring position for the leftmost (slowest) rotor</param>
165        /// <param name="ring4Pos">The ring position for the extra rotor for the M4</param>
166        /// <param name="plugBoard">An alphabet string providing the substitution given by the Plugboard</param>
167        public void setInternalConfig(int rotor1, int rotor2, int rotor3, int rotor4,
168            int refl,
169            int ring1Pos, int ring2Pos, int ring3Pos, int ring4Pos, string plugBoard)
170        {
171            //set the internal config elements
172            iCfg.Rotor1 = rotor1;
173            iCfg.Rotor2 = rotor2;
174            iCfg.Rotor3 = rotor3;
175            iCfg.Rotor4 = rotor4;
176
177            iCfg.Reflector = refl;
178
179            iCfg.Ring1pos = ring1Pos;
180            iCfg.Ring2pos = ring2Pos;
181            iCfg.Ring3pos = ring3Pos;
182            iCfg.Ring4pos = ring4Pos;
183
184            iCfg.PlugBoard = plugBoard;
185
186
187            logMessage(String.Format("Setting internal config to Rotors: {0},{1},{2}; Rings: {3},{4},{5}; Reflector: {6}; Plugboard: \"{7}\"",
188                (rotorEnum)iCfg.Rotor3, (rotorEnum)iCfg.Rotor2, (rotorEnum)iCfg.Rotor1, 
189                iCfg.Ring3pos, iCfg.Ring2pos, iCfg.Ring1pos, 
190                (reflectorEnum)iCfg.Reflector, 
191                getPlugs()), NotificationLevel.Info);
192
193
194            ///////////////////////////////////////
195            // now prepare everything for operation
196            ///////////////////////////////////////
197
198            // prepare the current string for the forward substitution. We use a the string 3-times,
199            // since this saves some alphabet wrap-arround checking
200            rotor1For = rotors[settings.Model, iCfg.Rotor1] + rotors[settings.Model, iCfg.Rotor1] + rotors[settings.Model, iCfg.Rotor1];
201            rotor2For = rotors[settings.Model, iCfg.Rotor2] + rotors[settings.Model, iCfg.Rotor2] + rotors[settings.Model, iCfg.Rotor2];
202            rotor3For = rotors[settings.Model, iCfg.Rotor3] + rotors[settings.Model, iCfg.Rotor3] + rotors[settings.Model, iCfg.Rotor3];
203            if (iCfg.Rotor4 < 8)
204            {
205                rotor4For = rotors[settings.Model, iCfg.Rotor4] + rotors[settings.Model, iCfg.Rotor4] + rotors[settings.Model, iCfg.Rotor4];
206            }
207
208
209            if (settings.Model > 0) // the Enigma A/B did not have a reflector, hence there is no reverse substitution
210            {
211                // prepare the current string for the reflector
212                reflector = reflectors[settings.Model, iCfg.Reflector] + reflectors[settings.Model, iCfg.Reflector] + reflectors[settings.Model, iCfg.Reflector];
213
214                // prepare the current string for the reverse substitution.
215                rotor1Rev = generateReverseSubst(rotors[settings.Model, iCfg.Rotor1]);
216                rotor1Rev += rotor1Rev + rotor1Rev;
217                rotor2Rev = generateReverseSubst(rotors[settings.Model, iCfg.Rotor2]);
218                rotor2Rev += rotor2Rev + rotor2Rev;
219                rotor3Rev = generateReverseSubst(rotors[settings.Model, iCfg.Rotor3]);
220                rotor3Rev += rotor3Rev + rotor3Rev;
221                if (iCfg.Rotor4 < 8)
222                {
223                    rotor4Rev = generateReverseSubst(rotors[settings.Model, iCfg.Rotor4]);
224                    rotor4Rev += rotor4Rev + rotor4Rev;
225                }
226            }
227
228            // configure rotor notches - work in Progress, here only Enigma I/M3 is considered
229            rotor1notches = notches[iCfg.Rotor1];
230            rotor2notches = notches[iCfg.Rotor2];
231            rotor3notches = notches[iCfg.Rotor3];
232
233        }
234
235
236        /// <summary>
237        /// Generates the inverse substitution string for a given substitution
238        /// </summary>
239        /// <param name="p">The substitution string</param>
240        /// <returns>The reversed substitution string</returns>
241        private string generateReverseSubst(string p)
242        {
243            char[] result = new char[alen];
244
245            for (int i = 0; i < alen; i++)
246            {
247                result[i] = settings.Alphabet[p.IndexOf(settings.Alphabet[i])];
248            }
249
250            return new string(result);
251        }
252
253
254        /// <summary>
255        /// Encrypt one char at the time. Only letters from the alphabet are allowed.
256        /// This mast be taken care by the calling method. Illegal characters will lead
257        /// to exception!
258        /// </summary>
259        /// <param name="keypressed"></param>
260        /// <returns></returns>
261        private char enigmacrypt(char keypressed)
262        {
263            //1. Substitution with plugboard
264            char entrySubst = enigmaPlugBoard(keypressed);
265
266            //2. Spindle substitution
267            char spindleSubst = enigmaSpindle(entrySubst);
268
269            //3. Substitution with plugboard
270            return enigmaPlugBoard(spindleSubst);
271        }
272
273
274        /// <summary>
275        /// The method simulates the substition done by the plugboard of the Enigma.
276        /// This part provieds the monoalpahbetic substitution for the Enigma.
277        /// </summary>
278        /// <param name="c">The letter to be substituted.</param>
279        /// <returns>The substituted character</returns>
280        private char enigmaPlugBoard(char c)
281        {
282            return iCfg.PlugBoard[settings.AlphabetIndexOf(c)];
283        }
284
285
286        /// <summary>
287        /// This method simulated the substitution done by the rotors, i.e.
288        /// the spindle. This part provides the polyalphabetic substitution for the Enigma
289        /// </summary>
290        /// <param name="c"></param>
291        /// <returns></returns>
292        private char enigmaSpindle(char entrySubst)
293        {
294            char ch = entrySubst;
295
296            //check notches and update the rotor position
297            foreach (char n in rotor1notches)
298            {
299                if (settings.AlphabetIndexOf(n) == iCfg.Rotor1pos) iCfg.Rotor2pos = (iCfg.Rotor2pos + 1) % alen;
300            }
301
302            foreach (char n in rotor2notches)
303            {
304                int currentRotor2pos = iCfg.Rotor2pos;
305
306                if (settings.AlphabetIndexOf(n) == currentRotor2pos)
307                {
308                    iCfg.Rotor3pos = (iCfg.Rotor3pos + 1) % alen;
309                    iCfg.Rotor2pos = (iCfg.Rotor2pos + 1) % alen; // double-stepping, step of rotor 3 takes rotor 2 with it (and 1, but 1 steps anyway)
310                }
311            }
312
313            foreach (char n in rotor3notches)
314            {
315                if (settings.AlphabetIndexOf(n) == iCfg.Rotor3pos) iCfg.Rotor4pos = (iCfg.Rotor4pos + 1) % alen;
316            }
317
318            // Rotor 1 always steps
319            iCfg.Rotor1pos = (iCfg.Rotor1pos + 1) % alen;
320           
321           
322            // write back the updated rotor settings (only if not analyzing)
323            //if (settings.Action == 0)
324            //    settings.Key = currentKeyString();
325
326            //add the ring-offset
327            int rotor1Pos = iCfg.Rotor1pos - (iCfg.Ring1pos - 1); if (rotor1Pos < 0) rotor1Pos += alen;
328            int rotor2Pos = iCfg.Rotor2pos - (iCfg.Ring2pos - 1); if (rotor2Pos < 0) rotor2Pos += alen;
329            int rotor3Pos = iCfg.Rotor3pos - (iCfg.Ring3pos - 1); if (rotor3Pos < 0) rotor3Pos += alen;
330            //int rotor3Pos = (alen + iCfg.Rotor3pos - (iCfg.Ring3pos - 1)) % alen; // slower alternative
331
332            // now do the substitution
333            ch = A3[alen + settings.AlphabetIndexOf(rotor1For[alen + settings.AlphabetIndexOf(ch) + rotor1Pos]) - rotor1Pos];
334            ch = A3[alen + settings.AlphabetIndexOf(rotor2For[alen + settings.AlphabetIndexOf(ch) + rotor2Pos]) - rotor2Pos];
335            ch = A3[alen + settings.AlphabetIndexOf(rotor3For[alen + settings.AlphabetIndexOf(ch) + rotor3Pos]) - rotor3Pos];
336            ch = reflector[alen + settings.AlphabetIndexOf(ch)];
337            ch = A3[alen + settings.AlphabetIndexOf(rotor3Rev[alen + settings.AlphabetIndexOf(ch) + rotor3Pos]) - rotor3Pos];
338            ch = A3[alen + settings.AlphabetIndexOf(rotor2Rev[alen + settings.AlphabetIndexOf(ch) + rotor2Pos]) - rotor2Pos];
339            ch = A3[alen + settings.AlphabetIndexOf(rotor1Rev[alen + settings.AlphabetIndexOf(ch) + rotor1Pos]) - rotor1Pos];
340
341            return ch;
342        }
343
344
345        /// <summary>
346        /// Returns the current key as a string, i.e. the rotor positions in the settings pane
347        /// </summary>
348        private string currentKeyString()
349        {
350            char R1 = settings.Alphabet[iCfg.Rotor1pos];
351            char R2 = settings.Alphabet[iCfg.Rotor2pos];
352            char R3 = settings.Alphabet[iCfg.Rotor3pos];
353            char R4 = settings.Alphabet[iCfg.Rotor4pos];
354
355            string key = R3.ToString() + R2.ToString() + R1.ToString();
356
357            if (settings.Model == 4)
358                return R4 + key;
359            else
360                return key;
361        }
362
363        private string getPlugs()
364        {
365            StringBuilder result = new StringBuilder();
366
367            for (int i = 0; i < settings.Alphabet.Length; i++)
368                        {
369                if (settings.Alphabet[i] != iCfg.PlugBoard[i] && !result.ToString().Contains(settings.Alphabet[i]))
370                {
371                    if (result.Length > 0)
372                        result.Append(' ');
373
374                    result.Append(settings.Alphabet[i].ToString() + iCfg.PlugBoard[i].ToString());
375                }
376                        }
377
378            if (result.Length == 0)
379                result.Append("-- no plugs --");
380
381            return result.ToString();
382        }
383
384        private void logMessage(string msg, NotificationLevel lvl)
385        {
386            if ((int)lvl >= ((int)VerboseLevel - 1))
387            {
388                pluginFacade.LogMessage(msg, lvl);
389            }           
390        }
391    }
392}
Note: See TracBrowser for help on using the repository browser.