2 // System.Security.Cryptography.DESCryptoServiceProvider
5 // Sergey Chaban (serge@wildwestsoftware.com)
6 // Sebastien Pouliot (sebastien@ximian.com)
8 // Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
31 using Mono
.Security
.Cryptography
;
33 namespace System
.Security
.Cryptography
{
36 // a. FIPS PUB 46-3: Data Encryption Standard
37 // http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
39 internal class DESTransform
: SymmetricTransform
{
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;
46 private byte[] keySchedule
;
47 private byte[] byteBuff
;
48 private uint[] dwordBuff
;
50 // S-boxes from FIPS 46-3, Appendix 1, page 17
51 private static readonly byte [] sBoxes
= {
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,
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,
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,
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,
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,
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,
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,
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
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
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,
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
130 private static readonly byte [] leftRot
= {
131 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
134 private static readonly byte [] leftRotTotal
;
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
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
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
177 private static readonly uint [] spBoxes
;
178 private static readonly int [] ipTab
;
179 private static readonly int [] fpTab
;
181 static DESTransform ()
183 spBoxes
= new uint [64 * 8];
185 int [] pBox
= new int [32];
187 for (int p
= 0; p
< 32; p
++) {
188 for (int i
= 0; i
< 32; i
++) {
196 for (int s
= 0; s
< 8; s
++) { // for each S-box
199 for (int i
= 0; i
< 64; i
++) { // inputs
202 int indx
= (i
& 0x20) | ((i
& 1) << 4) | ((i
>> 1) & 0xF);
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
]));
210 spBoxes
[sOff
+ i
] = sp
;
214 leftRotTotal
= new byte [leftRot
.Length
];
216 for (int i
= 0; i
< leftRot
.Length
; i
++) {
218 for (int j
= 0; j
<= i
; r
+= leftRot
[j
++]) {
219 // no statement (confuse the compiler == warning)
221 leftRotTotal
[i
] = (byte) r
;
224 InitPermutationTable (ipBits
, out ipTab
);
225 InitPermutationTable (fpBits
, out fpTab
);
228 // Default constructor.
229 internal DESTransform (SymmetricAlgorithm symmAlgo
, bool encryption
, byte[] key
, byte[] iv
)
230 : base (symmAlgo
, encryption
, iv
)
232 keySchedule
= new byte [KEY_BYTE_SIZE
* 16];
233 byteBuff
= new byte [BLOCK_BYTE_SIZE
];
234 dwordBuff
= new uint [BLOCK_BYTE_SIZE
/ 4];
238 private static void InitPermutationTable (byte[] pBits
, out int[] permTab
)
240 permTab
= new int [8*2 * 8*2 * (64/32)];
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));
256 private uint CipherFunct (uint r
, int n
)
259 byte[] subkey
= keySchedule
;
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)];
276 private static void Permutation (byte[] input
, byte[] _output
, int[] permTab
, bool preSwap
)
278 if (preSwap
&& BitConverter
.IsLittleEndian
)
281 byte[] output
= _output
;
283 int offs1
= (((int)(input
[0]) >> 4)) << 1;
284 int offs2
= (1 << 5) + ((((int)input
[0]) & 0xF) << 1);
286 int d1
= permTab
[offs1
++] | permTab
[offs2
++];
287 int d2
= permTab
[offs1
] | permTab
[offs2
];
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);
295 d1
|= permTab
[offs1
++] | permTab
[offs2
++];
296 d2
|= permTab
[offs1
] | permTab
[offs2
];
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);
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
);
321 private static void BSwap (byte [] byteBuff
)
323 byte t
= byteBuff
[0];
324 byteBuff
[0] = byteBuff
[3];
328 byteBuff
[1] = byteBuff
[2];
332 byteBuff
[4] = byteBuff
[7];
336 byteBuff
[5] = byteBuff
[6];
340 internal void SetKey (byte[] key
)
342 // NOTE: see Fig. 3, Key schedule calculation, at page 20.
343 Array
.Clear (keySchedule
, 0, keySchedule
.Length
);
345 int keyBitSize
= PC1
.Length
;
347 byte[] keyPC1
= new byte [keyBitSize
]; // PC1-permuted key
348 byte[] keyRot
= new byte [keyBitSize
]; // PC1 & rotated
352 foreach (byte bitPos
in PC1
) {
353 keyPC1
[indx
++] = (byte)((key
[(int)bitPos
>> 3] >> (7 ^
(bitPos
& 7))) & 1);
357 for (int i
= 0; i
< KEY_BYTE_SIZE
*2; i
++) {
358 int b
= keyBitSize
>> 1;
360 for (j
= 0; j
< b
; j
++) {
361 int s
= j
+ (int) leftRotTotal
[i
];
362 keyRot
[j
] = keyPC1
[s
< b
? s
: s
- b
];
365 for (j
= b
; j
< keyBitSize
; j
++) {
366 int s
= j
+ (int) leftRotTotal
[i
];
367 keyRot
[j
] = keyPC1
[s
< keyBitSize
? s
: s
- b
];
370 int keyOffs
= i
* KEY_BYTE_SIZE
;
373 foreach (byte bitPos
in PC2
) {
374 if (keyRot
[(int)bitPos
] != 0) {
375 keySchedule
[keyOffs
+ (j
/6)] |= (byte) (0x80 >> ((j
% 6) + 2));
382 // public helper for TripleDES
383 public void ProcessBlock (byte[] input
, byte[] output
)
388 protected override void ECB (byte[] input
, byte[] output
)
390 byte[] byteBuff
= this.byteBuff
;
391 uint[] dwordBuff
= this.dwordBuff
;
393 Permutation (input
, byteBuff
, ipTab
, false);
394 Buffer
.BlockCopy (byteBuff
, 0, dwordBuff
, 0, BLOCK_BYTE_SIZE
);
397 uint d0
= dwordBuff
[0];
398 uint d1
= dwordBuff
[1];
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);
422 uint d1
= dwordBuff
[0];
423 uint d0
= dwordBuff
[1];
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);
447 Buffer
.BlockCopy (dwordBuff
, 0, byteBuff
, 0, BLOCK_BYTE_SIZE
);
448 Permutation (byteBuff
, output
, fpTab
, true);
452 public sealed class DESCryptoServiceProvider
: DES
{
454 public DESCryptoServiceProvider () : base ()
458 public override ICryptoTransform
CreateDecryptor (byte[] rgbKey
, byte[] rgbIV
)
462 return new DESTransform (this, false, rgbKey
, rgbIV
);
465 public override ICryptoTransform
CreateEncryptor (byte[] rgbKey
, byte[] rgbIV
)
469 return new DESTransform (this, true, rgbKey
, rgbIV
);
472 public override void GenerateIV ()
474 IVValue
= KeyBuilder
.IV (BlockSizeValue
>> 3);
477 public override void GenerateKey ()
479 int size
= (KeySizeValue
>> 3);
480 KeyValue
= KeyBuilder
.Key (size
);
481 while (IsWeakKey (KeyValue
) || IsSemiWeakKey (KeyValue
))
482 KeyValue
= KeyBuilder
.Key (size
);