DES和RSA混合加密及解密
实际开发过程中,RSA生成的公钥应保存在加密方,私钥应保存在解密方,可使用读取文件内容方式获取密钥。
maven依赖:
<!-- DES -->
<dependency>
<groupId>javax.xml.rpc</groupId>
<artifactId>javax.xml.rpc-api</artifactId>
<version>1.1.1</version>
</dependency>
<!-- RSA -->
<dependency>
<groupId>org.apache.axis</groupId>
<artifactId>axis</artifactId>
<version>1.4</version>
</dependency>
<!-- base64 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
DES工具类:
package common;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.NoSuchAlgorithmException;
/**
* @program: Demo
* @Date: 2019/2/20 20:59
* @Author: LiJc
* @Description:
*/
public class DESUtil {
/**
* 生成KEY
*/
public static byte[] getKey(){
KeyGenerator keyGenerator = null;
try {
keyGenerator = KeyGenerator.getInstance("DES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.out.println("----------------KEY生成失败!");
return null;
}
keyGenerator.init(56);
SecretKey secretKey = keyGenerator.generateKey();
byte[] byteKey = secretKey.getEncoded();
return byteKey;
}
/**
* DES加密
*
* @param context
* @return
*/
public static byte[] desEncrypt(String context, String key) {
try {
// KEY转换
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey conventSecretKey = secretKeyFactory.generateSecret(desKeySpec);
// 加密
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, conventSecretKey, new IvParameterSpec(key.getBytes("UTF-8")));
return cipher.doFinal(context.getBytes("UTF-8"));
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
/**
* DES解密
*
* @param context
* @return
*/
public static byte[] desDecrypt(byte[] context, String key) {
try {
// KEY转换
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey conventSecretKey = secretKeyFactory.generateSecret(desKeySpec);
// 解密
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, conventSecretKey, new IvParameterSpec(key.getBytes("UTF-8")));
return cipher.doFinal(context);
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
}
RSA工具类:
package common;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import javax.crypto.Cipher;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileWriter;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* @program: Demo
* @Date: 2019/2/21 22:56
* @Author: LiJc
* @Description:
*/
public class RSAUtil {
/**
* 转密钥字符串(base64编码)
*
* @return
*/
public static String getKeyString(Key key) throws Exception {
byte[] keyBytes = key.getEncoded();
String s = new String(Base64.encodeBase64(keyBytes));
return s;
}
/**
* 得到公钥
* @param publicKey 密钥字符串(经过base64编码)
* @throws Exception
*/
public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
//通过X509编码的Key指令获得公钥对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
return key;
}
/**
* 得到私钥
* @param privateKey 密钥字符串(经过base64编码)
* @throws Exception
*/
public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
//通过PKCS#8编码的Key指令获得私钥对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
return key;
}
/**
* 生成密钥对
* @param pubfilePath 公钥存放的文件路径
* @param prifilePath 私钥存放的文件路径
*/
public static void genKeyPair(String pubfilePath, String prifilePath) {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = null;
try {
keyPairGen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(1024, new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 得到公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
try {
// 得到公钥字符串
String publicKeyString = getKeyString(publicKey);
// 得到私钥字符串
String privateKeyString = getKeyString(privateKey);
// 将密钥对写入到文件
FileWriter pubfw = new FileWriter(pubfilePath);
FileWriter prifw = new FileWriter(prifilePath);
BufferedWriter pubbw = new BufferedWriter(pubfw);
BufferedWriter pribw = new BufferedWriter(prifw);
pubbw.write(publicKeyString);
pribw.write(privateKeyString);
pubbw.flush();
pubbw.close();
pubfw.close();
pribw.flush();
pribw.close();
prifw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 公钥加密
* @param data 需要加密的内容
* @param publicKey 公钥
* @return
*/
public static String publicEncrypt(String data, RSAPublicKey publicKey){
try{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return new String(Base64.encodeBase64(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes("UTF-8"), publicKey.getModulus().bitLength())));
}catch(Exception e){
throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
}
}
/**
* 私钥解密
* @param data 需要加密的内容
* @param privateKey 私钥
* @return
*/
public static String privateDecrypt(String data, RSAPrivateKey privateKey){
try{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), "UTF-8");
}catch(Exception e){
throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
}
}
private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){
int maxBlock = 0;
if(opmode == Cipher.DECRYPT_MODE){
maxBlock = keySize / 8;
}else{
maxBlock = keySize / 8 - 11;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] buff;
int i = 0;
try{
while(datas.length > offSet){
if(datas.length-offSet > maxBlock){
buff = cipher.doFinal(datas, offSet, maxBlock);
}else{
buff = cipher.doFinal(datas, offSet, datas.length-offSet);
}
out.write(buff, 0, buff.length);
i++;
offSet = i * maxBlock;
}
}catch(Exception e){
throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e);
}
byte[] resultDatas = out.toByteArray();
IOUtils.closeQuietly(out);
return resultDatas;
}
}
单元测试:
注意:RSA用到的密钥对为上一篇文章生成的 https://blog.csdn.net/JcMR_Li/article/details/87873079
package common;
import org.apache.commons.codec.binary.Base64;
import org.junit.Test;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
/**
* @program: Demo
* @Date: 2019/2/22 10:18
* @Author: LiJc
* @Description:
*/
public class DESAndRSATest {
/**
* DES和RSA混合加密,先进行DES加密,将DES加密后的内容进行base64编码,再将base64编码的DES进行RSA加密
*/
@Test
public void test1() throws InvalidKeySpecException, NoSuchAlgorithmException {
String deskey = "password";//des密钥//长度8位
String content = "真香警告!"; //内容
System.out.println("原始加密内容为:"+content);
//DES加密
byte[] encryptbyte = DESUtil.desEncrypt(content, deskey); //加密后返回为字节数组
String descontent = Base64.encodeBase64String(encryptbyte);
System.out.println("DES加密后内容为:"+ descontent);
//RSA部分start
String pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQ1IqhPNo8M/R1pHpocNuJ6enntJoB7OAaJrVoaHbvJOI4APkheX0J1UKizOGQNRr/V6vp3B+3MrPVGJ4lfRirrgnIK86PD5K/MChSWhxslWf3jQxr7AO8rMIPre7uoGjmY3pbSY82QUGDEhgDVsWTLTjWWqFQHVTwEfBPGgaktQIDAQAB";
//根据公钥key获取公钥
RSAPublicKey publicKey = RSAUtil.getPublicKey(pubkey);
//RSA加密
String rsacontent = RSAUtil.publicEncrypt(descontent, publicKey);
System.out.println("RSA加密后内容为:"+rsacontent);
String prikey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJDUiqE82jwz9HWkemhw24np6ee0mgHs4BomtWhodu8k4jgA+SF5fQnVQqLM4ZA1Gv9Xq+ncH7cys9UYniV9GKuuCcgrzo8Pkr8wKFJaHGyVZ/eNDGvsA7yswg+t7u6gaOZjeltJjzZBQYMSGANWxZMtONZaoVAdVPAR8E8aBqS1AgMBAAECgYBtteOSApPa2QyM9VyYsy1LCrvafs/PN44HoVz4S3IU9B69h9cxCWOzyC3jP0p7QA9EcDhVPh90Wl8pxK0//sRpWZrKps3ZqCQKogLSHTIaRJvvgQwN26KtIwSoXDwKqpmyhufIhXdFDmSIKb8v8rF3Sl3Mt5I+hDT83fnTjyPUPQJBAOBNObrgZQ7CvMuwtKilWhAqlNbhibfc3k4dtJ+23uixUgHq+WME6w7B0NUixT6ua7v+RKZD1RO9ANDGCEIQzfsCQQClTDPsjrkerRBsXrge6xK2drisIpEFBdYoIz9lYmCHXJctkx5nhLogxxTeAJgFWBIcOgrx5OCYOQgr5p6FikkPAkA45j470sqwCOR9w3DAy1lienrRW9tkwem+5Tg5v9kiLEFCbUogPVInpzEDsFNbCEIaKXFewBxganS3gVT89WhbAkAV90NrKyg0iGEHVar4CNsKvkoaLdnBph3oZY62JVWYh1hbqRJARWYKlwoR2lhZVXPKpnfv3y9tax7H3rSwIElHAkB7j65B6+L8Ty0RiEzHCOVXnUoUTai/BZfQ5erA9yVM/VW8p1mE/qhJOTQ5hFniO0dicl3YZyaYHW1D+Z1V4naO";
//获取私钥
RSAPrivateKey privateKey = RSAUtil.getPrivateKey(prikey);
//RSA解密
String content1 = RSAUtil.privateDecrypt(rsacontent, privateKey);
System.out.println("RSA解密后内容为:"+content1);
//RSA部分end
//DES解密
byte[] decryptbyte = DESUtil.desDecrypt(Base64.decodeBase64(content1), deskey); //将加密后返回的字节数组进行解密
System.out.println("DES解密后内容为:"+ new String(decryptbyte));
}
}
测试结果: