前言:
本实例用到两种加密算法:RSA非对称加密和DES对称加密;
除了RSA的公钥和私钥(公钥加密私钥解密,反之亦然),本实例还有两个秘钥:pingKey加密数据秘钥和workKey签名秘钥;
RSA只对pingKey和workKey加解密,DES通过pingKey对数据加解密;
RSA非对称加密比DES对称加密效率低、但安全性更高,故选用DES分别对多个字段值加密,RSA对pingKey和workKey加密;
开发步骤:
1、通过RsaUtils.genKeyPair()生成公钥和私钥,并将公钥和私钥用base64生成字符串,分配需要接入的下游;
2、公钥加密私钥解密,如果下游只需加密而不需解密,只用分配公钥字符串即可;
3、下游通过EncryptManager encryptManager = new EncryptManager();encryptManager.init();初始化pingKey和workKey随机数,并将两者拼接通过公钥生成monKey,monKey包含在报文中;
4、下游通过生成的pingKey加密数据encryptManager.encryptStr(...),通过生成的workKey加签数据SignUtils.getSign(...);
5、平台接收下游的报文,先用私钥解析monKey得到pingKey和workKey,再通过workKey验签数据,通过pingKey解密数据;
6、如果平台返回下游报文需要加密,流程同上;
该模块有以下几个java:
/RsaAndDesTest/src/com/test/Test.java // 测试类
/RsaAndDesTest/src/com/test/EncryptManager.java // 加解密类
/RsaAndDesTest/src/com/utils/DesUtils.java // des相关处理类
/RsaAndDesTest/src/com/utils/RsaUtils.java // rsa相关处理类
/RsaAndDesTest/src/com/utils/SignUtils.java // 签名相关处理类
引入的jar包:
commons-codec-1.4.jar // base64相关处理
commons-lang3-3.1.jar // 随机数相关处理
项目结构:
package com.test;
import java.util.HashMap;
import java.util.Map;
import com.utils.SignUtils;
/**
* 报文传输协议:
* RSA对加密解密秘钥和加签解签秘钥进行加密
* DES通过秘钥进行数据的加密解密和加签解签
* RSA通过公钥加密、私钥解密
*
* 加解密秘钥pingKey和加解签秘钥workKey为随机生成的24为字符串
* mobKey为通过RSA将pingKey和workKey拼接然后加密生成的秘钥串
*
* 步骤:
*
* 1、通过方法RsaUtils.genKeyPair()生成公钥和私钥(也可通过网络工具生成),分配给下游商户
* 下游:
* 2、随机生成两个秘钥(加解密pingKey和加解签workKey)
* 3、通过RsaUtils.encryptByPublicKey()和公钥加密得到mobKey
* 4、通过DesUtils.encryptByKey()对数据项加密
* 5、通过DesUtils.encryptByKey()对数据项加签,得到sign
* 6、将sign、mobKey、加密的数据,组装成报文传输
* 平台:
* 7、获取报文中的mobKey、sign
* 8、通过RsaUtils.decryptByPrivateKey()和私钥解密mobKey,得到两个秘钥(加解密pingKey和加解签workKey)
* 9、通过DesUtils.decryptByKey()对数据项加签,对比sign值验签
* 10、通过DesUtils.decryptByKey()对数据项解密,得到明文数据
*
* 返回下游的报文加解密和加解签流程同上
*
* (代码有些判断不严谨,请在实际的代码中进行完善。)
*/
public class Test {
private void sendMessage(Map<String, Object> params){
EncryptManager encryptManager = new EncryptManager();
encryptManager.init();
params.put("name", encryptManager.encryptStr("周星星")); // 加密
params.put("sex", "男");
params.put("age", encryptManager.encryptStr("10"));
params.put("mobKey", encryptManager.getMobKey());
// 签名
params.put("sign", SignUtils.getSign(params, encryptManager.getWorkKey()));
}
private void receviceMessage(Map<String, Object> params){
// 通过mobKey获取pingKey和workKey
String mobKey = (String) params.get("mobKey");
EncryptManager encryptManager = new EncryptManager();
encryptManager.parseMobKey(mobKey);
// 验签
if(!SignUtils.verifySign(params, encryptManager.getWorkKey())){
System.out.println("验签失败");
return;
}
params.put("name", encryptManager.decryptStr((String)params.get("name")));
params.put("age", encryptManager.decryptStr((String)params.get("age")));
}
public static void main(String[] args) {
Test test = new Test();
Map<String, Object> params = new HashMap<String, Object>();
test.sendMessage(params);
test.receviceMessage(params);
}
}
package com.test;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
import com.utils.DesUtils;
import com.utils.RsaUtils;
public class EncryptManager {
private static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCS3tyLB+gzLIGdO21Dem4JLp5TZGYWJUQl9vvUcMTbt0u4fjqlQp8musB4uc7EJ/DrBrR+HB2aoq7LknlNtCnfOH1WuMIXfQdfV1oiR0yi+ZCSjZQB+jRCO19NEWqMhUcBeZcx8em/UKXP6CmSINln6ttZGnbl12deOEQ+keoPIwIDAQAB";
private static final String privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJLe3IsH6DMsgZ07bUN6bgkunlNkZhYlRCX2+9RwxNu3S7h+OqVCnya6wHi5zsQn8OsGtH4cHZqirsuSeU20Kd84fVa4whd9B19XWiJHTKL5kJKNlAH6NEI7X00RaoyFRwF5lzHx6b9Qpc/oKZIg2Wfq21kaduXXZ144RD6R6g8jAgMBAAECgYAO8OMItb42boGlCCWeZrcI8hgjLaSA/juHjS+jNfGg1G28kALRSwy7uOXZojVZmSKWFjGIXr3YPFKB3R2//OMBbO5ep5Lu62iBLmXgdYwEXV1o0c1ZYkgDKF9tYN+Yv5nHB5bSZ4QnxpZ3LudvNNuUKqLFlDlHwWO6pKmr5cc7yQJBAPEbrse8d0u8cn5T0Xj+3WQ2kGm92ExyOn5sHLlnKPL4IKz3xbbLZWS3O8s1UhB4csPrcc2yEbc6hs5sHO1nFKUCQQCb8SCNUWeUpo8LhBMpIqd28vDaTDrRh5whwsdGbYkn2TPDc4i1lkHbGrTt5IqLh5XNKi79QHiiv5kAZBv7GCInAkA2LDcgD5tqO+QpuCF3oyQRMSVPbOVdf8jewOHPUntj5BZLZrxYruiQMY9QwCE5LCb1GECQq/LJDXBejvIM8T01AkASK/4kGaldXC9tIx3sfDpRlSvV9G4iPpBGKuF35onGF/x9OThkGLdh5fHRiwFOEyW0u8awAlRMetFEh2XvU7efAkA9CUF86C6OhlfAof15UienWPOtds2I4xr68Foh0xhZAf9sJoYIX1gKuCg87V1Sxsp2O/lfKWwaYpNlZncjzyYV";
private String pingKey = null;
private String workKey = null;
private String mobKey = null;
public String getPingKey() {
return pingKey;
}
public void setPingKey(String pingKey) {
this.pingKey = pingKey;
}
public String getWorkKey() {
return workKey;
}
public void setWorkKey(String workKey) {
this.workKey = workKey;
}
public String getMobKey() {
return mobKey;
}
public void setMobKey(String mobKey) {
this.mobKey = mobKey;
}
private void assambleMobKey() {
String mobKeyStr = this.getPingKey()+this.getWorkKey();
String mob = null;
try {
mob = Base64.encodeBase64String(RsaUtils.encryptByPublicKey(mobKeyStr.getBytes(), publicKey));
} catch (Exception e) {
e.printStackTrace();
}
this.setMobKey(mob);;
}
public EncryptManager(){
}
public void init(){
this.setPingKey(RandomStringUtils.random(24, "1234567890"));
this.setWorkKey(RandomStringUtils.random(24, "1234567890"));
this.assambleMobKey();
System.out.println("pingKey:"+this.getPingKey());
System.out.println("workKey:"+this.getWorkKey());
System.out.println("mobKey:"+this.getMobKey());
}
/**
* 加密数据
* @param data
* @return
*/
public String encryptStr(String data){
if(data==null || "".equals(data.trim())){
return null;
}
try {
byte[] result = DesUtils.encryptByKey(data.getBytes(), this.getPingKey());
return Base64.encodeBase64String(result);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 解密数据
* @param data
* @return
*/
public String decryptStr(String data){
if(data==null || "".equals(data.trim())){
return null;
}
try {
byte[] resultByte = DesUtils.decryptByKey(Base64.decodeBase64(data), this.getPingKey());
String result = new String(resultByte);
return result;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 通过mobKey获取pingKey和workKey
* @param mobKey
*/
public void parseMobKey(String mobKey){
if(mobKey==null || "".equals(mobKey.trim())){
return;
}
try {
byte[] mobKeyByte = Base64.decodeBase64(mobKey);
byte[] resultByte = RsaUtils.decryptByPrivateKey(mobKeyByte, privateKey);
String result = new String(resultByte);
String pingKey = result.substring(0,24);
String workKey = result.substring(24,48);
this.setPingKey(pingKey);
this.setWorkKey(workKey);
System.out.println("pingKey:"+pingKey);
System.out.println("workKey:"+workKey);
System.out.println("mobKey:"+mobKey);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
public static void main(String[] args) {
EncryptManager encryptManager = new EncryptManager();
encryptManager.init();
}
}
package com.utils;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import org.apache.commons.codec.binary.Base64;
public class DesUtils {
/**
* DES加密
* @param data
* @param key
* @return
* @throws Exception
*/
public static byte[] encryptByKey(byte[] data, String key) throws Exception{
// 可信任的随机数
SecureRandom secureRandom = new SecureRandom();
DESKeySpec keySpec = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, secureRandom);
return cipher.doFinal(data);
}
public static byte[] decryptByKey(byte[] data, String key) throws Exception{
// 可信任的随机数
SecureRandom secureRandom = new SecureRandom();
DESKeySpec keySpec = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, secretKey, secureRandom);
return cipher.doFinal(data);
}
public static void main(String[] args) throws Exception {
String sourceStr = "月光宝盒";
String key = "1234567890";
System.out.println("待加密:"+sourceStr);
byte[] encryptByte = DesUtils.encryptByKey(sourceStr.getBytes(), key);
String encryptStr = Base64.encodeBase64String(encryptByte);
System.out.println("加密后:"+encryptStr);
byte[] decryptByte = DesUtils.decryptByKey(Base64.decodeBase64(encryptStr), key);
String decryptStr = new String(decryptByte);
System.out.println("解密后:"+decryptStr);
}
}
package com.utils;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
public class RsaUtils {
private static final String ALGORITHM = "RSA";
private static final String PUBLICK_EY = "PUBLICK_EY";
private static final String PRIVATE_KEY = "PRIVATE_KEY";
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* 生成秘钥对,公钥和私钥
* @return
* @throws NoSuchAlgorithmException
*/
public static Map<String, Object> genKeyPair() throws NoSuchAlgorithmException{
Map<String, Object> keyMap = new HashMap<String, Object>();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(1024); // 秘钥字节数
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
keyMap.put(PUBLICK_EY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 公钥加密
* @param data
* @param publicKey
* @return
* @throws InvalidKeySpecException
*/
public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception{
// 得到公钥
byte[] keyBytes = Base64.decodeBase64(publicKey);
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
Key key = keyFactory.generatePublic(x509EncodedKeySpec);
// 加密数据,分段加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, key);
int inputLength = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offset = 0;
byte[] cache;
int i = 0;
while(inputLength-offset>0){
if(inputLength-offset>MAX_ENCRYPT_BLOCK){
cache = cipher.doFinal(data, offset, MAX_ENCRYPT_BLOCK);
}else{
cache = cipher.doFinal(data, offset, inputLength-offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
/**
* 私钥解密
* @param encryptedData
* @param privateKey
* @return
* @throws Exception
*/
public static byte[] decryptByPrivateKey(byte[] data, String privateKey) throws Exception{
// 得到私钥
byte[] keyBytes = Base64.decodeBase64(privateKey);
PKCS8EncodedKeySpec pKCS8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
Key key = keyFactory.generatePrivate(pKCS8EncodedKeySpec);
// 解密数据,分段解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, key);
int inputLength = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offset = 0;
byte[] cache;
int i = 0;
while(inputLength-offset>0){
if(inputLength-offset>MAX_DECRYPT_BLOCK){
cache = cipher.doFinal(data, offset, MAX_DECRYPT_BLOCK);
}else{
cache = cipher.doFinal(data, offset, inputLength-offset);
}
out.write(cache, 0, cache.length);
i++;
offset = i*MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
/**
* 获取公钥
* @param keyMap
* @return
*/
public static String getPublicKey(Map<String, Object> keyMap){
Key key = (Key) keyMap.get(PUBLICK_EY);
return Base64.encodeBase64String(key.getEncoded());
}
/**
* 获取私钥
* @param keyMap
* @return
*/
public static String getPrivateKey(Map<String, Object> keyMap){
Key key = (Key) keyMap.get(PRIVATE_KEY);
return Base64.encodeBase64String(key.getEncoded());
}
public static void main(String[] args) throws Exception {
// Map<String, Object> keyMap = RsaUtils.genKeyPair();
// String publicKey = RsaUtils.getPublicKey(keyMap);
// String privateKey = RsaUtils.getPrivateKey(keyMap);
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCS3tyLB+gzLIGdO21Dem4JLp5TZGYWJUQl9vvUcMTbt0u4fjqlQp8musB4uc7EJ/DrBrR+HB2aoq7LknlNtCnfOH1WuMIXfQdfV1oiR0yi+ZCSjZQB+jRCO19NEWqMhUcBeZcx8em/UKXP6CmSINln6ttZGnbl12deOEQ+keoPIwIDAQAB";
String privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJLe3IsH6DMsgZ07bUN6bgkunlNkZhYlRCX2+9RwxNu3S7h+OqVCnya6wHi5zsQn8OsGtH4cHZqirsuSeU20Kd84fVa4whd9B19XWiJHTKL5kJKNlAH6NEI7X00RaoyFRwF5lzHx6b9Qpc/oKZIg2Wfq21kaduXXZ144RD6R6g8jAgMBAAECgYAO8OMItb42boGlCCWeZrcI8hgjLaSA/juHjS+jNfGg1G28kALRSwy7uOXZojVZmSKWFjGIXr3YPFKB3R2//OMBbO5ep5Lu62iBLmXgdYwEXV1o0c1ZYkgDKF9tYN+Yv5nHB5bSZ4QnxpZ3LudvNNuUKqLFlDlHwWO6pKmr5cc7yQJBAPEbrse8d0u8cn5T0Xj+3WQ2kGm92ExyOn5sHLlnKPL4IKz3xbbLZWS3O8s1UhB4csPrcc2yEbc6hs5sHO1nFKUCQQCb8SCNUWeUpo8LhBMpIqd28vDaTDrRh5whwsdGbYkn2TPDc4i1lkHbGrTt5IqLh5XNKi79QHiiv5kAZBv7GCInAkA2LDcgD5tqO+QpuCF3oyQRMSVPbOVdf8jewOHPUntj5BZLZrxYruiQMY9QwCE5LCb1GECQq/LJDXBejvIM8T01AkASK/4kGaldXC9tIx3sfDpRlSvV9G4iPpBGKuF35onGF/x9OThkGLdh5fHRiwFOEyW0u8awAlRMetFEh2XvU7efAkA9CUF86C6OhlfAof15UienWPOtds2I4xr68Foh0xhZAf9sJoYIX1gKuCg87V1Sxsp2O/lfKWwaYpNlZncjzyYV";
System.out.println("公钥:"+publicKey);
System.out.println("私钥:"+privateKey);
// 公钥加密
String sourceStr = "我是谁?";
System.out.println("加密前:"+sourceStr);
byte[] encryptStrByte = RsaUtils.encryptByPublicKey(sourceStr.getBytes(), publicKey);
String encryptStr = Base64.encodeBase64String(encryptStrByte);
System.out.println("加密后:"+encryptStr);
System.out.println("长度:"+encryptStr.length());
// 私钥解密
byte[] decryptStrByte = RsaUtils.decryptByPrivateKey(Base64.decodeBase64(encryptStr), privateKey);
String sourceStr_1 = new String(decryptStrByte);
System.out.println("解密后:"+sourceStr_1);
/**
* 加密源数据通过getBytes()方法转换成字节数组进行加密
* 解密后的字节数组通过new String()方法转换成源字符串
* 明文显示加解密过程的字节数组,例如公私钥,用Base64转换成可见字符
*/
}
}
package com.utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
public class SignUtils {
/**
* 生成签名
* @param params
* @param workKey
* @return
*/
public static String getSign(Map<String, Object> params, String workKey){
if(params==null){
return null;
}
params.remove("sign");
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
StringBuffer sb = new StringBuffer();
for(String key : keys){
String value = (String) params.get(key);
if(value!=null && !"".equals(value.trim())){
sb.append(value);
}
}
try {
byte[] signByte = DesUtils.encryptByKey(sb.toString().getBytes(), workKey);
return Base64.encodeBase64String(signByte);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 验签
* @param params
* @return
*/
public static boolean verifySign(Map<String, Object> params, String workKey){
String sign = (String) params.get("sign");
return sign.equals(SignUtils.getSign(params, workKey));
}
}