1:加密的目的
保密性:防止用户隐私信息或重要业务数据被读取。
数据完整性:防止数据被网络中的第三方截取和篡改。
身份验证:确保数据访问接口调用方拥有相匹配权限。
2:
加密所需数据 | 名称 | 类型 | 说明 | 示例 |
appId | 应用id | String | 由银行网关颁发 | gw001 |
appSecret | 应用密码 | String | 由银行网关颁发 | 77459071-3b14-4a39-8960-be9cdb23009f |
rsaPublicKey | Rsa公钥 | String | 由银行网关颁发 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNxxx |
入参格式:
Key | 名称 | 类型 | 说明 | 是否必须 | 示例 |
appId | 应用id | String | 网关颁发 | 是 |
|
signature | 签名 | String | Base64编码的签名 | 是 |
|
ak | 加密的aes秘钥 | String | Base64编码后的加密的AES秘钥 | 是 |
|
message | 业务参数 | String | Aes秘钥加密的业务入参 | 是 |
|
serviceId | 接口id | String | 网关接口id | 是 |
|
加密规则
参数加密通过AES方式,AES密钥由调用端生成。
网关需要维护各appId对应的RSA私钥,客户端使用RSA公钥对AES秘钥做加密,服务端使用私钥进行解密,通过AES秘钥对请求数据做解密处理。
加签通过SHA256方式对(加密后的参数+ appSecret)采用MD5算法生成摘要.
加密代码
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
* 测试环境请求数据加密使用类
*
*/
public class RequestParamsEncryptionTest {
private static final String DEFAULT_URL_ENCODING = "UTF-8";
/**
*
* @param message 业务参数
* @param rsaPublicKey rsa公钥
* @param secret 应用密码
* @return 返回{message: "", signature: "", ak : ""}的map数据
* @throws Exception
*/
public static Map<String, String> encryption(String message, String rsaPublicKey, String secret) throws Exception{
// 1 生成AES秘钥
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128);
SecretKey sk = kg.generateKey();
byte[] aesKeyBytes = sk.getEncoded();
// 2 将业务参数用AES秘钥加密
byte[] encryMessage = encryptAES(message, aesKeyBytes);
// 3 将base64编码后的AES秘钥用RSA公钥加密 生成AK
String encodeAesKey = encodeBase64(aesKeyBytes);
byte[] akbytes = encryptRSA(loadPublicKeyByStr(rsaPublicKey), encodeAesKey.getBytes());
String akStr = encodeBase64(akbytes);
// 4 将加密后的业务参数和网关颁发的secret做sha256摘要生成签名
String encryBase64Message = encodeBase64(encryMessage);
String signature = encodeBase64(digest((encryBase64Message + secret).getBytes(), "SHA-256", null, 1));
Map<String, String> reData = new HashMap<>();
reData.put("message", encryBase64Message);
reData.put("signature", signature);
reData.put("ak", akStr);
return reData;
}
/**
* 字符串转换为Base64编码字符串.
* @throws UnsupportedEncodingException
*/
private static String encodeBase64(byte[] input) throws UnsupportedEncodingException {
return new String(Base64.encodeBase64(input), DEFAULT_URL_ENCODING);
}
/**
* @param input Base64字符串
* @return 解码Base64字符串,返回字节数组.
* @throws UnsupportedEncodingException
*/
private static byte[] decodeBase64(String input) throws UnsupportedEncodingException {
return Base64.decodeBase64(input.getBytes(DEFAULT_URL_ENCODING));
}
/**
* AES加密,先加密内容,然后再用Base64编码,返回Base64编码后的结果
*
* @param content
* 待加密字符串
* @param key
* AES秘钥
* @return Base64编码的加密内容
*/
private static byte[] encryptAES(String content, byte[] raw) throws Exception {
SecretKey aesKey = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] originalBytes = content.getBytes("utf-8");
byte[] encodedBytes = cipher.doFinal(originalBytes);
return encodedBytes;
}
/**
* 从字符串中加载公钥
*
* @param publicKeyStr
* 公钥数据字符串
* @throws Exception
* 加载公钥时产生的异常
*/
private static RSAPublicKey loadPublicKeyByStr(String publicKeyStr) throws Exception {
byte[] buffer = decodeBase64(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
/**
* rsa公钥加密过程
*
* @param publicKey
* 公钥
* @param plainTextData
* 明文数据
* @return
* @throws Exception
* 加密过程中的异常信息
*/
private static byte[] encryptRSA(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
if (publicKey == null) {
throw new Exception("加密公钥为空, 请设置");
}
Cipher cipher = null;
// 使用默认RSA
cipher = Cipher.getInstance("RSA");
// cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] output = cipher.doFinal(plainTextData);
return output;
}
/**
* 对字符串进行散列, 支持md5与sha1、sha256算法.
* @param input 输入byte
* @param algorithm 算法名称
* @param salt 加盐
* @param iterations 迭代次数
* @return
*/
private static byte[] digest(byte[] input, String algorithm, byte[] salt, int iterations) {
try {
MessageDigest digest = MessageDigest.getInstance(algorithm);
if (salt != null) {
digest.update(salt);
}
byte[] result = digest.digest(input);
for (int i = 1; i < iterations; i++) {
digest.reset();
result = digest.digest(result);
}
return result;
} catch (GeneralSecurityException e) {
}
return salt;
}
}