DES加密原理学习,C#代码演示示例——加密与解密(一)

(本示例仿照DES的加解密原理,使用C#编码,仅提供学习参考)

一:定义一个静态类DesEntry,在其中实现一个静态方法,其大体流程框架如下

1输入64位一组的明文,记为group

2初始置换
3,for i=0 to 15

  {//设Lp,Rp分别为前一轮的左边32位与右32位,Lc,Rc同理为当前轮次与Lp,Rp相应的值
            3.1,Lc=Rp:将右32位换到左边,Rp代表前一轮的右边32位
            3.2,Rc=Lp^f(Rp,Kc):求取本轮右边32位,f为转换函数
            3.3, 将Rp扩展置换成48位的新值并与Kc对合

    3.4将上一项获得的新值以<b1,b2,b3,b4,b5,b6>形式分成8组,取b1b6构成的2位二进制数值,b2b3b4b5构成的4位二进制数值分别作为从S盒中的行和列索引,
              从S盒中置换出相应的值(S[分组索引][行索引][列索引]),得到新的32位值
           3.5,再次将新值使用一个特定的置换函数置换成新的值
            3.6,将新值与Lp对合成新值
            3.7 串接LcRc,返回
              

  }

4,初始置换逆向

5,输出

加密解密采用相同算法

代码如下:

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

namespace JoeDES
{
    public static class DESEntry64
    {
        #region 加密
        //初始置换数组(64位),简称IP盒
        static int[] IP = new int[64] {
                                    58, 50, 42, 34, 26, 18, 10, 2,
                                    60, 52, 44, 36, 28, 20, 12, 4,
                                    62, 54, 46, 38, 30, 22, 14, 6,
                                    64, 56, 48, 40, 32, 24, 16, 8,
                                    57, 49, 41, 33, 25, 17, 9, 1 ,
                                    59, 51, 43, 35, 27, 19, 11, 3,
                                    61, 53, 45, 37, 29, 21, 13, 5,
                                    63, 55, 47, 39, 31, 23, 15, 7
                                    };
        //初始置换逆变换数组,简称IP_1盒
        static int[] IP_1 = new int[64] {
                                    40, 8, 48, 16, 56, 24, 64, 32,
                                    39, 7, 47, 15, 55, 23, 63, 31,
                                    38, 6, 46, 14, 54, 22, 62, 30,
                                    37, 5, 45, 13, 53, 21, 61, 29,
                                    36, 4, 44, 12, 52, 20, 60, 28,
                                    35, 3, 43, 11, 51, 19, 59, 27,
                                    34, 2, 42, 10, 50, 18, 58, 26,
                                    33, 1, 41, 9, 49, 17, 57, 25
                                     };

        //S盒 (特定)
        static int[][][] S = new int[8][][];


        static DESEntry64()
        {
            
            S[0] = new int[4][];
            S[1] = new int[4][];
            S[2] = new int[4][];
            S[3] = new int[4][];
            S[4] = new int[4][];
            S[5] = new int[4][];
            S[6] = new int[4][];
            S[7] = new int[4][];
            S[0][0] = new int[] { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, };
            S[0][1] = new int[] { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, };
            S[0][2] = new int[] { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, };
            S[0][3] = new int[] { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, };
            S[1][0] = new int[] { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, };
            S[1][1] = new int[] { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, };
            S[1][2] = new int[] { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, };
            S[1][3] = new int[] { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, };
            S[2][0] = new int[] { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, };
            S[2][1] = new int[] { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 13, 11, 15, 1, };
            S[2][2] = new int[] { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, };
            S[2][3] = new int[] { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, };
            S[3][0] = new int[] { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, };
            S[3][1] = new int[] { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, };
            S[3][2] = new int[] { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, };
            S[3][3] = new int[] { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, };
            S[4][0] = new int[] { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, };
            S[4][1] = new int[] { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, };
            S[4][2] = new int[] { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, };
            S[4][3] = new int[] { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, };
            S[5][0] = new int[] { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, };
            S[5][1] = new int[] { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, };
            S[5][2] = new int[] { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, };
            S[5][3] = new int[] { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, };
            S[6][0] = new int[] { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, };
            S[6][1] = new int[] { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, };
            S[6][2] = new int[] { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, };
            S[6][3] = new int[] { 6, 11, 12, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, };
            S[7][0] = new int[] { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, };
            S[7][1] = new int[] { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, };
            S[7][2] = new int[] { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, };
            S[7][3] = new int[] { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11, };
        }
        /// <summary>
        /// 加密64位明文
        /// </summary>
        /// <param name="plainText6"></param>
        /// <returns></returns>
        public static UInt64 Entry(UInt64 plainText64, UInt64 Key)
        {
           
            return  EntryAndDecrySharedMethod(plainText64, Key, true); ;

        }


        private static UInt64 InitialPlace(UInt64 plainText64)
        {
            return IPlace(plainText64, IP);
        }
        private static UInt64 InitialReversePlace(UInt64 plainText64)
        {
            return IPlace(plainText64, IP_1);
        }
        /// <summary>
        /// DES初始换置与逆置换
        /// </summary>
        /// <param name="plainText64">等价于UInt64二进制形式的明文输入</param>
        /// <param name="placeArray">等价于IP盒或IP_1盒的数组</param>
        /// <returns></returns>
        private static UInt64 IPlace(UInt64 plainText64, int[] placeArray)
        {
            UInt64 result = 0;
            //缓存结果
            //将输入参数的每个字节转化为二进制字符串形式,以方便对每个位进行位置变动
            //string operatorTempSb = data.ConvertToBitsString();//用于进行位置互换的辅助变量
            UInt64 tempData = plainText64;
            //按照初始置换数组置换明文中的每一位二进制并输出到结果中
            for (int i = 0; i < 64; i++)
            {
                tempData = plainText64 >> (64 - placeArray[i]);
                tempData = (tempData << 63);//
                tempData = tempData >> i;
                result = result ^ tempData;
                //result = Convert.ToInt64(operatorTempSb, 2);

            }
            return result;
        }


        //分组扩展
        /// <summary>
        /// 扩展分组右32位到48位
        /// </summary>
        /// <param name="rightOfGroup32">包含分组右32位信息的输入(变量的低32位)</param>
        /// <returns>返回被扩展的信息(值的低48位部分)</returns>
        /// <remarks>E扩展,将32位二进制符号分为8组,每组头和尾部分别新增一个二进制位,前部为前一个索引对应的符号,尾部
        /// 为后一个索引对应的符号,其中第一组的前部为原来32位数的第32位,最后一组的尾部添加原32位符号的第一位符号。如下列表所示
        /// 32, 1, 2, 3, 4, 5,
        /// 4,  5, 6, 7, 8, 9,
        /// 8,  9,10,11,12,13,
        /// 12,13,14,15,16,17,
        /// 16,17,18,19,20,21,
        /// 20,21,22,23,24,25,
        /// 24,25,26,27,28,29,
        /// 28,29,30,31,32, 1
        /// </remarks>
        private static UInt64 ExtensionGroupRight32(UInt64 rightOfGroup32)
        {
            UInt64 result = 0;
            UInt64 temp = (UInt64)0x1;
            temp = rightOfGroup32 & temp;
            temp = temp << 32;
            rightOfGroup32 = rightOfGroup32 ^ temp;
            temp = (UInt64)0x1 << 31;
            temp = (rightOfGroup32 & temp) >> 31;//提取第1位值
            //将第1位放到最后一位上
            rightOfGroup32 = (rightOfGroup32 << 1) ^ temp;

            for (int i = 0; i < 8; i++)
            {
                //
                result = result ^ ((rightOfGroup32 >> (28 - i * 4)) & (UInt64)0x3F);
                if (i < 7)
                {
                    result = result << 6;
                }
            }
            return result;
        }



        /// <summary>
        /// 加密分组右32位
        /// </summary>
        /// <param name="rightOfGroup">包含分组右边的32位二进制码信息(参数低32位)</param>
        /// <param name="skey"></param>
        /// <returns></returns>
        private static UInt64 EntryRight32(UInt64 rightOfGroup, UInt64 skey)
        {
            UInt64 result = 0;
            //将低32位扩展到48位
            UInt64 ERi = ExtensionGroupRight32(rightOfGroup);



            //S盒置换
            result = GetValueFromS(ERi, skey);

            //P置换
            result = SubPlaceFunction(result);

            return result;
        }
        /// <summary>
        /// 分组右32位置换函数
        /// </summary>
        /// <param name="RightOfGroup32"></param>
        /// <returns></returns>
        private static UInt64 SubPlaceFunction(UInt64 RightOfGroup32)
        {
            int[] pCase = new int[32] {
                                    16,7,20,21,
                                    29,12,28,17,
                                    1,15,23,26,
                                    5,18,31,10,
                                    2,8,24,14,
                                    32,27,3,9,
                                    19,13,30,6,
                                    22,11,4,25
                                     };
            UInt64 result = 0;
            //缓存结果
            UInt32 cacheData = (UInt32)RightOfGroup32;
            UInt32 tempData = 0;

            //按照初始置换数组置换明文中的每一位二进制并输出到结果中
            for (int i = 0; i < 32; i++)
            {
                tempData = cacheData >> (32 - pCase[i]);
                tempData = (tempData << 31);//
                tempData = tempData >> i;
                result = result ^ tempData;
                //result = Convert.ToInt64(operatorTempSb, 2);

            }
            return result;
        }


        /// <summary>
        /// 对合,并通过S盒获取新值
        /// </summary>
        /// <param name="rightOfGroup48">通过E盒扩展到48位的一个等价的UInt64</param>
        /// <param name="skey">子密钥的等价UInt64(其中的低48位作为有效值)</param>
        /// <returns></returns>
        private static UInt64 GetValueFromS(UInt64 rightOfGroup48, UInt64 skey)
        {
            //使用轮skey对合rightOfGroup48成新的值
            UInt64 cacheB = rightOfGroup48 ^ skey;//将低48位记为8个(b1,b2,b3,b4,b5,b6)的组合
            //
            UInt64 result = 0;
            UInt64 tempForRowLow = 0x1;//提取(b1,b2,b3,b4,b5,b6)最低一位b6
            UInt64 tempForRowHigh = 0x20;//提取(b1,b2,b3,b4,b5,b6)最高一位b1
            UInt64 tempForColumn = 0xF;//提取(b2,b3,b4,b5)
            for (int i = 0; i < 8; i++)
            {
                UInt64 tempData = cacheB >> (42 - 6 * i);//将6位(b1,b2,b3,b4,b5,b6)移动到最末位以便获取对应S盒的置换索引,”b1b6“为行索引,”b2b3b4b5“为列索引
                UInt64 rowIndex = (tempData & tempForRowLow) + ((tempData & tempForRowHigh) >> 4);
                UInt64 columnIndex = ((tempData >> 1) & tempForColumn);
                //从S盒中置换新的值并串接到结果当中
                result = result ^ (UInt64)S[i][rowIndex][columnIndex];
                if (i < 7)
                {
                    result = result << 4;
                }

            }
            return result;
        }
        #endregion

        #region 解密
        /// <summary>
        /// 与加密算法相同
        /// </summary>
        /// <param name="ChiperText64"></param>
        /// <param name="Key"></param>
        /// <returns></returns>
        public static UInt64 Decrypt(UInt64 ChiperText64, UInt64 Key)
        {
            return EntryAndDecrySharedMethod(ChiperText64,Key,false);
        }
        #endregion
        /// <summary>
        /// 加解密采用的相同的算法
        /// </summary>
        /// <param name="ChiperText64"></param>
        /// <param name="Key"></param>
        /// <returns></returns>
        private static UInt64 EntryAndDecrySharedMethod(UInt64 ChiperText64, UInt64 Key,bool IsEntry)
        {

            //获取子密钥数组
            UInt64[] sKeys = GetSubKeys(Key);
            if (!IsEntry)
            {
                sKeys = sKeys.Reverse().ToArray();
            }
            //设Lp,Rp分别为前一轮的左边32位与右32位,Lc,Rc同理为当前轮次与Lp,Rp相应的值
            UInt64 group0 = ChiperText64;
            //初始置换
            group0 = InitialPlace(group0);
            UInt64 Lp = (UInt64)((group0 & 0xFFFFFFFF00000000) >> 32);
            UInt64 Rp = (UInt64)(group0 & 0xFFFFFFFF);
            UInt64 Lc = 0;
            UInt64 Rc = 0;
            //for i=0 to 15
            for (int i = 0; i < 15; i++)
            {
                //Lc=Rp:将右32位换到左边,Rp代表前一轮的右边32位
                Lc = Rp;
                //Rc=Lp^f(Rp,Kc):求取本轮右边32位,f为转换函数
                Rc = Lp ^ EntryRight32(Rp, sKeys[i]);
               
                Lp = Lc; Rp = Rc;
            }
            //最后的一轮不调换左右
            Lc = Rp;
            Rc = EntryRight32(Rp, sKeys[15]);
            Rc = Lp ^ Rc;
            //归并
            group0 = (Rc << 32) ^ Lc;

            //逆置换
            group0 = InitialReversePlace(group0);
            return group0;
        }



        #region 子密钥生成
        //剔除校验位,打乱密钥顺序的PC-1盒
        public static int[] PC_1 = new int[56]
        {
            57, 49, 41, 33, 25, 17,  9,
            1 , 58, 50, 42, 34, 26, 18,
            10,  2, 59, 51, 43, 35, 27,
            19, 11,  3, 60, 52, 44, 36,
            63, 55, 47, 39, 31, 23, 15,
             7, 62, 54, 46, 38, 30, 22,
            14,  6, 61, 53, 45, 37, 29,
            21, 13,  5, 28, 20, 12,  4
        };
        //从由key经过PC-1置换、移位等操作后的56位值中置换选择
        public static int[] PC_2 = new int[48]
        {
            14 ,17 ,11, 24 , 1 , 5,
            3,  28 ,15,  6 ,21 ,10,
            23 ,19 ,12,  4 ,26 , 8,
            16 , 7 ,27, 20 ,13 , 2,
            41 ,52 ,31, 37 ,47 ,55,
            30 ,40 ,51, 45 ,33 ,48,
            44 ,49 ,39, 56 ,34 ,53,
            46 ,42 ,50, 36 ,29 ,32
        };
        /// <summary>
        /// 生成16个子密钥
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static UInt64[] GetSubKeys(UInt64 key)
        {
            UInt64[] skeys = new ulong[16];
            //PC-1置换,去校验并置换新的56位有效值

            UInt64 cache56 = 0;//缓存
            UInt64 getBit = 0;
            for (int i = 0; i < 56; i++)
            {
                getBit = key >> (64 - PC_1[i]) & (UInt64)0x1;
                cache56 = cache56 ^ getBit;
                if (i < 55)
                {
                    cache56 = cache56 << 1;
                }

            }

            //for i=0 to 15
            //移位归并置换生成
            for (int i = 0; i < 16; i++)
            {


                UInt32 C = (UInt32)(cache56 >> 28);
                UInt32 D = (UInt32)(cache56 << 4) >> 4;

                if (i == 0 || i == 1 || i == 8 || i == 15)
                {
                    UInt32 temp = (C >> 27) & (UInt32)(0x1);
                    C = (C << 1) & (0x0FFFFFFF) ^ temp;
                    temp = (D >> 27) & (UInt32)0x1;
                    D = (D << 1) & (0x0FFFFFFF) ^ temp;
                }
                else
                {
                    UInt32 temp = C >> 26 & (UInt32)(0x3);//提取头2位
                    C = ((C << 2) & (UInt32)(0x0FFFFFFF)) ^ temp;
                    temp = D >> 26 & (UInt32)(0x3);
                    D = ((D << 2) & (UInt32)(0x0FFFFFFF)) ^ temp;
                }
                //回并
                cache56 = (UInt64)C;
                cache56 = cache56 << 28;
                cache56 = cache56 ^ D;
                //从cache56中按PC-2盒选出48位作为子密钥
                for (int j = 0; j < 48; j++)
                {
                    skeys[i] = skeys[i] ^ (cache56 >> (56 - PC_2[j]) & (UInt64)0x1);
                    if (j != 47)
                    {
                        skeys[i] = skeys[i] << 1;
                    }

                }
            }
            return skeys;

        }
        #endregion

    }


}
DES加解密代码

 注:经过测试,S盒中的数并非特定,可自行设计不同的数据


   

posted @ 2017-03-02 17:26  joelylee  阅读(355)  评论(0)    收藏  举报