2004-09-16 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / corlib / System.Security.Cryptography / DESCryptoServiceProvider.cs
1 //
2 // System.Security.Cryptography.DESCryptoServiceProvider
3 //
4 // Authors:
5 //      Sergey Chaban (serge@wildwestsoftware.com)
6 //      Sebastien Pouliot (sebastien@ximian.com)
7 //
8 // Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using Mono.Security.Cryptography;
32
33 namespace System.Security.Cryptography {
34
35         // References:
36         // a.   FIPS PUB 46-3: Data Encryption Standard
37         //      http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
38         
39         internal class DESTransform : SymmetricTransform {
40         
41                 internal static readonly int KEY_BIT_SIZE = 64;
42                 internal static readonly int KEY_BYTE_SIZE = KEY_BIT_SIZE / 8;
43                 internal static readonly int BLOCK_BIT_SIZE = 64;
44                 internal static readonly int BLOCK_BYTE_SIZE = BLOCK_BIT_SIZE / 8;
45         
46                 private byte[] keySchedule;
47                 private byte[] byteBuff;
48                 private uint[] dwordBuff;
49         
50                 // S-boxes from FIPS 46-3, Appendix 1, page 17
51                 private static readonly byte [] sBoxes = {
52                                                 /* S1 */
53                         14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
54                         0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
55                         4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
56                         15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13,
57         
58                                                 /* S2 */
59                         15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
60                         3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
61                         0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
62                         13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9,
63         
64                                                 /* S3 */
65                         10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
66                         13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
67                         13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
68                         1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12,
69         
70                                                 /* S4 */
71                         7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
72                         13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
73                         10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
74                         3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14,
75         
76                                                 /* S5 */
77                         2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
78                         14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
79                         4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
80                         11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3,
81         
82                                                 /* S6 */
83                         12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
84                         10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
85                         9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
86                         4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13,
87         
88                                                 /* S7 */
89                         4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
90                         13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
91                         1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
92                         6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12,
93         
94                                                 /* S8 */
95                         13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
96                         1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
97                         7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
98                         2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
99                 };
100         
101         
102                 // P table from page 15, also in Appendix 1, page 18
103                 private static readonly byte [] pTab = {        
104                         16-1,  7-1, 20-1, 21-1,
105                         29-1, 12-1, 28-1, 17-1,
106                         1-1, 15-1, 23-1, 26-1,
107                         5-1, 18-1, 31-1, 10-1,
108                         2-1,  8-1, 24-1, 14-1,
109                         32-1, 27-1,  3-1,  9-1,
110                         19-1, 13-1, 30-1,  6-1,
111                         22-1, 11-1,  4-1, 25-1
112                 };
113         
114         
115                 // Permuted choice 1 table, PC-1, page 19
116                 // Translated to zero-based format.
117                 private static readonly byte [] PC1 = {
118                         57-1, 49-1, 41-1, 33-1, 25-1, 17-1,  9-1,
119                         1-1, 58-1, 50-1, 42-1, 34-1, 26-1, 18-1,
120                         10-1,  2-1, 59-1, 51-1, 43-1, 35-1, 27-1,
121                         19-1, 11-1,  3-1, 60-1, 52-1, 44-1, 36-1,
122         
123                         63-1, 55-1, 47-1, 39-1, 31-1, 23-1, 15-1,
124                         7-1, 62-1, 54-1, 46-1, 38-1, 30-1, 22-1,
125                         14-1,  6-1, 61-1, 53-1, 45-1, 37-1, 29-1,
126                         21-1, 13-1,  5-1, 28-1, 20-1, 12-1,  4-1
127                 };
128         
129         
130                 private static readonly byte [] leftRot = {
131                         1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
132                 };
133         
134                 private static readonly byte [] leftRotTotal;
135         
136                 // Permuted choice 2 table, PC-2, page 21
137                 // Translated to zero-based format.
138                 private static readonly byte [] PC2 = {
139                         14-1, 17-1, 11-1, 24-1,  1-1,  5-1,
140                         3-1, 28-1, 15-1,  6-1, 21-1, 10-1,
141                         23-1, 19-1, 12-1,  4-1, 26-1,  8-1,
142                         16-1,  7-1, 27-1, 20-1, 13-1,  2-1,
143                         41-1, 52-1, 31-1, 37-1, 47-1, 55-1,
144                         30-1, 40-1, 51-1, 45-1, 33-1, 48-1,
145                         44-1, 49-1, 39-1, 56-1, 34-1, 53-1,
146                         46-1, 42-1, 50-1, 36-1, 29-1, 32-1
147                 };
148         
149         
150                 // Initial permutation IP, page 10.
151                 // Transposed to 0-based format.
152                 private static readonly byte [] ipBits = {
153                         58-1, 50-1, 42-1, 34-1, 26-1, 18-1, 10-1,  2-1,
154                         60-1, 52-1, 44-1, 36-1, 28-1, 20-1, 12-1,  4-1,
155                         62-1, 54-1, 46-1, 38-1, 30-1, 22-1, 14-1,  6-1,
156                         64-1, 56-1, 48-1, 40-1, 32-1, 24-1, 16-1,  8-1,
157                         57-1, 49-1, 41-1, 33-1, 25-1, 17-1,  9-1,  1-1,
158                         59-1, 51-1, 43-1, 35-1, 27-1, 19-1, 11-1,  3-1,
159                         61-1, 53-1, 45-1, 37-1, 29-1, 21-1, 13-1,  5-1,
160                         63-1, 55-1, 47-1, 39-1, 31-1, 23-1, 15-1,  7-1
161                 };
162         
163         
164                 // Final permutation FP = IP^(-1), page 10.
165                 // Transposed to 0-based format.
166                 private static readonly byte [] fpBits = {
167                         40-1,  8-1, 48-1, 16-1, 56-1, 24-1, 64-1, 32-1,
168                         39-1,  7-1, 47-1, 15-1, 55-1, 23-1, 63-1, 31-1,
169                         38-1,  6-1, 46-1, 14-1, 54-1, 22-1, 62-1, 30-1,
170                         37-1,  5-1, 45-1, 13-1, 53-1, 21-1, 61-1, 29-1,
171                         36-1,  4-1, 44-1, 12-1, 52-1, 20-1, 60-1, 28-1,
172                         35-1,  3-1, 43-1, 11-1, 51-1, 19-1, 59-1, 27-1,
173                         34-1,  2-1, 42-1, 10-1, 50-1, 18-1, 58-1, 26-1,
174                         33-1,  1-1, 41-1,  9-1, 49-1, 17-1, 57-1, 25-1
175                 };
176         
177                 private static readonly uint [] spBoxes;
178                 private static readonly int [] ipTab;
179                 private static readonly int [] fpTab;
180         
181                 static DESTransform ()
182                 {
183                         spBoxes = new uint [64 * 8];
184         
185                         int [] pBox = new int [32];
186         
187                         for (int p = 0; p < 32; p++) {
188                                 for (int i = 0; i < 32; i++) {
189                                         if (p == pTab [i]) {
190                                                 pBox [p] = i;
191                                                 break;
192                                         }
193                                 }
194                         }
195         
196                         for (int s = 0; s < 8; s++) { // for each S-box
197                                 int sOff = s << 6;
198         
199                                 for (int i = 0; i < 64; i++) { // inputs
200                                         uint sp=0;
201         
202                                         int indx = (i & 0x20) | ((i & 1) << 4) | ((i >> 1) & 0xF);
203         
204                                         for (int j = 0; j < 4; j++) { // for each bit in the output
205                                                 if ((sBoxes [sOff + indx] & (8 >> j)) != 0) {
206                                                         sp |= (uint) (1 << (31 - pBox [(s << 2) + j]));
207                                                 }
208                                         }
209         
210                                         spBoxes [sOff + i] = sp;
211                                 }
212                         }
213         
214                         leftRotTotal = new byte [leftRot.Length];
215         
216                         for (int i = 0; i < leftRot.Length; i++) {
217                                 int r = 0;
218                                 for (int j = 0; j <= i; r += leftRot [j++]) {
219                                         // no statement (confuse the compiler == warning)
220                                 }
221                                 leftRotTotal [i]  = (byte) r;
222                         }
223         
224                         InitPermutationTable (ipBits, out ipTab);
225                         InitPermutationTable (fpBits, out fpTab);
226                 }
227         
228                 // Default constructor.
229                 internal DESTransform (SymmetricAlgorithm symmAlgo, bool encryption, byte[] key, byte[] iv) 
230                         : base (symmAlgo, encryption, iv)
231                 {
232                         keySchedule = new byte [KEY_BYTE_SIZE * 16];
233                         byteBuff = new byte [BLOCK_BYTE_SIZE];
234                         dwordBuff = new uint [BLOCK_BYTE_SIZE / 4];
235                         SetKey (key);
236                 }
237         
238                 private static void InitPermutationTable (byte[] pBits, out int[] permTab)
239                 {
240                         permTab = new int [8*2 * 8*2 * (64/32)];
241         
242                         for (int i = 0; i < 16; i++) {
243                                 for (int j = 0; j < 16; j++) {
244                                         int offs = (i << 5) + (j << 1);
245                                         for (int n = 0; n < 64; n++) {
246                                                 int bitNum = (int) pBits [n];
247                                                 if ((bitNum >> 2 == i) &&
248                                                         0 != (j & (8 >> (bitNum & 3)))) {
249                                                         permTab [offs + (n >> (3+2))] |= (int) ((0x80808080 & (0xFF << (n & (3 << 3)))) >> (n & 7));
250                                                 }
251                                         }
252                                 }
253                         }
254                 }
255         
256                 private uint CipherFunct (uint r, int n)
257                 {
258                         uint res = 0;
259                         byte[] subkey = keySchedule;
260                         int i = n << 3;
261         
262                         uint rt = (r >> 1) | (r << 31); // ROR32(r)
263                         res |= spBoxes [0*64 + (((rt >> 26) ^ subkey [i++]) & 0x3F)];
264                         res |= spBoxes [1*64 + (((rt >> 22) ^ subkey [i++]) & 0x3F)];
265                         res |= spBoxes [2*64 + (((rt >> 18) ^ subkey [i++]) & 0x3F)];
266                         res |= spBoxes [3*64 + (((rt >> 14) ^ subkey [i++]) & 0x3F)];
267                         res |= spBoxes [4*64 + (((rt >> 10) ^ subkey [i++]) & 0x3F)];
268                         res |= spBoxes [5*64 + (((rt >>  6) ^ subkey [i++]) & 0x3F)];
269                         res |= spBoxes [6*64 + (((rt >>  2) ^ subkey [i++]) & 0x3F)];
270                         rt = (r << 1) | (r >> 31); // ROL32(r)
271                         res |= spBoxes [7*64 + ((rt ^ subkey [i]) & 0x3F)];
272         
273                         return res;
274                 }
275         
276                 private static void Permutation (byte[] input, byte[] _output, int[] permTab, bool preSwap)
277                 {
278                         if (preSwap && BitConverter.IsLittleEndian)
279                                 BSwap (input);
280         
281                         byte[] output = _output;
282         
283                         int offs1 = (((int)(input [0]) >> 4)) << 1;
284                         int offs2 = (1 << 5) + ((((int)input [0]) & 0xF) << 1);
285         
286                         int d1 = permTab [offs1++] | permTab [offs2++];
287                         int d2 = permTab [offs1]   | permTab [offs2];
288         
289                         int max = BLOCK_BYTE_SIZE << 1;
290                         for (int i = 2, indx = 1; i < max; i += 2, indx++) {
291                                 int ii = (int) input [indx];
292                                 offs1 = (i << 5) + ((ii >> 4) << 1);
293                                 offs2 = ((i + 1) << 5) + ((ii & 0xF) << 1);
294         
295                                 d1 |= permTab [offs1++] | permTab [offs2++];
296                                 d2 |= permTab [offs1]   | permTab [offs2];
297                         }
298         
299                         if (preSwap || !BitConverter.IsLittleEndian) {
300                                 output [0] = (byte) (d1);
301                                 output [1] = (byte) (d1 >> 8);
302                                 output [2] = (byte) (d1 >> 16);
303                                 output [3] = (byte) (d1 >> 24);
304                                 output [4] = (byte) (d2);
305                                 output [5] = (byte) (d2 >> 8);
306                                 output [6] = (byte) (d2 >> 16);
307                                 output [7] = (byte) (d2 >> 24);
308                         }
309                         else {
310                                 output [0] = (byte) (d1 >> 24);
311                                 output [1] = (byte) (d1 >> 16);
312                                 output [2] = (byte) (d1 >> 8);
313                                 output [3] = (byte) (d1);
314                                 output [4] = (byte) (d2 >> 24);
315                                 output [5] = (byte) (d2 >> 16);
316                                 output [6] = (byte) (d2 >> 8);
317                                 output [7] = (byte) (d2);
318                         }
319                 }
320         
321                 private static void BSwap (byte [] byteBuff)
322                 {
323                         byte t = byteBuff [0];
324                         byteBuff [0] = byteBuff [3];
325                         byteBuff [3] = t;
326         
327                         t = byteBuff [1];
328                         byteBuff [1] = byteBuff [2];
329                         byteBuff [2] = t;
330         
331                         t = byteBuff [4];
332                         byteBuff [4] = byteBuff [7];
333                         byteBuff [7] = t;
334         
335                         t = byteBuff [5];
336                         byteBuff [5] = byteBuff [6];
337                         byteBuff [6] = t;
338                 }
339         
340                 internal void SetKey (byte[] key)
341                 {
342                         // NOTE: see Fig. 3, Key schedule calculation, at page 20.
343                         Array.Clear (keySchedule, 0, keySchedule.Length);
344         
345                         int keyBitSize = PC1.Length;
346         
347                         byte[] keyPC1 = new byte [keyBitSize]; // PC1-permuted key
348                         byte[] keyRot = new byte [keyBitSize]; // PC1 & rotated
349         
350                         int indx = 0;
351         
352                         foreach (byte bitPos in PC1) {
353                                 keyPC1 [indx++] = (byte)((key [(int)bitPos >> 3] >> (7 ^ (bitPos & 7))) & 1);
354                         }
355         
356                         int j;
357                         for (int i = 0; i < KEY_BYTE_SIZE*2; i++) {
358                                 int b = keyBitSize >> 1;
359         
360                                 for (j = 0; j < b; j++) {
361                                         int s = j + (int) leftRotTotal [i];
362                                         keyRot [j] = keyPC1 [s < b ? s : s - b];
363                                 }
364         
365                                 for (j = b; j < keyBitSize; j++) {
366                                         int s = j + (int) leftRotTotal [i];
367                                         keyRot [j] = keyPC1 [s < keyBitSize ? s : s - b];
368                                 }
369         
370                                 int keyOffs = i * KEY_BYTE_SIZE;
371         
372                                 j = 0;
373                                 foreach (byte bitPos in PC2) {
374                                         if (keyRot [(int)bitPos] != 0) {
375                                                 keySchedule [keyOffs + (j/6)] |= (byte) (0x80 >> ((j % 6) + 2));
376                                         }
377                                         j++;
378                                 }
379                         }
380                 }
381         
382                 // public helper for TripleDES
383                 public void ProcessBlock (byte[] input, byte[] output) 
384                 {
385                         ECB (input, output);
386                 }
387         
388                 protected override void ECB (byte[] input, byte[] output) 
389                 {
390                         byte[] byteBuff = this.byteBuff;
391                         uint[] dwordBuff = this.dwordBuff;
392         
393                         Permutation (input, byteBuff, ipTab, false);
394                         Buffer.BlockCopy (byteBuff, 0, dwordBuff, 0, BLOCK_BYTE_SIZE);
395         
396                         if (encrypt) {
397                                 uint d0 = dwordBuff [0];
398                                 uint d1 = dwordBuff [1];
399         
400                                 // 16 rounds
401                                 d0 ^= CipherFunct (d1,  0);
402                                 d1 ^= CipherFunct (d0,  1);
403                                 d0 ^= CipherFunct (d1,  2);
404                                 d1 ^= CipherFunct (d0,  3);
405                                 d0 ^= CipherFunct (d1,  4);
406                                 d1 ^= CipherFunct (d0,  5);
407                                 d0 ^= CipherFunct (d1,  6);
408                                 d1 ^= CipherFunct (d0,  7);
409                                 d0 ^= CipherFunct (d1,  8);
410                                 d1 ^= CipherFunct (d0,  9);
411                                 d0 ^= CipherFunct (d1, 10);
412                                 d1 ^= CipherFunct (d0, 11);
413                                 d0 ^= CipherFunct (d1, 12);
414                                 d1 ^= CipherFunct (d0, 13);
415                                 d0 ^= CipherFunct (d1, 14);
416                                 d1 ^= CipherFunct (d0, 15);
417         
418                                 dwordBuff [0] = d1;
419                                 dwordBuff [1] = d0;
420                         }
421                         else {
422                                 uint d1 = dwordBuff [0];
423                                 uint d0 = dwordBuff [1];
424         
425                                 // 16 rounds in reverse order
426                                 d1 ^= CipherFunct (d0, 15);
427                                 d0 ^= CipherFunct (d1, 14);
428                                 d1 ^= CipherFunct (d0, 13);
429                                 d0 ^= CipherFunct (d1, 12);
430                                 d1 ^= CipherFunct (d0, 11);
431                                 d0 ^= CipherFunct (d1, 10);
432                                 d1 ^= CipherFunct (d0,  9);
433                                 d0 ^= CipherFunct (d1,  8);
434                                 d1 ^= CipherFunct (d0,  7);
435                                 d0 ^= CipherFunct (d1,  6);
436                                 d1 ^= CipherFunct (d0,  5);
437                                 d0 ^= CipherFunct (d1,  4);
438                                 d1 ^= CipherFunct (d0,  3);
439                                 d0 ^= CipherFunct (d1,  2);
440                                 d1 ^= CipherFunct (d0,  1);
441                                 d0 ^= CipherFunct (d1,  0);
442         
443                                 dwordBuff [0] = d0;
444                                 dwordBuff [1] = d1;
445                         }
446         
447                         Buffer.BlockCopy (dwordBuff, 0, byteBuff, 0, BLOCK_BYTE_SIZE);
448                         Permutation (byteBuff, output, fpTab, true);
449                 }
450         } 
451         
452         public sealed class DESCryptoServiceProvider : DES {
453         
454                 public DESCryptoServiceProvider () : base ()
455                 {
456                 }
457         
458                 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV) 
459                 {
460                         Key = rgbKey;
461                         IV = rgbIV;
462                         return new DESTransform (this, false, rgbKey, rgbIV);
463                 }
464         
465                 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV) 
466                 {
467                         Key = rgbKey;
468                         IV = rgbIV;
469                         return new DESTransform (this, true, rgbKey, rgbIV);
470                 }
471         
472                 public override void GenerateIV () 
473                 {
474                         IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
475                 }
476         
477                 public override void GenerateKey () 
478                 {
479                         int size = (KeySizeValue >> 3);
480                         KeyValue = KeyBuilder.Key (size);
481                         while (IsWeakKey (KeyValue) || IsSemiWeakKey (KeyValue))
482                                 KeyValue = KeyBuilder.Key (size);
483                 }
484         }
485 }