WT86
WT86

Reputation: 833

DES Encryption is not working C#

I have wrote DES in C# from scratch, and I will post the whole code here, for me it seems right but when I'm trying an example it is not. Here is my entire code.

Des Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DES_Cipher
{
    class DES
    {
        string leftSide = "";
        string rightSide = "";
        string tempLeft = "";

        F_Function f = new F_Function();
        Key_Scheduler k = new Key_Scheduler();

        public string DESEncryption(string input, string Key)
        {
            input = String.Join(String.Empty,
  input.Select(
    c => Convert.ToString(Convert.ToInt32(c.ToString(), 16), 2).PadLeft(4, '0')
  )
);
            Key = String.Join(String.Empty,
  Key.Select(
    c => Convert.ToString(Convert.ToInt32(c.ToString(), 16), 2).PadLeft(4, '0')
  )
);
            // input = strtoBin(input);
            string chunk = "";
            string finalPerm = "";
            string result = "";
            string[] subKeys;

            //split the string into blocks of 64 bits
            IEnumerable<string> output = Enumerable.Range(0, input.Length / 64)
   .Select(x => input.Substring(x * 64, 64));
            string[] newInput = output.ToArray();

            //for each block 
            for (int i = 0; i < newInput.Length; i++)
            {
                //Initial Permutation
                chunk = initalPermutation(newInput[i]);

                //split the chunk in two halves 32 bit each
                leftSide = chunk.Substring(0, chunk.Length / 2);
                rightSide = chunk.Substring(chunk.Length / 2, chunk.Length / 2);
                subKeys = k.keySched(Key);

                for (int j = 0; j < 16; j++)
                {

                    //F Function on the right side
                    tempLeft = leftSide;
                    leftSide = rightSide;
                    rightSide = f.f_function(rightSide, subKeys[j]);
                    rightSide = XOR(tempLeft, rightSide);

                }

                finalPerm = rightSide + leftSide;
                finalPerm = finalPermutation(finalPerm);
                result = result + finalPerm;
            }
            result = BinaryStringToHexString(result);
            return result;
        }

        private string initalPermutation(string block)
        {


            char[] tempBlock ={block[57],block[49],block[41],block[33],block[25],block[17],block[9],block[1],
                             block[59],block[51],block[43],block[35],block[27],block[19],block[11],block[3],
                             block[61],block[53],block[45],block[37],block[29],block[21],block[13],block[5],
                             block[63],block[55],block[47],block[39],block[31],block[23],block[15],block[7],
                             block[56],block[48],block[40],block[32],block[24],block[16],block[8],block[0],
                             block[58],block[50],block[42],block[34],block[26],block[18],block[10],block[2],
                             block[60],block[52],block[44],block[36],block[28],block[20],block[12],block[4],
                             block[62],block[54],block[46],block[38],block[30],block[22],block[14],block[6]};
            string res = new string(tempBlock);
            return res;
        }

        private string finalPermutation(string block)
        {

            char[] tempBlock ={block[39],block[7],block[47],block[15],block[55],block[23],block[63],block[31],
                             block[38],block[6],block[46],block[14],block[54],block[22],block[62],block[30],
                             block[37],block[5],block[45],block[13],block[53],block[21],block[61],block[29],
                             block[36],block[4],block[44],block[12],block[52],block[20],block[60],block[28],
                             block[35],block[3],block[43],block[11],block[51],block[19],block[59],block[27],
                             block[34],block[2],block[42],block[10],block[50],block[18],block[58],block[26],
                             block[33],block[1],block[41],block[9],block[49],block[17],block[57],block[25],
                             block[32],block[0],block[40],block[8],block[48],block[16],block[56],block[24]};
            string res = new string(tempBlock);
            return res;
        }

        //convert string to binary function
        private string strtoBin(string input)
        {
            StringBuilder sb = new StringBuilder();
            foreach (char L in input)
            {
                sb.Append(Convert.ToString(L, 2).PadLeft(8, '0'));

            }

            return sb.ToString();
        }

        private string XOR(string expanedArray, string key)
        {
            string[] result = new string[key.Length];
            string res;
            char[] a = expanedArray.ToCharArray();
            char[] b = key.ToCharArray();

            for (int i = 0; i < key.Length; i++)
            {
                result[i] = (a[i] ^ b[i]).ToString();

            }
            res = string.Join("", result);
            return res;
        }
        private static string BinaryStringToHexString(string binary)
        {
            StringBuilder result = new StringBuilder(binary.Length / 8 + 1);

            // TODO: check all 1's or 0's... Will throw otherwise

            int mod4Len = binary.Length % 8;
            if (mod4Len != 0)
            {
                // pad to length multiple of 8
                binary = binary.PadLeft(((binary.Length / 8) + 1) * 8, '0');
            }

            for (int i = 0; i < binary.Length; i += 8)
            {
                string eightBits = binary.Substring(i, 8);
                result.AppendFormat("{0:X2}", Convert.ToByte(eightBits, 2));
            }

            return result.ToString();
        }

}
}

Key Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DES_Cipher
{
    class Key_Scheduler
    {
        public static String c0 = "";
        public static String d0 = "";
        public string[] keySched(string key)
        {

                string[] keys = new string[16];
                string  perm1 = "";

                    //Permutation Choice - 1
                    perm1 = permuatedchoice1(key);

                    //split the key in two halves 28 bit each
                    c0 = perm1.Substring(0, perm1.Length / 2);
                    d0 = perm1.Substring(perm1.Length / 2, perm1.Length / 2);

                    for (int i = 0; i < 16; i++)
                    {
                        keys[i] = GenerateKeys(c0, d0, i);

                    }

                    return keys;
            }

        private string GenerateKeys(string L, string R,int i)
        {
            string key;
            if (i == 0 || i == 1 || i == 8 || i == 15)
            {
                c0 = rotateShift(L, 1);
                d0 = rotateShift(R, 1);

                key = L + R;
                key = permuatedchoice2(key);
                return key;
            }

            else
            {
                c0 = rotateShift(L, 2);
                d0 = rotateShift(R, 2);

                key = L + R;
                key = permuatedchoice2(key);
                return key;
            }


        }

        private string rotateShift(string key, int shift)
        {
            string res="";
            string[] result = new string[key.Length];
            char[] a = key.ToCharArray();
            int index = 0;
            for (int i = shift;  index < a.Length; i++)
            {
                result[index++] = a[i % a.Length].ToString();
            }
            res = string.Join("", result);
            return res;
        }
        private string permuatedchoice1(string key)
        {
            string res;
            char[] tempArr ={key[56],key[48],key[40],key[32],key[24],key[16],key[8],key[0],
                            key[57],key[49],key[41],key[33],key[25],key[17],key[9],key[1],
                            key[58],key[50],key[42],key[34],key[26],key[18],key[10],key[2],
                            key[59],key[51],key[43],key[35],key[62],key[54],key[46],key[38],
                            key[30],key[22],key[14],key[6],key[61],key[53],key[45],key[37],
                            key[29],key[21],key[13],key[5],key[60],key[52],key[44],key[36],
                            key[28],key[20],key[12],key[4],key[27],key[19],key[11],key[3]};

            res = new string(tempArr);
            return res;
        }

        private string permuatedchoice2(string key)
        {
            string res;
            char[] tempArr ={key[13],key[16],key[10],key[23],key[0],key[4],key[2],key[27],
                            key[14],key[5],key[20],key[9],key[22],key[18],key[11],key[3],
                            key[25],key[7],key[15],key[6],key[26],key[19],key[12],key[1],
                            key[40],key[51],key[30],key[36],key[46],key[54],key[29],key[39],
                            key[50],key[44],key[32],key[47],key[43],key[48],key[38],key[55],
                            key[33],key[52],key[45],key[41],key[49],key[35],key[28],key[31]};

            res = new string(tempArr);
            return res;
        }

    }
}

And Finally, the F Function Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DES_Cipher
{
    class F_Function
    {
        #region SBoxes definition
        int[,] s1Box = {{14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7},
                     {0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8},
                     {4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0},
                     {15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13}};

        int[,] s2Box = {{15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10},
                       {3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5},
                       {0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15},
                       {13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9}};

        int[,] s3Box = {{10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8},
                       {13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1},
                       {13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7},
                       {1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12}};

        int[,] s4Box = {{7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15},
                       {13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9},
                       {10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4},
                       {3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14}};

        int[,] s5Box = {{2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9},
                      {14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6},
                      {4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14},
                      {11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3}};

        int[,] s6Box = {{12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11},
                      {10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8},
                      {9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6},
                      {4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13}};

        int[,] s7Box = {{4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1},
                       {13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6},
                       {1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2},
                       {6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12}};

        int[,] s8Box = {{13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7},
                       {1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2},
                       {7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8},
                       {2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11}};
        #endregion
        int[] expanstionArr = new int[48] { 31, 0, 1, 2, 3, 4,
                                            3, 4, 5, 6, 7, 8, 
                                            7, 8, 9, 10, 11, 12,
                                            11, 12, 13, 14, 15, 16,
                                            15, 16, 17, 18, 19, 20, 
                                            19, 20, 21, 22, 23, 24,
                                            23, 24, 25, 26, 27, 28, 
                                            27, 28, 29, 30, 31, 1 };

        int[] permutationMatrix = new int[32] { 15, 6, 19, 20, 28, 11, 27, 16,
                                                0, 14, 22, 25, 4, 17, 30, 9, 
                                                1, 7, 23, 13, 31, 26, 2, 8, 
                                                18, 12, 29, 5, 21, 10, 3, 24 };

        Key_Scheduler key = new Key_Scheduler();
        public string f_function(string input, string mainKey)
        {
            string res, exp, xor, sboxsub, perm;
            exp = expansion(input);
            //subKey =key.keySched(mainKey);
            int a = mainKey.Length - exp.Length;
            xor=XORwithKey(exp,mainKey);
            sboxsub = SBoxSubstitution(xor);
            perm = permutation(sboxsub);
            res = perm;
            return res;
        }
        private string expansion (string rightSide )
        {
            char[] arr = new char[48];
            int len = rightSide.Length;

            for (int i = 0; i < arr.Length; i++)
            {
                arr[i] = rightSide[expanstionArr[i]];

            }
            string res = new string(arr);
            return res;
        }
        private string XORwithKey(string expanedArray,string key)
        {
            string[] result = new string[key.Length];
            string res;
            char[] a = expanedArray.ToCharArray();
            char[] b = key.ToCharArray();

            for (int i = 0; i < key.Length; i++)
            {
                result[i] = (a[i] ^ b[i]).ToString();

            }
            res = string.Join("", result);
            return res;
        }

        private string SBoxSubstitution(string input)
        {
            string res="";
            string r;
            int row, col, s1, s2, s3, s4, s5, s6, s7, s8;
            string c;
            char[] temp;
            IEnumerable<string> output = Enumerable.Range(0, input.Length / 6)
              .Select(x => input.Substring(x * 6, 6));
            string[] newInput = output.ToArray();

            for (int i = 0; i < newInput.Length; i++)
            {
                temp = newInput[i].ToCharArray();
                r = temp[0].ToString()+temp[5].ToString();
                row = Convert.ToInt32(r,2);
                c = temp[1].ToString() + temp[2].ToString() + temp[3].ToString() + temp[4].ToString();
                col = Convert.ToInt32(c,2);
                if (i == 0)
                {
                    s1 = SBoxSearch(row, col, s1Box);
                    res += s1.ToString();
                }
                else if (i == 1)
                {
                    s2 = SBoxSearch(row, col, s2Box);
                    res += s2.ToString();
                }
                else if (i == 2)
                {
                    s3 = SBoxSearch(row, col, s3Box);
                    res += s3.ToString();
                }
                else if (i == 3)
                {
                    s4 = SBoxSearch(row, col, s4Box);
                    res += s4.ToString();
                }
                else if (i == 4)
                {
                    s5 = SBoxSearch(row, col, s5Box);
                    res += s5.ToString();
                }
                else if (i == 5)
                {
                    s6 = SBoxSearch(row, col, s6Box);
                    res += s6.ToString();
                }
                else if (i == 6)
                {
                    s7 = SBoxSearch(row, col, s7Box);
                    res += s7.ToString();
                }
                else
                {
                    s8 = SBoxSearch(row, col, s8Box);
                    res += s8.ToString();
                }
            }

            res = strtoBin(res);
            return res;
        }

        private string permutation(string input)
        {
            char[] arr = new char[32];

            for (int i = 0; i < arr.Length; i++)
            {
                arr[i] = input[permutationMatrix[i]];

            }
            string res = new string(arr);

            return res;
        }

        private int SBoxSearch(int row, int col, int[,] sBox)
        {
            int res=0;
            for (int i = 0; i < 4; i++)
            {
                if (i == row)
                {
                    for (int j = 0; j < 16; j++)
                    {
                        if (j == col)
                        { 
                            res = sBox[i, j];
                            break;
                        }
                        else continue;
                    }
                    break;
                }
                else continue;
            }
            return res;
        }

        private string strtoBin(string input)
        {
            StringBuilder sb = new StringBuilder();
            foreach (char L in input)
            {
                sb.Append(Convert.ToString(L, 2).PadLeft(8, '0'));

            }

            return sb.ToString();
        }


    }
}

When I'm testing it, btw all inputs are in hex, my input is: 02468aceeca86420

Used key is:

0f1571c947d9e859

the encryption output should be:

da02ce3a89ecac3b

But I'm getting this output instead:

019945B853663D50

I double checked everything and I really don't know what I did wrong here ... Pardon me for the messy code but it was written in less than a day :/

Thank you for any tip

Upvotes: 2

Views: 1392

Answers (3)

J.Kivi
J.Kivi

Reputation: 1

This is almost complete code for beginner like me to start learning to use DES. How about making some corrections so everyone don't need to follow the same debugging and fixing job (or better if they do this). Some of helping links are gone but something useful is out there. I was using http://page.math.tu-berlin.de/~kant/teaching/hess/krypto-ws2006/des.htm and http://people.eku.edu/styere/Encrypt/JS-DES.html (with modified not readonly)

  • first key must be the last keys[15] and every next is keys[i-1]
  • strtoBin is very wrong there. After discarding it there is better output directly binarray from SBoxSubstitution by forming output res like res += Convert.ToString(s1, 2).PadLeft(4, '0'); in first if (i == 1) and so on
  • last number in expanstionArr must be 0 of course

After those 3 modifications I got the DESEncryption working.

And what you know... decrypting is working too without any other repair :) For that you copy whole DESEncryption to "DESDecryption" and change only (int j = 0; j < 16; j++) to for (int j = 15; j >= 0; j--)

Upvotes: 0

user1155120
user1155120

Reputation:

The encrypt test vector (0F1571C947D9E859 02468ACEECA86420 DA02CE3A89ECAC3B) is valid, I checked against standard compliant implementation.

The way to trouble shoot a new DES implementation is to compare round values against a known implementation, such as using a DES Calculator that produces round values. You could likewise copy a known good implementation and modify it to output round values. It also means producing the same values for your implementation each round.

The failure will show up in your implementation of one or more of the permutations, the key schedule or it's shift direction, or programming language syntax or semantics.

It's easier to compare binary results when you're dealing with strings of 1's and 0's.

There's also a javascript implementation of DES found on google code: JS-DES.html, and if you want the missing images from the bottom of the page they can be found at JS-DES_fichiers. Save the images in a sub directory named JS-DES_fichiers.

This is what it produces for

Key: 0F1571C947D9E859
Input: 02468ACEECA86420
(Expected output: DA02CE3A89ECAC3B)

Input bits: 00000010 01000110 10001010 11001110 11101100 10101000 01100100 00100000
Key bits: 00001111 00010101 01110001 11001001 01000111 11011001 11101000 01011001
CD[0]:  0110100 0111111 0001000 1001010 0001000 1000100 1111101 0010110
CD[1]:  1101000 1111110 0010001 0010100 0010001 0001001 1111010 0101100
KS[1]:  011110 000011 001111 000011 001000 001101 101001 110000
CD[2]:  1010001 1111100 0100010 0101001 0100010 0010011 1110100 1011000
KS[2]:  001010 110001 101001 110100 110010 100100 100011 011000
CD[3]:  1000111 1110001 0001001 0100110 0001000 1001111 1010010 1100001
KS[3]:  100011 000111 100011 011000 100000 011101 001100 011101
CD[4]:  0011111 1000100 0100101 0011010 0100010 0111110 1001011 0000100
KS[4]:  000101 100110 011101 111000 100100 110001 011010 100000
CD[5]:  1111110 0010001 0010100 1101000 0001001 1111010 0101100 0010001
KS[5]:  110011 100101 110100 000001 110110 000000 101100 100101
CD[6]:  1111000 1000100 1010011 0100011 0100111 1101001 0110000 1000100
KS[6]:  010010 111010 101101 001101 000100 100110 101010 011100
CD[7]:  1100010 0010010 1001101 0001111 0011111 0100101 1000010 0010001
KS[7]:  000010 011111 010010 001011 011100 010011 000110 010001
CD[8]:  0001000 1001010 0110100 0111111 1111101 0010110 0001000 1000100
KS[8]:  011100 010000 110111 101010 101000 110010 000000 101011
CD[9]:  0010001 0010100 1101000 1111110 1111010 0101100 0010001 0001001
KS[9]:  000100 101001 101010 111000 001100 110100 011111 000011
CD[10]:  1000100 1010011 0100011 1111000 1101001 0110000 1000100 0100111
KS[10]:  100111 000011 100001 100110 000111 101000 000100 000011
CD[11]:  0010010 1001101 0001111 1100010 0100101 1000010 0010001 0011111
KS[11]:  101000 100110 111001 001100 110001 100110 010101 000100
CD[12]:  1001010 0110100 0111111 0001000 0010110 0001000 1000100 1111101
KS[12]:  010010 000111 011100 100100 011010 001010 001111 001000
CD[13]:  0101001 1010001 1111100 0100010 1011000 0100010 0010011 1110100
KS[13]:  110000 001001 110101 111001 111100 001101 010000 001011
CD[14]:  0100110 1000111 1110001 0001001 1100001 0001000 1001111 1010010
KS[14]:  110001 011110 001001 100011 010011 100001 011000 101010
CD[15]:  0011010 0011111 1000100 0100101 0000100 0100010 0111110 1001011
KS[15]:  101000 111101 111110 000010 100111 000111 100101 101000
CD[16]:  0110100 0111111 0001000 1001010 0001000 1000100 1111101 0010110
KS[16]:  101001 100001 001000 001011 010011 010100 110000 100101
L[0]:  01011010 00000000 01011010 00000000
R[0]:  00111100 11110000 00111100 00001111
Round 1
E   :  100111 111001 011110 100000 000111 111000 000001 011110
KS  :  011110 000011 001111 000011 001000 001101 101001 110000
E xor KS:  111001 111010 010001 100011 001111 110101 101000 101110
Sbox:  1010 0011 0010 1111 0001 0001 1100 0010
P   : 11100000 11010010 01110010 01000101
L[i]: 00111100 11110000 00111100 00001111
R[i]: 10111010 11010010 00101000 01000101
Round 2
E   :  110111 110101 011010 100100 000101 010000 001000 001011
KS  :  001010 110001 101001 110100 110010 100100 100011 011000
E xor KS:  111101 000100 110011 010000 110111 110100 101011 010011
Sbox:  0110 1000 1111 0001 1001 0100 0100 0101
P   : 10100101 00011001 10001011 00101100
L[i]: 10111010 11010010 00101000 01000101
R[i]: 10011001 11101001 10110111 00100011
Round 3
E   :  110011 110011 111101 010011 110110 101110 100100 000111
KS  :  100011 000111 100011 011000 100000 011101 001100 011101
E xor KS:  010000 110100 011110 001011 010110 110011 101000 011010
Sbox:  0011 1100 1000 1111 1111 1110 1100 0000
P   : 10110001 01111100 00010011 11011011
L[i]: 10011001 11101001 10110111 00100011
R[i]: 00001011 10101110 00111011 10011110
Round 4
E   :  000001 010111 110101 011100 000111 110111 110011 111100
KS  :  000101 100110 011101 111000 100100 110001 011010 100000
E xor KS:  000100 110001 101000 100100 100011 000110 101001 011100
Sbox:  1101 1011 1000 1001 1000 1111 0001 1100
P   : 11011011 10101000 11100001 01101010
L[i]: 00001011 10101110 00111011 10011110
R[i]: 01000010 01000001 01010110 01001001
Round 5
E   :  101000 000100 001000 000010 101010 101100 001001 010010
KS  :  110011 100101 110100 000001 110110 000000 101100 100101
E xor KS:  011011 100001 111100 000011 011100 101100 100101 110111
Sbox:  0101 1101 1110 1000 1110 1100 1101 0000
P   : 00010011 00011101 11000001 11011111
L[i]: 01000010 01000001 01010110 01001001
R[i]: 00011000 10110011 11111010 01000001
Round 6
E   :  100011 110001 010110 100111 111111 110100 001000 000010
KS  :  010010 111010 101101 001101 000100 100110 101010 011100
E xor KS:  110001 001011 111011 101010 111011 010010 100010 011110
Sbox:  0101 0010 0101 1011 0100 1101 0100 0111
P   : 11010100 01010111 10101000 01101010
L[i]: 00011000 10110011 11111010 01000001
R[i]: 10010110 00010110 11111110 00100011
Round 7
E   :  110010 101100 000010 101101 011111 111100 000100 000111
KS  :  000010 011111 010010 001011 011100 010011 000110 010001
E xor KS:  110000 110011 010000 100110 000011 101111 000010 010110
Sbox:  1111 0110 0001 0000 1011 1010 1011 1110
P   : 01111111 10100010 10000110 10110011
L[i]: 10010110 00010110 11111110 00100011
R[i]: 01100111 00010001 01111100 11110010
Round 8
E   :  001100 001110 100010 100010 101111 111001 011110 100100
KS  :  011100 010000 110111 101010 101000 110010 000000 101011
E xor KS:  010000 011110 010101 001000 000111 001011 011110 001111
Sbox:  0011 1010 0101 0000 1100 1100 0001 0100
P   : 01010111 00001101 00000010 00101010
L[i]: 01100111 00010001 01111100 11110010
R[i]: 11000001 00011011 11111100 00001001
Round 9
E   :  111000 000010 100011 110111 111111 111000 000001 010011
KS  :  000100 101001 101010 111000 001100 110100 011111 000011
E xor KS:  111100 101011 001001 001111 110011 001100 011110 010000
Sbox:  0101 1111 0011 0011 1111 0110 0001 1010
P   : 11101111 01101110 11000000 10011110
L[i]: 11000001 00011011 11111100 00001001
R[i]: 10001000 01111111 10111100 01101100
Round 10
E   :  010001 010000 001111 111111 110111 111000 001101 011001
KS  :  100111 000011 100001 100110 000111 101000 000100 000011
E xor KS:  110110 010011 101110 011001 110000 010000 001001 011010
Sbox:  0111 0000 0000 0001 1111 0000 0100 0000
P   : 10100001 00010100 10000010 10000010
L[i]: 10001000 01111111 10111100 01101100
R[i]: 01100000 00001111 01111110 10001011
Round 11
E   :  101100 000000 000001 011110 101111 111101 010001 010110
KS  :  101000 100110 111001 001100 110001 100110 010101 000100
E xor KS:  000100 100110 111000 010010 011110 011011 000100 010010
Sbox:  1101 1011 0101 0010 1001 1011 0010 1001
P   : 01111101 11101001 11101100 00000010
L[i]: 01100000 00001111 01111110 10001011
R[i]: 11110101 10010110 01010000 01101110
Round 12
E   :  011110 101011 110010 101100 001010 100000 001101 011101
KS  :  010010 000111 011100 100100 011010 001010 001111 001000
E xor KS:  001100 101100 101110 001000 010000 101010 000010 010101
Sbox:  1011 1101 0000 0000 1000 1000 1011 0110
P   : 00010011 10001010 01000110 00110011
L[i]: 11110101 10010110 01010000 01101110
R[i]: 01110011 10000101 00111000 10111000
Round 13
E   :  001110 100111 110000 001010 100111 110001 010111 110000
KS  :  110000 001001 110101 111001 111100 001101 010000 001011
E xor KS:  111110 101110 000101 110011 011011 111100 000111 111011
Sbox:  0000 0001 0000 0100 1001 1011 0111 0101
P   : 00110011 00110000 01111100 00100000
L[i]: 01110011 10000101 00111000 10111000
R[i]: 11000110 10100110 00101100 01001110
Round 14
E   :  011000 001101 010100 001100 000101 011000 001001 011101
KS  :  110001 011110 001001 100011 010011 100001 011000 101010
E xor KS:  101001 010011 011101 101111 010110 111001 010001 110111
Sbox:  0100 0000 1111 1000 1111 0110 1110 0000
P   : 00100101 00110101 10000101 11001101
L[i]: 11000110 10100110 00101100 01001110
R[i]: 01010110 10110000 10111101 01110101
Round 15
E   :  101010 101101 010110 100001 010111 111010 101110 101010
KS  :  101000 111101 111110 000010 100111 000111 100101 101000
E xor KS:  000010 010000 101000 100011 110000 111101 001011 000010
Sbox:  0100 1001 1000 1111 1111 1000 1001 0010
P   : 10110011 01001110 11010001 11000001
L[i]: 01010110 10110000 10111101 01110101
R[i]: 01110101 11101000 11111101 10001111
Round 16
E   :  101110 101011 111101 010001 011111 111011 110001 011110
KS  :  101001 100001 001000 001011 010011 010100 110000 100101
E xor KS:  000111 001010 110101 011010 001100 101111 000001 111011
Sbox:  0100 1011 1110 1100 1011 1010 1101 0101
P   : 01110011 00111001 11011001 11100101
L[i]: 01110101 11101000 11111101 10001111
R[i]: 00100101 10001001 01100100 10010000
LR[16]  00100101 10001001 01100100 10010000 01110101 11101000 11111101 10001111
Output  11011010 00000010 11001110 00111010 10001001 11101100 10101100 00111011

Output message da02ce3a89ecac3b

Upvotes: 1

andrei.ciprian
andrei.ciprian

Reputation: 3025

This is the implementation of the DES algorithm, as specified by the NIST in publication FIPS PUB 197, availible on the NIST website, here. The algorithm takes 64 bit blocks and encrypts them using a 56 bit key, producing a 64 bit output in the classic case with no padding or zero padding. Your implementation should use bitwise operations over 8 byte arrays, not hex string representations of length 16, or char[32] like you do in your permutations. Obviously permutations, shifts or rotations of char arrays of size 16 or 32 are not idempotent with same operations over 64 bit values described in the algorithm and adjustments should be made. Not only this approach is bug prone, but it is also much slower. Answering this would mean debugging and fixing your code which is beyond the purpose of this site imho, and since this looks like a homework to me (prove me wrong) I am going to preach this small DESCryptoServiceProvider wrapper.

static class DesCsp
{

  public static byte[] EncryptBytes(byte[] input, byte[] desKey, byte[] desIV)
  {
    DES des = new DESCryptoServiceProvider();
    des.Padding = PaddingMode.None;
    var enc = des.CreateEncryptor(desKey, desIV);
    return enc.TransformFinalBlock (input, 0, input.Length);    
  }

  public static byte[] DecryptBytes(byte[] encryptedOutput, byte[] desKey, byte[] desIV)
  {
    DES des = new DESCryptoServiceProvider();
    des.Padding = PaddingMode.None;
    var dec = des.CreateDecryptor(desKey, desIV);
    return dec.TransformFinalBlock(encryptedOutput, 0, encryptedOutput.Length);
  }

  public static string EncryptHexStrings(string input, byte[] desKey, byte[] desIV)
  {
    byte[] bytes = HexStringToByteArray(input);
    byte[] encBytes = EncryptBytes (bytes,desKey,desIV);
    return ByteArrayToHexString(encBytes);
  }

  public static string DecryptHexStrings(string encryptedOutput, byte[] desKey, byte[] desIV)
  {
    byte[] bytes = HexStringToByteArray(encryptedOutput);
    byte[] decBytes = DecryptBytes(bytes,desKey,desIV);
    return ByteArrayToHexString(decBytes);
  }

  public static string EncryptHexStrings(string input, string desKey, string desIV)
  {
    byte[] key = HexStringToByteArray(desKey);
    byte[] iv = HexStringToByteArray(desIV);
    return EncryptHexStrings(input, key, iv);
  }

  public static string DecryptHexStrings(string encryptedOutput, string desKey, string desIV)
  {
    byte[] key = HexStringToByteArray(desKey);
    byte[] iv = HexStringToByteArray(desIV);
    return DecryptHexStrings(encryptedOutput,key,iv);
  }

  public static byte[] HexStringToByteArray(string s)
  {
    byte[] ret = new byte[s.Length / 2];
    for (int i=0; i<s.Length; i+=2)
    {
      ret[i/2] = Convert.ToByte (s.Substring (i,2), 16);      
    }
    return ret;
  }

  public static string ByteArrayToHexString(byte[] bytes)
  {
    StringBuilder sb = new StringBuilder();
    foreach (byte b in bytes)
      sb.AppendFormat("{0:X2}", b);
    return sb.ToString();
  }

}

Check it like this, with your data:

// the encryption output should be: da02ce3a89ecac3b
// But I'm getting this output instead: 019945B853663D50
string inputString = "02468aceeca86420";
string stringkey = "0f1571c947d9e859";
string encryptedReference = "da02ce3a89ecac3b";
string siv = "0000000000000000";
encryptedString = DesCsp.EncryptHexStrings(inputString, stringkey, siv);
decryptedString = DesCsp.DecryptHexStrings(encryptedString, stringkey, siv);
Debug.Assert(inputString.ToUpper() == decryptedString.ToUpper());
Debug.Assert(encryptedString.ToUpper() == encryptedReference.ToUpper());

The symmetric encryption algorithms in System.Security.Cryptography also have an initialization vector, but you needn't worry about that. Just like this wrapper you could use your EncryptBytes(byte[] input, byte[] desKey) method all over the place. For your public static string EncryptHexStrings(string input, string desKey) you'd adapt the input string to a byte array, encrypt it as bytes, make a hex string out of the encrypted bytes on return.

Upvotes: 0

Related Questions