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