zl程序教程

您现在的位置是:首页 >  其它

当前栏目

第七章 对称加密算法--DES

-- 对称 加密算法 第七章 DES
2023-09-27 14:22:34 时间

注意:本节内容主要参考自《Java加密与解密的艺术(第2版)》第7章“初等加密算法--对称加密算法”

7.1、对称加密算法

特点:

  • 加密与解密使用同一个密钥
  • 是使用最广的算法

常见对称加密算法:

  • DES(已被破解,但是是其他对称算法的基石)
  • DESede(处理速度慢、加密耗时,也不常用)
  • AES(DES的替代者,最常用)
  • IDEA(目前常用的电子邮件加密算法)
  • PBE(对已知对称加密进行包装)

7.2、DES(已破解,基本不用)

实现方式:

  • JDK(提供56位密钥,提供PKCS5Padding的填充模式)
  • Bouncy Castle(提供64位密钥,提供PKCS7Padding的填充模式)

由于DES已被破解,现在企业基本已不再使用,此处只列出基于JDK实现的代码。

  1 package com.util.des;
  2 
  3 import java.io.UnsupportedEncodingException;
  4 import java.security.InvalidKeyException;
  5 import java.security.Key;
  6 import java.security.NoSuchAlgorithmException;
  7 import java.security.spec.InvalidKeySpecException;
  8 
  9 import javax.crypto.BadPaddingException;
 10 import javax.crypto.Cipher;
 11 import javax.crypto.IllegalBlockSizeException;
 12 import javax.crypto.KeyGenerator;
 13 import javax.crypto.NoSuchPaddingException;
 14 import javax.crypto.SecretKey;
 15 import javax.crypto.SecretKeyFactory;
 16 import javax.crypto.spec.DESKeySpec;
 17 
 18 import org.apache.commons.codec.binary.Base64;
 19 
 20 /**
 21  * 基于JDK的DES算法
 22  */
 23 public class DESJDK {
 24     private static final String ENCODING = "UTF-8";
 25     private static final String KEY_ALGORITHM = "DES";//产生密钥的算法
 26     private static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";//加解密算法 格式:算法/工作模式/填充模式
 27     
 28     /**
 29      * 产生密钥
 30      */
 31     public static byte[] getKey() throws NoSuchAlgorithmException{
 32         KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
 33         keyGenerator.init(56);//初始化密钥长度
 34         SecretKey key =keyGenerator.generateKey();//产生密钥
 35         return key.getEncoded();
 36     }
 37     
 38     /**
 39      * 还原密钥:二进制字节数组转换为十六进制字符串
 40      */
 41     public static Key toKey(byte[] keyByte) throws InvalidKeyException, 
 42                                                    NoSuchAlgorithmException, 
 43                                                    InvalidKeySpecException{
 44         DESKeySpec desKeySpec = new DESKeySpec(keyByte);
 45         return SecretKeyFactory.getInstance(KEY_ALGORITHM).generateSecret(desKeySpec);
 46     }
 47     
 48     /**
 49      * DES加密
 50      * @param data     带加密数据
 51      * @param keyByte  密钥
 52      */
 53     public static byte[] encrypt(String data, byte[] keyByte) throws InvalidKeyException, 
 54                                                                      NoSuchAlgorithmException, 
 55                                                                      InvalidKeySpecException, 
 56                                                                      NoSuchPaddingException, 
 57                                                                      IllegalBlockSizeException, 
 58                                                                      BadPaddingException, 
 59                                                                      UnsupportedEncodingException{
 60         Key key = toKey(keyByte);//还原密钥
 61         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 62         cipher.init(Cipher.ENCRYPT_MODE, key);//设置加密模式并且初始化key
 63         return cipher.doFinal(data.getBytes(ENCODING));
 64     }
 65     
 66     /**
 67      * DES加密,并转为16进制字符串或Base64编码字符串
 68      */
 69     public static String encryptDESHex(String data, byte[] keyByte) throws InvalidKeyException, 
 70                                                                            NoSuchAlgorithmException, 
 71                                                                            InvalidKeySpecException, 
 72                                                                            NoSuchPaddingException, 
 73                                                                            IllegalBlockSizeException, 
 74                                                                            BadPaddingException, 
 75                                                                            UnsupportedEncodingException {
 76         byte[] encodedByte = encrypt(data, keyByte);
 77         //return new String(Hex.encode(encodedByte));//借助BC
 78         //return new String(org.apache.commons.codec.binary.Hex.encodeHexString(encodedByte));//借助CC
 79         return Base64.encodeBase64String(encodedByte);//借助CC的Base64编码
 80     }
 81     
 82     /**
 83      * DES解密
 84      * @param data        待解密数据为字节数组
 85      * @param keyByte    密钥
 86      */
 87     public static byte[] decrypt(byte[] data, byte[] keyByte) throws InvalidKeyException, 
 88                                                                      NoSuchAlgorithmException, 
 89                                                                      InvalidKeySpecException, 
 90                                                                      NoSuchPaddingException, 
 91                                                                      IllegalBlockSizeException, 
 92                                                                      BadPaddingException, 
 93                                                                      UnsupportedEncodingException {
 94         Key key = toKey(keyByte);//还原密钥
 95         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
 96         cipher.init(Cipher.DECRYPT_MODE, key);//设置解密模式(这是加解密的唯一不同的地方)并且初始化key
 97         return cipher.doFinal(data);
 98     }
 99     
100     /**
101      * DES解密
102      * @param data        待解密数据为字符串
103      * @param keyByte    密钥
104      */
105     public static byte[] decrypt(String data, byte[] keyByte) throws InvalidKeyException, 
106                                                                      NoSuchAlgorithmException, 
107                                                                      InvalidKeySpecException, 
108                                                                      NoSuchPaddingException, 
109                                                                      IllegalBlockSizeException, 
110                                                                      BadPaddingException, 
111                                                                      UnsupportedEncodingException {
112         Key key = toKey(keyByte);//还原密钥
113         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
114         cipher.init(Cipher.DECRYPT_MODE, key);//设置解密模式(这是加解密的唯一不同的地方)并且初始化key
115         return cipher.doFinal(Base64.decodeBase64(data));//注意data不可以直接采用data.getByte()方法转化为字节数组,否则会抛异常
116     }
117     
118     /**
119      * 测试
120      */
121     public static void main(String[] args) throws NoSuchAlgorithmException, 
122                                                   InvalidKeyException, 
123                                                   InvalidKeySpecException, 
124                                                   NoSuchPaddingException, 
125                                                   IllegalBlockSizeException, 
126                                                   BadPaddingException, 
127                                                   UnsupportedEncodingException {
128         String data = "找一个好姑娘做老婆是我的梦 想!";
129         /*************测试encode()**************/
130         System.out.println("原文-->"+data);
131         byte[] keyByte = DESJDK.getKey(); 
132         System.out.println("密钥-->"+Base64.encodeBase64String(keyByte));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
133         byte[] encodedByte = DESJDK.encrypt(data, keyByte);
134         System.out.println("加密后-->"+encodedByte);
135         byte[] encodedByte2 = DESJDK.encrypt(data, keyByte);
136         System.out.println("加密后-->"+encodedByte2);
137         byte[] decodedByte = DESJDK.decrypt(encodedByte, keyByte);
138         System.out.println("解密后-->"+decodedByte);
139         for(int i=0;i<encodedByte.length;i++){
140             System.out.println(encodedByte[i]==encodedByte2[i]);
141         }
142         /*************测试encodeHmacMD5Hex()**************/
143         System.out.println("原文-->"+data);
144         byte[] keyByte3 = DESJDK.getKey(); 
145         System.out.println("密钥-->"+Base64.encodeBase64String(keyByte3));//这里将二进制的密钥使用base64加密保存,这也是在实际中使用的方式
146         String encodedStr = DESJDK.encryptDESHex(data, keyByte3);
147         System.out.println("加密后-->"+encodedStr);
148         String encodedByte4 = DESJDK.encryptDESHex(data, keyByte3);
149         System.out.println("加密后-->"+encodedByte4);
150         byte[] decodedByte3 = DESJDK.decrypt(Base64.decodeBase64(encodedStr), keyByte3);
151         System.out.println("解密Byte[]后-->"+decodedByte3);
152         byte[] decodedByte4 = DESJDK.decrypt(encodedStr, keyByte3);
153         System.out.println("解密String后-->"+decodedByte4);
154     }
155 }
View Code

注意点:

  • 整个算法的过程与Hmac系列算法一样,都是发送方先生成一个密钥(二进制的字节数组),然后发送方将密钥通过安全的途径传给接收方。加解密过程:还原密钥(将二进制的字节数组还原成Java对象),然后根据密钥与待加解密数据进行加解密。
  • 加解密算法常量CIPHER_ALGORITHM是一个组合常量,其中的工作模式常用的是ECB和CTR(AES最常用的工作模式)填充模式一般采用PKCS5Padding即可,或者使用BC的PKCS7Padding,具体的工作模式与填充模式的介绍自己去查吧,至于JDK和BC均支持那些工作模式与填充模式直接去查本文最上边的书籍附录即可。
  • 初始化密钥长度的时候指定为56(JDK提供56位的密钥,采用BC可以产生64位的密钥)
  • 还原密钥的时候没有使用通用的方式SecretKey key = new SecretKeySpec(keyByte, ALGORITHM)来还原(当然也可以使用),而是使用了DES自己的还原类,这是DES的推荐做法,但是在AES中推荐使用通用的方式来还原密钥
  • 实际使用中,加密的密文会采用二进制来存储,密钥会采用Base64编码来存储;但是在演示的时候我会提供转化为字符串的密文(转化方法:BC的十六进制转化类 ;CC的十六进制转化类;CC的Base64编码)
  • 在解密过程中,如果传入的待解密数据data是String的,在使用dofinal()方法进行加密时,不可以直接使用doFinal(data.getByte()),否则会抛异常;可以使用doFinal(Base64.decodeBase64(data))
  • 同一段数据使用统一个密钥无论加密多少次,加密后的密文都相同