(加密基础)DES篇

本文章分析非常浅显,java代码写的不够细致,只考虑了标准的DES加密输出,并未将结果转化为hex或者base64输出,若有不当之处欢迎各位大佬指出

DES加密

DES加密是一种对称加密算法,被广泛应用与协议传输、本地数据加密、加密用户登录结果信息并序列化到本地磁盘

一.C语言实现和原理解析

说明:理论部分借鉴看雪密码学大佬:https://bbs.pediy.com/thread-253558.htm#des%E7%AE%97%E6%B3%95%E7%9A%84%E8%A7%A3%E5%AF%86%E6%96%B9%E6%B3%95%EF%BC%9A

DES算法使用Feistel框架和分组密码原理
 流程图如下链接: https://bbs.pediy.com/upload/attach/202002/813468_24VWUXQHSW3DQWC.png

1.明文初始置换

通过置换表对传入的数据进行乱序处理

置换表如下:

在这里插入图片描述
例如:假如原数据的第58位为1,那么经过置换后,第0行、0列的值就等于1

在这里插入图片描述
代码实现:

const unsigned char IP_Table[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
};
 
int IP_Substitution(const unsigned char* BitPlain, unsigned char* Bit_IP_Table)
{
    
    
    int ret = 0;
 
    for (int i = 0; i < 64; i++)
    {
    
    
        Bit_IP_Table[i] = BitPlain[IP_Table[i] - 1];
    }
 
    return ret;
}

2.分组(L,R组)

在这里插入图片描述

按照上下进行分组

unsigned char Bit_IP_Table[64];      //初始置换后的明文表
unsigned char BitL_Table[17][32];    //L表Bit组
unsigned char BitR_Table[17][32];    //R表Bit组
 
memcpy(BitL_Table[0], Bit_IP_Table,         32);
memcpy(BitR_Table[0], &Bit_IP_Table[32],    32);

3.右分组(R组)由32位扩展为48位

通过扩展置换变对R组进行扩展,原理和前面的置换表差不多,就是多了一些重复的映射

在这里插入图片描述

代码实现:

const unsigned char E_Table[48] =
{
    
    
    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
};
 
int E_Substitution(const unsigned char* BitR_Table, unsigned char* BitE_Table)
{
    
    
    int ret = 0;
 
    for (int i = 0; i < 48; i++)
    {
    
    
        BitE_Table[i] = BitR_Table[E_Table[i] - 1];
    }
 
    return ret;
}
```c
#### 4.扩展的R组和48位密钥进行异或
```c
int DES_XOR(const unsigned char* Bit1_Table, const unsigned char* Bit2_Table, unsigned char* Bit_Xor/*异或运算的结果*/, int nBit/*异或运算的位数*/)
{
    
    
	int ret = 0;
	for (int i = 0; i < nBit; i++)
	{
    
    
		Bit_Xor[i] = Bit1_Table[i] ^ Bit2_Table[i];
	}

	return ret;
}

5.将48位异或的结果转换为32位

详细过程:先将48为分成8组,每组6位,在将6位数字经过变化转换为4位

6->4操作:

例:(一个6位的分组)

1 0 0 1 0 1

将该分组的第一位和最后一位取出来,以二进制的形式表示,作为行索引

将该分组的第2到5位取出来,以二进制的形式表示,作为列索引

代码:

const unsigned char S_Table[8][4][16] =
{
    
    
    //S1盒
    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,
 
    //S2盒
    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,
 
    //S3盒
    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,
 
    //S4盒
    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,
 
    //S5盒
    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,
 
    //S6盒
    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,
 
    //S7盒
    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,
 
    //S8盒
    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
};
 
 
unsigned char Bit_Xor[8][6];          //存放异或运算的结果
unsigned char Bit_Integer[8][4];      //将整数变成Bit位
unsigned char Row;                    //S盒的行号
unsigned char Col;                    //S盒的列号
unsigned char Integer;                //从S盒中取得的32位整数
 
for (int i = 0; i < 8; i++)
{
    
    
    //计算S盒的行号和列号
    Row = (Bit_Xor[i][0] << 1) + Bit_Xor[i][5];
    Col = (Bit_Xor[i][1] << 3) + (Bit_Xor[i][2] << 2) + (Bit_Xor[i][3] << 1) + Bit_Xor[i][4];
 
    //从S盒中取得整数
    Integer = S_Table[i][Row][Col];
 
    //将取得的4Bit数转换成Bit组
    for (int j = 0; j < 4; j++)
    {
    
    
        Bit_Integer[i][j] = Integer >> (3 - j) & 1;
    }
}

6.p置换

同最开始的初始置换,只是对数据进行了打乱操作
在这里插入图片描述

const unsigned char P_Table[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
};
 
int P_Substitution(const unsigned char *Bit_Integer, unsigned char* BitP_Table)
{
    
    
    int ret = 0;
 
    for (int i = 0; i < 32; i++)
    {
    
    
        BitP_Table[i] = Bit_Integer[P_Table[i] - 1];
    }
 
    return ret;
}

7、将返回的结果和L组进行异或操作,作为新的R组,并将旧的R组赋值给新的L组

伪代码:


R[i+1] = L[i] ^ F(R[i], K[i]);
L[i+1] = R[i];

8.按照3、4、5、6、7步重复16次

for (int i = 0; i < 16; i++)
{
    
    
    //将R组和子密钥组进行F函数运算
    DES_F_Function(BitR_Table[i], BitSubKey[i], Bit_F_Out);
 
    //L组盒F函数的输出结果进行异或运算
    DES_XOR(BitL_Table[i], Bit_F_Out, BitR_Table[i + 1], 32);
 
    //Li+1 = Ri
    memcpy(BitL_Table[i + 1], BitR_Table[i], 32);
}
 
//L[16]和R[16]进行交叉合并
memcpy(BitRL_Table,         BitR_Table[16], 32);
memcpy(&BitRL_Table[32],    BitL_Table[16], 32);

9.逆初始值置换

对上述16步操作后的结果进行逆初始值置换操作,也是类似于初始置换表

const unsigned char reIP_Table[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
};
 
int reIP_Substitution(const unsigned char *BitRL_Table, unsigned char *Bit_reIP_Table)
{
    
    
    int ret = 0;
 
    for (int i = 0; i < 64; i++)
    {
    
    
        Bit_reIP_Table[i] = BitRL_Table[reIP_Table[i] - 1];
    }
 
    return ret;
}

10.密钥的扩展和加密

PC-1置换
将64位密钥中的8、16、24、32、40、48、56、64位剔除作为校验位。
其余的位进行置换表操作

const unsigned char PC_1_Table[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
};
 
int PC_1_Substitution(const unsigned char *BitKey, unsigned char *BitKey_PC_1)
{
    
    
    int ret = 0;
 
    for (int i = 0; i < 56; i++)
    {
    
    
        BitKey_PC_1[i] = BitKey[PC_1_Table[i] - 1];
    }
 
    return ret;
}

然后对56位数据进行分组,分成C、D组,采用上下分组,再进行16次变化,每次变化后会进行(PC-2置换)生成一次密钥用作每一轮的加密

每轮变化都进行整体左位移操作(并把前面超出范围的两位数据移动到数据的最后面),根据具体的轮数位移的位数也不同,其中1、2、9、16轮中,位移1位,其余轮位移2位

const unsigned char Bit_Round[16] =
{
    
    
    1, 1, 2, 2,
    2, 2, 2, 2,
    1, 2, 2, 2,
    2, 2, 2, 1
};
 
int BitRound_L(const unsigned char* SrcBitGroup, unsigned char* DesBitGroup, int nBit)
{
    
    
    int ret = 0;
 
    memcpy(DesBitGroup,             &SrcBitGroup[nBit], 28 - nBit);
    memcpy(&DesBitGroup[28 - nBit], SrcBitGroup,        nBit);
 
    return ret;
}
 
//将C、D两组进行轮转移位操作    左移
BitRound_L(BitC_Table[i], BitC_Table[i + 1], Bit_Round[i]);
BitRound_L(BitD_Table[i], BitD_Table[i + 1], Bit_Round[i]);
密钥生成算法PC-2置换

PC-2置换
置换嘛,不多说了

const unsigned char PC_2_Table[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
};
 
int PC_2_Substitution(const unsigned char *BitKey, unsigned char *SubKey)
{
    
    
    int ret = 0;
 
    for (int i = 0; i < 48; i++)
    {
    
    
        SubKey[i] = BitKey[PC_2_Table[i] - 1];
    }
 
    return ret;
}

C语言实现完成!!

二、java实现

根据模式的不同有很多实现方式,现展示一种方式
,主要抓住特征private static final String ALGORITHM = "DES";来对加密方式进行判断,标准的DES算法以字符串输出时很容易产生乱码,因此输出时需要将其转化为hex或者base64编码的形式

package decrypt01;
import java.util.Base64;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public final class DES {
    
    

    private static final String ALGORITHM = "DES";
    private static final String TRANSFORMATION = "DES/ECB/PKCS5Padding";

    //利用8个字节64位的key给src加密
    public static byte[] encrypt(byte[] src,byte[]key)
    {
    
    
        try {
    
    
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM);
            KeySpec keySpec = new DESKeySpec(key);
            SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey,new SecureRandom());
            byte[] enMsgBytes = cipher.doFinal(src);    
            return enMsgBytes;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return null;
    }

    //利用8个字节64位的key给src解密
    public static byte[] decrypt(byte[] encryptBytes,byte[]key){
    
    
        try {
    
    
            Cipher deCipher = Cipher.getInstance(TRANSFORMATION);
            SecretKeyFactory deDecretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM);
            KeySpec deKeySpec = new DESKeySpec(key);
            SecretKey deSecretKey = deDecretKeyFactory.generateSecret(deKeySpec);
            deCipher.init(Cipher.DECRYPT_MODE, deSecretKey,new SecureRandom());
            byte[] deMsgBytes = deCipher.doFinal(encryptBytes);
            return deMsgBytes;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return null;
    }
	public static String encode(byte[] key) {
    
    
	    return new String(Base64.getEncoder().encode(key));
	    //����base64���ܰ�
	}
	public static String decode(byte[] key) {
    
    
	    return new String(Base64.getDecoder().decode(key));
	}
    private static String key = "12345678";

    public static void main(String[] args) throws Exception{
    
    
        String msg = "12345678";
        System.out.println("加密前:"+msg);
       byte[] encryptBytes = DES.encrypt(msg.getBytes(),key.getBytes());
        System.out.println("加密后:"+new String(encryptBytes));
        byte[] deMsgBytes = DES.decrypt(encryptBytes,key.getBytes());
        System.out.println("解密后:"+new String(deMsgBytes));
    }

}

三、3DES java实现

3DES是DES经过改进的结果,增强了其密钥的长度



import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class do3DES {
    
    

   //key 根据实际情况对应的修改
   private final byte[] keybyte="123456788765432112345678".getBytes(); //keybyte为加密密钥,长度为24字节
   private static final String Algorithm = "DESede"; //定义 加密算法,可用 DES,DESede,Blowfish
   private SecretKey deskey;
   //生成密钥
   public do3DES(){
    
    
       deskey = new SecretKeySpec(keybyte, Algorithm);
   }
   //加密
   public byte[] encrypt(byte[] data){
    
    
        try {
    
    
            Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, deskey);
            return cipher.doFinal(data);
        } catch (Exception ex) {
    
    
            //加密失败,打日志
            ex.printStackTrace();
        } 
        return null;
   }
   //解密
   public byte[] decrypt(byte[] data){
    
    
       try {
    
    
            Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE,deskey);
            return cipher.doFinal(data);
        } catch (Exception ex) {
    
    
            //解密失败,打日志
            ex.printStackTrace();
        } 
        return null;
   }

   public static void main(String[] args) throws Exception {
    
    
	   do3DES des=new do3DES();
       String req ="cryptology";

       String toreq  = toHexString(req);
       System.err.println("十六进制报文=="+toreq);
       byte[] srcData=req.toString().getBytes("utf-8");
       byte[] encryptData=des.encrypt(srcData);
       System.out.println("密文:");
       if(encryptData!=null){
    
    
           for(int i=0;i<encryptData.length;i++){
    
    
               String hex=Integer.toHexString(encryptData[i]);
               if(hex.length()>1)
                System.out.print(hex.substring(hex.length()-2)+" ");
               else
                System.out.print("0"+hex+" ");
           }
       }
       System.out.println("");
       System.out.println("明文:"+req);
   }

   // 转化字符串为十六进制编码
   public static String toHexString(String s) {
    
    
       String str = "";
       for (int i = 0; i < s.length(); i++) {
    
    
           int ch = (int) s.charAt(i);
           String s4 = Integer.toHexString(ch);
           str = str + s4;
       }
       return str;
   }
}

猜你喜欢

转载自blog.csdn.net/weixin_43632667/article/details/105922888