DesCipher
Implements DES cipher algorithm.
using System;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
public class DesCipher : BlockCipher
{
private int[] _encryptionKey;
private int[] _decryptionKey;
private static readonly short[] bytebit = new short[8] {
128,
64,
32,
16,
8,
4,
2,
1
};
private static readonly int[] bigbyte = new int[24] {
8388608,
4194304,
2097152,
1048576,
524288,
262144,
131072,
65536,
32768,
16384,
8192,
4096,
2048,
1024,
512,
256,
128,
64,
32,
16,
8,
4,
2,
1
};
private static readonly byte[] pc1 = new byte[56] {
56,
48,
40,
32,
24,
16,
8,
0,
57,
49,
41,
33,
25,
17,
9,
1,
58,
50,
42,
34,
26,
18,
10,
2,
59,
51,
43,
35,
62,
54,
46,
38,
30,
22,
14,
6,
61,
53,
45,
37,
29,
21,
13,
5,
60,
52,
44,
36,
28,
20,
12,
4,
27,
19,
11,
3
};
private static readonly byte[] totrot = new byte[16] {
1,
2,
4,
6,
8,
10,
12,
14,
15,
17,
19,
21,
23,
25,
27,
28
};
private static readonly byte[] pc2 = new byte[48] {
13,
16,
10,
23,
0,
4,
2,
27,
14,
5,
20,
9,
22,
18,
11,
3,
25,
7,
15,
6,
26,
19,
12,
1,
40,
51,
30,
36,
46,
54,
29,
39,
50,
44,
32,
47,
43,
48,
38,
55,
33,
52,
45,
41,
49,
35,
28,
31
};
private static readonly uint[] SP1 = new uint[64] {
16843776,
0,
65536,
16843780,
16842756,
66564,
4,
65536,
1024,
16843776,
16843780,
1024,
16778244,
16842756,
16777216,
4,
1028,
16778240,
16778240,
66560,
66560,
16842752,
16842752,
16778244,
65540,
16777220,
16777220,
65540,
0,
1028,
66564,
16777216,
65536,
16843780,
4,
16842752,
16843776,
16777216,
16777216,
1024,
16842756,
65536,
66560,
16777220,
1024,
4,
16778244,
66564,
16843780,
65540,
16842752,
16778244,
16777220,
1028,
66564,
16843776,
1028,
16778240,
16778240,
0,
65540,
66560,
0,
16842756
};
private static readonly uint[] SP2 = new uint[64] {
2148565024,
2147516416,
32768,
1081376,
1048576,
32,
2148532256,
2147516448,
2147483680,
2148565024,
2148564992,
2147483648,
2147516416,
1048576,
32,
2148532256,
1081344,
1048608,
2147516448,
0,
2147483648,
32768,
1081376,
2148532224,
1048608,
2147483680,
0,
1081344,
32800,
2148564992,
2148532224,
32800,
0,
1081376,
2148532256,
1048576,
2147516448,
2148532224,
2148564992,
32768,
2148532224,
2147516416,
32,
2148565024,
1081376,
32,
32768,
2147483648,
32800,
2148564992,
1048576,
2147483680,
1048608,
2147516448,
2147483680,
1048608,
1081344,
0,
2147516416,
32800,
2147483648,
2148532256,
2148565024,
1081344
};
private static readonly uint[] SP3 = new uint[64] {
520,
134349312,
0,
134348808,
134218240,
0,
131592,
134218240,
131080,
134217736,
134217736,
131072,
134349320,
131080,
134348800,
520,
134217728,
8,
134349312,
512,
131584,
134348800,
134348808,
131592,
134218248,
131584,
131072,
134218248,
8,
134349320,
512,
134217728,
134349312,
134217728,
131080,
520,
131072,
134349312,
134218240,
0,
512,
131080,
134349320,
134218240,
134217736,
512,
0,
134348808,
134218248,
131072,
134217728,
134349320,
8,
131592,
131584,
134217736,
134348800,
134218248,
520,
134348800,
131592,
8,
134348808,
131584
};
private static readonly uint[] SP4 = new uint[64] {
8396801,
8321,
8321,
128,
8396928,
8388737,
8388609,
8193,
0,
8396800,
8396800,
8396929,
129,
0,
8388736,
8388609,
1,
8192,
8388608,
8396801,
128,
8388608,
8193,
8320,
8388737,
1,
8320,
8388736,
8192,
8396928,
8396929,
129,
8388736,
8388609,
8396800,
8396929,
129,
0,
0,
8396800,
8320,
8388736,
8388737,
1,
8396801,
8321,
8321,
128,
8396929,
129,
1,
8192,
8388609,
8193,
8396928,
8388737,
8193,
8320,
8388608,
8396801,
128,
8388608,
8192,
8396928
};
private static readonly uint[] SP5 = new uint[64] {
256,
34078976,
34078720,
1107296512,
524288,
256,
1073741824,
34078720,
1074266368,
524288,
33554688,
1074266368,
1107296512,
1107820544,
524544,
1073741824,
33554432,
1074266112,
1074266112,
0,
1073742080,
1107820800,
1107820800,
33554688,
1107820544,
1073742080,
0,
1107296256,
34078976,
33554432,
1107296256,
524544,
524288,
1107296512,
256,
33554432,
1073741824,
34078720,
1107296512,
1074266368,
33554688,
1073741824,
1107820544,
34078976,
1074266368,
256,
33554432,
1107820544,
1107820800,
524544,
1107296256,
1107820800,
34078720,
0,
1074266112,
1107296256,
524544,
33554688,
1073742080,
524288,
0,
1074266112,
34078976,
1073742080
};
private static readonly uint[] SP6 = new uint[64] {
536870928,
541065216,
16384,
541081616,
541065216,
16,
541081616,
4194304,
536887296,
4210704,
4194304,
536870928,
4194320,
536887296,
536870912,
16400,
0,
4194320,
536887312,
16384,
4210688,
536887312,
16,
541065232,
541065232,
0,
4210704,
541081600,
16400,
4210688,
541081600,
536870912,
536887296,
16,
541065232,
4210688,
541081616,
4194304,
16400,
536870928,
4194304,
536887296,
536870912,
16400,
536870928,
541081616,
4210688,
541065216,
4210704,
541081600,
0,
541065232,
16,
16384,
541065216,
4210704,
16384,
4194320,
536887312,
0,
541081600,
536870912,
4194320,
536887312
};
private static readonly uint[] SP7 = new uint[64] {
2097152,
69206018,
67110914,
0,
2048,
67110914,
2099202,
69208064,
69208066,
2097152,
0,
67108866,
2,
67108864,
69206018,
2050,
67110912,
2099202,
2097154,
67110912,
67108866,
69206016,
69208064,
2097154,
69206016,
2048,
2050,
69208066,
2099200,
2,
67108864,
2099200,
67108864,
2099200,
2097152,
67110914,
67110914,
69206018,
69206018,
2,
2097154,
67108864,
67110912,
2097152,
69208064,
2050,
2099202,
69208064,
2050,
67108866,
69208066,
69206016,
2099200,
0,
2,
69208066,
0,
2099202,
69206016,
2048,
67108866,
67110912,
2048,
2097154
};
private static readonly uint[] SP8 = new uint[64] {
268439616,
4096,
262144,
268701760,
268435456,
268439616,
64,
268435456,
262208,
268697600,
268701760,
266240,
268701696,
266304,
4096,
64,
268697600,
268435520,
268439552,
4160,
266240,
262208,
268697664,
268701696,
4160,
0,
0,
268697664,
268435520,
268439552,
266304,
262144,
266304,
262144,
268701696,
4096,
64,
268697664,
4096,
266304,
268439552,
64,
268435520,
268697600,
268697664,
268435456,
262144,
268439616,
0,
268701760,
262208,
268435520,
268697600,
268439552,
268439616,
0,
268701760,
266240,
266240,
4160,
4160,
262208,
268435456,
268701696
};
public DesCipher(byte[] key, CipherMode mode, CipherPadding padding)
: base(key, 8, mode, padding)
{
}
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputOffset + base.BlockSize > inputBuffer.Length)
throw new IndexOutOfRangeException("input buffer too short");
if (outputOffset + base.BlockSize > outputBuffer.Length)
throw new IndexOutOfRangeException("output buffer too short");
if (_encryptionKey == null)
_encryptionKey = GenerateWorkingKey(true, base.Key);
DesFunc(_encryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset);
return base.BlockSize;
}
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputOffset + base.BlockSize > inputBuffer.Length)
throw new IndexOutOfRangeException("input buffer too short");
if (outputOffset + base.BlockSize > outputBuffer.Length)
throw new IndexOutOfRangeException("output buffer too short");
if (_decryptionKey == null)
_decryptionKey = GenerateWorkingKey(false, base.Key);
DesFunc(_decryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset);
return base.BlockSize;
}
protected int[] GenerateWorkingKey(bool encrypting, byte[] key)
{
ValidateKey();
int[] array = new int[32];
bool[] array2 = new bool[56];
bool[] array3 = new bool[56];
for (int i = 0; i < 56; i++) {
int num = pc1[i];
array2[i] = ((key[(uint)num >> 3] & bytebit[num & 7]) != 0);
}
for (int j = 0; j < 16; j++) {
int num2 = (!encrypting) ? (15 - j << 1) : (j << 1);
int num3 = num2 + 1;
array[num2] = (array[num3] = 0);
for (int k = 0; k < 28; k++) {
int num4 = k + totrot[j];
if (num4 < 28)
array3[k] = array2[num4];
else
array3[k] = array2[num4 - 28];
}
for (int l = 28; l < 56; l++) {
int num4 = l + totrot[j];
if (num4 < 56)
array3[l] = array2[num4];
else
array3[l] = array2[num4 - 28];
}
for (int m = 0; m < 24; m++) {
if (array3[pc2[m]])
array[num2] |= bigbyte[m];
if (array3[pc2[m + 24]])
array[num3] |= bigbyte[m];
}
}
for (int n = 0; n != 32; n += 2) {
int num5 = array[n];
int num6 = array[n + 1];
array[n] = (((num5 & 16515072) << 6) | ((num5 & 4032) << 10) | (int)((uint)(num6 & 16515072) >> 10) | (int)((uint)(num6 & 4032) >> 6));
array[n + 1] = (((num5 & 258048) << 12) | ((num5 & 63) << 16) | (int)((uint)(num6 & 258048) >> 4) | (num6 & 63));
}
return array;
}
protected virtual void ValidateKey()
{
int num = base.Key.Length * 8;
if (num != 64)
throw new ArgumentException($"""{num}""");
}
protected static void DesFunc(int[] wKey, byte[] input, int inOff, byte[] outBytes, int outOff)
{
uint num = Cipher.BigEndianToUInt32(input, inOff);
uint num2 = Cipher.BigEndianToUInt32(input, inOff + 4);
uint num3 = ((num >> 4) ^ num2) & 252645135;
num2 ^= num3;
num ^= num3 << 4;
num3 = (((num >> 16) ^ num2) & 65535);
num2 ^= num3;
num ^= num3 << 16;
num3 = (((num2 >> 2) ^ num) & 858993459);
num ^= num3;
num2 ^= num3 << 2;
num3 = (((num2 >> 8) ^ num) & 16711935);
num ^= num3;
num2 ^= num3 << 8;
num2 = ((num2 << 1) | (num2 >> 31));
num3 = (uint)((int)(num ^ num2) & -1431655766);
num ^= num3;
num2 ^= num3;
num = ((num << 1) | (num >> 31));
for (int i = 0; i < 8; i++) {
num3 = ((num2 << 28) | (num2 >> 4));
num3 = (uint)((int)num3 ^ wKey[i * 4]);
uint num4 = SP7[num3 & 63];
num4 |= SP5[(num3 >> 8) & 63];
num4 |= SP3[(num3 >> 16) & 63];
num4 |= SP1[(num3 >> 24) & 63];
num3 = (uint)((int)num2 ^ wKey[i * 4 + 1]);
num4 |= SP8[num3 & 63];
num4 |= SP6[(num3 >> 8) & 63];
num4 |= SP4[(num3 >> 16) & 63];
num4 |= SP2[(num3 >> 24) & 63];
num ^= num4;
num3 = ((num << 28) | (num >> 4));
num3 = (uint)((int)num3 ^ wKey[i * 4 + 2]);
num4 = SP7[num3 & 63];
num4 |= SP5[(num3 >> 8) & 63];
num4 |= SP3[(num3 >> 16) & 63];
num4 |= SP1[(num3 >> 24) & 63];
num3 = (uint)((int)num ^ wKey[i * 4 + 3]);
num4 |= SP8[num3 & 63];
num4 |= SP6[(num3 >> 8) & 63];
num4 |= SP4[(num3 >> 16) & 63];
num4 |= SP2[(num3 >> 24) & 63];
num2 ^= num4;
}
num2 = ((num2 << 31) | (num2 >> 1));
num3 = (uint)((int)(num ^ num2) & -1431655766);
num ^= num3;
num2 ^= num3;
num = ((num << 31) | (num >> 1));
num3 = (((num >> 8) ^ num2) & 16711935);
num2 ^= num3;
num ^= num3 << 8;
num3 = (((num >> 2) ^ num2) & 858993459);
num2 ^= num3;
num ^= num3 << 2;
num3 = (((num2 >> 16) ^ num) & 65535);
num ^= num3;
num2 ^= num3 << 16;
num3 = (((num2 >> 4) ^ num) & 252645135);
num ^= num3;
num2 ^= num3 << 4;
Cipher.UInt32ToBigEndian(num2, outBytes, outOff);
Cipher.UInt32ToBigEndian(num, outBytes, outOff + 4);
}
}
}