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 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
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.
36 using Mono.Security.Cryptography;
38 namespace System.Security.Cryptography {
41 // a. FIPS PUB 46-3: Data Encryption Standard
42 // http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
44 internal class DESTransform : SymmetricTransform {
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;
51 private byte[] keySchedule;
52 private byte[] byteBuff;
53 private uint[] dwordBuff;
55 // S-boxes from FIPS 46-3, Appendix 1, page 17
56 private static readonly byte [] sBoxes = {
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,
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,
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,
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,
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,
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,
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,
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
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
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,
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
135 private static readonly byte [] leftRot = {
136 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
139 private static readonly byte [] leftRotTotal;
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
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
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
182 private static readonly uint [] spBoxes;
183 private static readonly int [] ipTab;
184 private static readonly int [] fpTab;
186 static DESTransform ()
188 spBoxes = new uint [64 * 8];
190 int [] pBox = new int [32];
192 for (int p = 0; p < 32; p++) {
193 for (int i = 0; i < 32; i++) {
201 for (int s = 0; s < 8; s++) { // for each S-box
204 for (int i = 0; i < 64; i++) { // inputs
207 int indx = (i & 0x20) | ((i & 1) << 4) | ((i >> 1) & 0xF);
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]));
215 spBoxes [sOff + i] = sp;
219 leftRotTotal = new byte [leftRot.Length];
221 for (int i = 0; i < leftRot.Length; i++) {
223 for (int j = 0; j <= i; r += leftRot [j++]);
224 leftRotTotal [i] = (byte) r;
227 InitPermutationTable (ipBits, out ipTab);
228 InitPermutationTable (fpBits, out fpTab);
231 // Default constructor.
232 internal DESTransform (SymmetricAlgorithm symmAlgo, bool encryption, byte[] key, byte[] iv)
233 : base (symmAlgo, encryption, iv)
235 keySchedule = new byte [KEY_BYTE_SIZE * 16];
236 byteBuff = new byte [BLOCK_BYTE_SIZE];
237 dwordBuff = new uint [BLOCK_BYTE_SIZE / 4];
241 private static void InitPermutationTable (byte[] pBits, out int[] permTab)
243 permTab = new int [8*2 * 8*2 * (64/32)];
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));
259 private uint CipherFunct (uint r, int n)
262 byte[] subkey = keySchedule;
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)];
279 private static void Permutation (byte[] input, byte[] _output, int[] permTab, bool preSwap)
281 if (preSwap && BitConverter.IsLittleEndian)
284 byte[] output = _output;
286 int offs1 = (((int)(input [0]) >> 4)) << 1;
287 int offs2 = (1 << 5) + ((((int)input [0]) & 0xF) << 1);
289 int d1 = permTab [offs1++] | permTab [offs2++];
290 int d2 = permTab [offs1] | permTab [offs2];
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);
298 d1 |= permTab [offs1++] | permTab [offs2++];
299 d2 |= permTab [offs1] | permTab [offs2];
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);
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);
324 private static void BSwap (byte [] byteBuff)
326 byte t = byteBuff [0];
327 byteBuff [0] = byteBuff [3];
331 byteBuff [1] = byteBuff [2];
335 byteBuff [4] = byteBuff [7];
339 byteBuff [5] = byteBuff [6];
343 internal void SetKey (byte[] key)
345 // NOTE: see Fig. 3, Key schedule calculation, at page 20.
346 Array.Clear (keySchedule, 0, keySchedule.Length);
348 int keyBitSize = PC1.Length;
350 byte[] keyPC1 = new byte [keyBitSize]; // PC1-permuted key
351 byte[] keyRot = new byte [keyBitSize]; // PC1 & rotated
355 foreach (byte bitPos in PC1) {
356 keyPC1 [indx++] = (byte)((key [(int)bitPos >> 3] >> (7 ^ (bitPos & 7))) & 1);
360 for (int i = 0; i < KEY_BYTE_SIZE*2; i++) {
361 int b = keyBitSize >> 1;
363 for (j = 0; j < b; j++) {
364 int s = j + (int) leftRotTotal [i];
365 keyRot [j] = keyPC1 [s < b ? s : s - b];
368 for (j = b; j < keyBitSize; j++) {
369 int s = j + (int) leftRotTotal [i];
370 keyRot [j] = keyPC1 [s < keyBitSize ? s : s - b];
373 int keyOffs = i * KEY_BYTE_SIZE;
376 foreach (byte bitPos in PC2) {
377 if (keyRot [(int)bitPos] != 0) {
378 keySchedule [keyOffs + (j/6)] |= (byte) (0x80 >> ((j % 6) + 2));
385 // public helper for TripleDES
386 public void ProcessBlock (byte[] input, byte[] output)
391 protected override void ECB (byte[] input, byte[] output)
393 byte[] byteBuff = this.byteBuff;
394 uint[] dwordBuff = this.dwordBuff;
396 Permutation (input, byteBuff, ipTab, false);
397 Buffer.BlockCopy (byteBuff, 0, dwordBuff, 0, BLOCK_BYTE_SIZE);
400 uint d0 = dwordBuff [0];
401 uint d1 = dwordBuff [1];
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);
425 uint d1 = dwordBuff [0];
426 uint d0 = dwordBuff [1];
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);
450 Buffer.BlockCopy (dwordBuff, 0, byteBuff, 0, BLOCK_BYTE_SIZE);
451 Permutation (byteBuff, output, fpTab, true);
455 public sealed class DESCryptoServiceProvider : DES {
457 public DESCryptoServiceProvider () : base ()
461 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
465 return new DESTransform (this, false, rgbKey, rgbIV);
468 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
472 return new DESTransform (this, true, rgbKey, rgbIV);
475 public override void GenerateIV ()
477 IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
480 public override void GenerateKey ()
482 int size = (KeySizeValue >> 3);
483 KeyValue = KeyBuilder.Key (size);
484 while (IsWeakKey (KeyValue) || IsSemiWeakKey (KeyValue))
485 KeyValue = KeyBuilder.Key (size);