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 // (C) 2004 Novell (http://www.novell.com)
13 using Mono.Security.Cryptography;
15 namespace System.Security.Cryptography {
18 // a. FIPS PUB 46-3: Data Encryption Standard
19 // http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
21 internal class DESTransform : SymmetricTransform {
23 internal static readonly int KEY_BIT_SIZE = 64;
24 internal static readonly int KEY_BYTE_SIZE = KEY_BIT_SIZE / 8;
25 internal static readonly int BLOCK_BIT_SIZE = 64;
26 internal static readonly int BLOCK_BYTE_SIZE = BLOCK_BIT_SIZE / 8;
28 private byte[] keySchedule;
29 private byte[] byteBuff;
30 private uint[] dwordBuff;
32 // S-boxes from FIPS 46-3, Appendix 1, page 17
33 private static readonly byte [] sBoxes = {
35 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
36 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
37 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
38 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
41 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
42 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
43 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
44 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
47 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
48 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
49 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
50 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
53 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
54 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
55 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
56 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
59 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
60 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
61 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
62 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
65 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
66 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
67 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
68 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
71 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
72 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
73 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
74 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
77 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
78 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
79 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
80 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
84 // P table from page 15, also in Appendix 1, page 18
85 private static readonly byte [] pTab = {
86 16-1, 7-1, 20-1, 21-1,
87 29-1, 12-1, 28-1, 17-1,
88 1-1, 15-1, 23-1, 26-1,
89 5-1, 18-1, 31-1, 10-1,
92 19-1, 13-1, 30-1, 6-1,
97 // Permuted choice 1 table, PC-1, page 19
98 // Translated to zero-based format.
99 private static readonly byte [] PC1 = {
100 57-1, 49-1, 41-1, 33-1, 25-1, 17-1, 9-1,
101 1-1, 58-1, 50-1, 42-1, 34-1, 26-1, 18-1,
102 10-1, 2-1, 59-1, 51-1, 43-1, 35-1, 27-1,
103 19-1, 11-1, 3-1, 60-1, 52-1, 44-1, 36-1,
105 63-1, 55-1, 47-1, 39-1, 31-1, 23-1, 15-1,
106 7-1, 62-1, 54-1, 46-1, 38-1, 30-1, 22-1,
107 14-1, 6-1, 61-1, 53-1, 45-1, 37-1, 29-1,
108 21-1, 13-1, 5-1, 28-1, 20-1, 12-1, 4-1
112 private static readonly byte [] leftRot = {
113 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
116 private static readonly byte [] leftRotTotal;
118 // Permuted choice 2 table, PC-2, page 21
119 // Translated to zero-based format.
120 private static readonly byte [] PC2 = {
121 14-1, 17-1, 11-1, 24-1, 1-1, 5-1,
122 3-1, 28-1, 15-1, 6-1, 21-1, 10-1,
123 23-1, 19-1, 12-1, 4-1, 26-1, 8-1,
124 16-1, 7-1, 27-1, 20-1, 13-1, 2-1,
125 41-1, 52-1, 31-1, 37-1, 47-1, 55-1,
126 30-1, 40-1, 51-1, 45-1, 33-1, 48-1,
127 44-1, 49-1, 39-1, 56-1, 34-1, 53-1,
128 46-1, 42-1, 50-1, 36-1, 29-1, 32-1
132 // Initial permutation IP, page 10.
133 // Transposed to 0-based format.
134 private static readonly byte [] ipBits = {
135 58-1, 50-1, 42-1, 34-1, 26-1, 18-1, 10-1, 2-1,
136 60-1, 52-1, 44-1, 36-1, 28-1, 20-1, 12-1, 4-1,
137 62-1, 54-1, 46-1, 38-1, 30-1, 22-1, 14-1, 6-1,
138 64-1, 56-1, 48-1, 40-1, 32-1, 24-1, 16-1, 8-1,
139 57-1, 49-1, 41-1, 33-1, 25-1, 17-1, 9-1, 1-1,
140 59-1, 51-1, 43-1, 35-1, 27-1, 19-1, 11-1, 3-1,
141 61-1, 53-1, 45-1, 37-1, 29-1, 21-1, 13-1, 5-1,
142 63-1, 55-1, 47-1, 39-1, 31-1, 23-1, 15-1, 7-1
146 // Final permutation FP = IP^(-1), page 10.
147 // Transposed to 0-based format.
148 private static readonly byte [] fpBits = {
149 40-1, 8-1, 48-1, 16-1, 56-1, 24-1, 64-1, 32-1,
150 39-1, 7-1, 47-1, 15-1, 55-1, 23-1, 63-1, 31-1,
151 38-1, 6-1, 46-1, 14-1, 54-1, 22-1, 62-1, 30-1,
152 37-1, 5-1, 45-1, 13-1, 53-1, 21-1, 61-1, 29-1,
153 36-1, 4-1, 44-1, 12-1, 52-1, 20-1, 60-1, 28-1,
154 35-1, 3-1, 43-1, 11-1, 51-1, 19-1, 59-1, 27-1,
155 34-1, 2-1, 42-1, 10-1, 50-1, 18-1, 58-1, 26-1,
156 33-1, 1-1, 41-1, 9-1, 49-1, 17-1, 57-1, 25-1
159 private static readonly uint [] spBoxes;
160 private static readonly int [] ipTab;
161 private static readonly int [] fpTab;
163 static DESTransform ()
165 spBoxes = new uint [64 * 8];
167 int [] pBox = new int [32];
169 for (int p = 0; p < 32; p++) {
170 for (int i = 0; i < 32; i++) {
178 for (int s = 0; s < 8; s++) { // for each S-box
181 for (int i = 0; i < 64; i++) { // inputs
184 int indx = (i & 0x20) | ((i & 1) << 4) | ((i >> 1) & 0xF);
186 for (int j = 0; j < 4; j++) { // for each bit in the output
187 if ((sBoxes [sOff + indx] & (8 >> j)) != 0) {
188 sp |= (uint) (1 << (31 - pBox [(s << 2) + j]));
192 spBoxes [sOff + i] = sp;
196 leftRotTotal = new byte [leftRot.Length];
198 for (int i = 0; i < leftRot.Length; i++) {
200 for (int j = 0; j <= i; r += leftRot [j++]);
201 leftRotTotal [i] = (byte) r;
204 InitPermutationTable (ipBits, out ipTab);
205 InitPermutationTable (fpBits, out fpTab);
208 // Default constructor.
209 internal DESTransform (SymmetricAlgorithm symmAlgo, bool encryption, byte[] key, byte[] iv)
210 : base (symmAlgo, encryption, iv)
212 keySchedule = new byte [KEY_BYTE_SIZE * 16];
213 byteBuff = new byte [BLOCK_BYTE_SIZE];
214 dwordBuff = new uint [BLOCK_BYTE_SIZE / 4];
218 private static void InitPermutationTable (byte[] pBits, out int[] permTab)
220 permTab = new int [8*2 * 8*2 * (64/32)];
222 for (int i = 0; i < 16; i++) {
223 for (int j = 0; j < 16; j++) {
224 int offs = (i << 5) + (j << 1);
225 for (int n = 0; n < 64; n++) {
226 int bitNum = (int) pBits [n];
227 if ((bitNum >> 2 == i) &&
228 0 != (j & (8 >> (bitNum & 3)))) {
229 permTab [offs + (n >> (3+2))] |= (int) ((0x80808080 & (0xFF << (n & (3 << 3)))) >> (n & 7));
236 private uint CipherFunct (uint r, int n)
239 byte[] subkey = keySchedule;
242 uint rt = (r >> 1) | (r << 31); // ROR32(r)
243 res |= spBoxes [0*64 + (((rt >> 26) ^ subkey [i++]) & 0x3F)];
244 res |= spBoxes [1*64 + (((rt >> 22) ^ subkey [i++]) & 0x3F)];
245 res |= spBoxes [2*64 + (((rt >> 18) ^ subkey [i++]) & 0x3F)];
246 res |= spBoxes [3*64 + (((rt >> 14) ^ subkey [i++]) & 0x3F)];
247 res |= spBoxes [4*64 + (((rt >> 10) ^ subkey [i++]) & 0x3F)];
248 res |= spBoxes [5*64 + (((rt >> 6) ^ subkey [i++]) & 0x3F)];
249 res |= spBoxes [6*64 + (((rt >> 2) ^ subkey [i++]) & 0x3F)];
250 rt = (r << 1) | (r >> 31); // ROL32(r)
251 res |= spBoxes [7*64 + ((rt ^ subkey [i]) & 0x3F)];
256 private static void Permutation (byte[] input, byte[] _output, int[] permTab, bool preSwap)
258 if (preSwap && BitConverter.IsLittleEndian)
261 byte[] output = _output;
263 int offs1 = (((int)(input [0]) >> 4)) << 1;
264 int offs2 = (1 << 5) + ((((int)input [0]) & 0xF) << 1);
266 int d1 = permTab [offs1++] | permTab [offs2++];
267 int d2 = permTab [offs1] | permTab [offs2];
269 int max = BLOCK_BYTE_SIZE << 1;
270 for (int i = 2, indx = 1; i < max; i += 2, indx++) {
271 int ii = (int) input [indx];
272 offs1 = (i << 5) + ((ii >> 4) << 1);
273 offs2 = ((i + 1) << 5) + ((ii & 0xF) << 1);
275 d1 |= permTab [offs1++] | permTab [offs2++];
276 d2 |= permTab [offs1] | permTab [offs2];
279 if (preSwap || !BitConverter.IsLittleEndian) {
280 output [0] = (byte) (d1);
281 output [1] = (byte) (d1 >> 8);
282 output [2] = (byte) (d1 >> 16);
283 output [3] = (byte) (d1 >> 24);
284 output [4] = (byte) (d2);
285 output [5] = (byte) (d2 >> 8);
286 output [6] = (byte) (d2 >> 16);
287 output [7] = (byte) (d2 >> 24);
290 output [0] = (byte) (d1 >> 24);
291 output [1] = (byte) (d1 >> 16);
292 output [2] = (byte) (d1 >> 8);
293 output [3] = (byte) (d1);
294 output [4] = (byte) (d2 >> 24);
295 output [5] = (byte) (d2 >> 16);
296 output [6] = (byte) (d2 >> 8);
297 output [7] = (byte) (d2);
301 private static void BSwap (byte [] byteBuff)
303 byte t = byteBuff [0];
304 byteBuff [0] = byteBuff [3];
308 byteBuff [1] = byteBuff [2];
312 byteBuff [4] = byteBuff [7];
316 byteBuff [5] = byteBuff [6];
320 internal void SetKey (byte[] key)
322 // NOTE: see Fig. 3, Key schedule calculation, at page 20.
323 Array.Clear (keySchedule, 0, keySchedule.Length);
325 int keyBitSize = PC1.Length;
327 byte[] keyPC1 = new byte [keyBitSize]; // PC1-permuted key
328 byte[] keyRot = new byte [keyBitSize]; // PC1 & rotated
332 foreach (byte bitPos in PC1) {
333 keyPC1 [indx++] = (byte)((key [(int)bitPos >> 3] >> (7 ^ (bitPos & 7))) & 1);
337 for (int i = 0; i < KEY_BYTE_SIZE*2; i++) {
338 int b = keyBitSize >> 1;
340 for (j = 0; j < b; j++) {
341 int s = j + (int) leftRotTotal [i];
342 keyRot [j] = keyPC1 [s < b ? s : s - b];
345 for (j = b; j < keyBitSize; j++) {
346 int s = j + (int) leftRotTotal [i];
347 keyRot [j] = keyPC1 [s < keyBitSize ? s : s - b];
350 int keyOffs = i * KEY_BYTE_SIZE;
353 foreach (byte bitPos in PC2) {
354 if (keyRot [(int)bitPos] != 0) {
355 keySchedule [keyOffs + (j/6)] |= (byte) (0x80 >> ((j % 6) + 2));
362 // public helper for TripleDES
363 public void ProcessBlock (byte[] input, byte[] output)
368 protected override void ECB (byte[] input, byte[] output)
370 byte[] byteBuff = this.byteBuff;
371 uint[] dwordBuff = this.dwordBuff;
373 Permutation (input, byteBuff, ipTab, false);
374 Buffer.BlockCopy (byteBuff, 0, dwordBuff, 0, BLOCK_BYTE_SIZE);
377 uint d0 = dwordBuff [0];
378 uint d1 = dwordBuff [1];
381 d0 ^= CipherFunct (d1, 0);
382 d1 ^= CipherFunct (d0, 1);
383 d0 ^= CipherFunct (d1, 2);
384 d1 ^= CipherFunct (d0, 3);
385 d0 ^= CipherFunct (d1, 4);
386 d1 ^= CipherFunct (d0, 5);
387 d0 ^= CipherFunct (d1, 6);
388 d1 ^= CipherFunct (d0, 7);
389 d0 ^= CipherFunct (d1, 8);
390 d1 ^= CipherFunct (d0, 9);
391 d0 ^= CipherFunct (d1, 10);
392 d1 ^= CipherFunct (d0, 11);
393 d0 ^= CipherFunct (d1, 12);
394 d1 ^= CipherFunct (d0, 13);
395 d0 ^= CipherFunct (d1, 14);
396 d1 ^= CipherFunct (d0, 15);
402 uint d1 = dwordBuff [0];
403 uint d0 = dwordBuff [1];
405 // 16 rounds in reverse order
406 d1 ^= CipherFunct (d0, 15);
407 d0 ^= CipherFunct (d1, 14);
408 d1 ^= CipherFunct (d0, 13);
409 d0 ^= CipherFunct (d1, 12);
410 d1 ^= CipherFunct (d0, 11);
411 d0 ^= CipherFunct (d1, 10);
412 d1 ^= CipherFunct (d0, 9);
413 d0 ^= CipherFunct (d1, 8);
414 d1 ^= CipherFunct (d0, 7);
415 d0 ^= CipherFunct (d1, 6);
416 d1 ^= CipherFunct (d0, 5);
417 d0 ^= CipherFunct (d1, 4);
418 d1 ^= CipherFunct (d0, 3);
419 d0 ^= CipherFunct (d1, 2);
420 d1 ^= CipherFunct (d0, 1);
421 d0 ^= CipherFunct (d1, 0);
427 Buffer.BlockCopy (dwordBuff, 0, byteBuff, 0, BLOCK_BYTE_SIZE);
428 Permutation (byteBuff, output, fpTab, true);
432 public sealed class DESCryptoServiceProvider : DES {
434 public DESCryptoServiceProvider () : base ()
438 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
442 return new DESTransform (this, false, rgbKey, rgbIV);
445 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
449 return new DESTransform (this, true, rgbKey, rgbIV);
452 public override void GenerateIV ()
454 IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
457 public override void GenerateKey ()
459 int size = (KeySizeValue >> 3);
460 KeyValue = KeyBuilder.Key (size);
461 while (IsWeakKey (KeyValue) || IsSemiWeakKey (KeyValue))
462 KeyValue = KeyBuilder.Key (size);