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 } }
注:经过测试,S盒中的数并非特定,可自行设计不同的数据

浙公网安备 33010602011771号