一、数据交互
咱们本人的零碎须要和第三方零碎进行对接,实现业务的齐全系统化、自动化操作等,零碎对接其实就是数据的对接,有数据的传输那么就得思考数据的平安交互,个别须要咱们做到两点:数据加密和数据签名。数据加密是为了解决明文裸露的问题,数据签名是为了确保数据完整性和防篡改。
二、非对称加密
非对称加密算法存在两个密钥,一个称之为公钥,一个称之为私钥,这两个密钥齐全不同但又齐全匹配。只有应用匹配的一对公钥和私钥,能力实现对明文的加密和解密过程。常见的非对称加密有 RSA、SM2 等
三、公钥与私钥
由服务端生成公钥与私钥,而后把公钥发送给客户端,客户端通过公钥对数据加密,而后把加密的数据发送给服务端,服务端通过私钥对数据解密。
理论我的项目中,客户端和服务端是相对而言的,客户端也有可能是服务端来接收数据,所以个别两端都会生成一对公钥和私钥,而后把公钥发送给对方,接口交互过程中,通过公钥加密,私钥解密进行数据传输。
公钥和私钥都能够用于加解密操作,用公钥加密的数据只能由对应的私钥解密,反之亦然。虽说两者都可用于加密,然而不同场景应用不同的密钥来加密,规定如下:
1、私钥用于签名、公钥用于验签(私钥加密,公钥解密)
签名和加密作用不同,签名并不是为了窃密,而是为了保障这个签名是由特定的某个人签名的,而不是被其它人伪造的签名,所以私钥的公有性就适宜用在签名用处上。
2、公钥用于加密、私钥用于解密
公钥加密,只能由私钥解密,而私钥是公有不公开的,只能由特定的私钥持有人解密,保证数据的安全性(即便截获数据也不晓得是什么内容)
四、RSA 加解密代码
/**
* RSA 非对称加密
*/
public class RSAUtils {
/**
* 非对称密钥算法
*/
public static final String KEY_ALGORITHM = "RSA";
/**
* 密钥长度,DH 算法的默认密钥长度是 1024
* 密钥长度必须是 64 的倍数,在 512 到 65536 位之间
*/
private static final int KEY_SIZE = 1024;
/**
* 公钥
*/
private static final String PUBLIC_KEY = "RSAPublicKey";
/**
* 私钥
*/
private static final String PRIVATE_KEY = "RSAPrivateKey";
/**
* 初始化密钥对
*
* @return Map 甲方密钥的 Map
*/
public static Map<String, Object> initKey() throws Exception {
// 实例化密钥生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
// 初始化密钥生成器
keyPairGenerator.initialize(KEY_SIZE);
// 生成密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 甲方公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 甲方私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 将密钥存储在 map 中
Map<String, Object> keyMap = new HashMap<String, Object>();
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 私钥加密
*
* @param data 待加密数据
* @param key 密钥
* @return byte[] 加密数据
*/
public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {
// 获得私钥
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 公钥加密
*
* @param data 待加密数据
* @param key 密钥
* @return byte[] 加密数据
*/
public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
// 实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 初始化公钥
// 密钥资料转换
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
// 产生公钥
PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
// 数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(data);
}
/**
* 私钥解密
*
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密数据
*/
public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {
// 获得私钥
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 公钥解密
*
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密数据
*/
public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {
// 实例化密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 初始化公钥
// 密钥资料转换
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
// 产生公钥
PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
// 数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, pubKey);
return cipher.doFinal(data);
}
/**
* 获得私钥
*
* @param keyMap 密钥 map
* @return byte[] 私钥
*/
public static byte[] getPrivateKey(Map<String, Object> keyMap) {Key key = (Key) keyMap.get(PRIVATE_KEY);
return key.getEncoded();}
/**
* 获得公钥
*
* @param keyMap 密钥 map
* @return byte[] 公钥
*/
public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);
return key.getEncoded();}
}
五、接口设计
申请体类:
public class RequestData {
/**
* 序列号,全局惟一,用来标识一个申请
*/
private String seqNo;
/**
* 工夫戳,毫秒
*/
private String timestamp;
/**
* 交易服务码
*/
private String transCode;
/**
* 数据签名
*/
private String signature;
/**
* 申请数据体,数据 JSON 串
*/
private String plain;
public String getSeqNo() {return seqNo;}
public void setSeqNo(String seqNo) {this.seqNo = seqNo;}
public String getTimestamp() {return timestamp;}
public void setTimestamp(String timestamp) {this.timestamp = timestamp;}
public String getTransCode() {return transCode;}
public void setTransCode(String transCode) {this.transCode = transCode;}
public String getSignature() {return signature;}
public void setSignature(String signature) {this.signature = signature;}
public String getPlain() {return plain;}
public void setPlain(String plain) {this.plain = plain;}
}
响应体类:
public class ResponseData {
/**
* 序列号,全局惟一,用来标识一个申请
*/
private String seqNo;
/**
* 工夫戳,毫秒
*/
private Long timestamp;
/**
* 交易服务码
*/
private String transCode;
/**
* 数据签名
*/
private String signature;
/**
* 申请数据体
*/
private String plain;
public String getSeqNo() {return seqNo;}
public void setSeqNo(String seqNo) {this.seqNo = seqNo;}
public Long getTimestamp() {return timestamp;}
public void setTimestamp(Long timestamp) {this.timestamp = timestamp;}
public String getTransCode() {return transCode;}
public void setTransCode(String transCode) {this.transCode = transCode;}
public String getSignature() {return signature;}
public void setSignature(String signature) {this.signature = signature;}
public String getPlain() {return plain;}
public void setPlain(String plain) {this.plain = plain;}
}