报文加密
请求报文 AES 加密规则与 Java 参考实现
本系统对请求报文体进行全报文加密。业务参数先序列化为 JSON 字符串,再用本次请求随机生成的 trk 做 AES 加密,最后 Base64 编码得到 payload。
加密链
- 生成 128 位随机 AES 密钥,得到原始字节
trkBytes。 - 用平台下发的 RSA 公钥加密
trkBytes,再Base64编码,作为报文公共字段trk上送。 - 将业务参数序列化为 UTF-8 JSON 字符串
plainJson。 - 用
trkBytes对plainJson做 AES 加密。 - 对 AES 密文做
Base64编码,作为报文公共字段payload上送。
businessParams = { ... }
plainJson = JSON.stringify(businessParams)
trkBytes = randomBytes(16)
trk = Base64(RSA_ECB_PKCS1Padding(platformPublicKey, trkBytes))
payload = Base64(AES_CBC_PKCS5Padding(trkBytes, utf8(plainJson)))trk 同时用于解密本次请求对应的响应 payload,因此客户端需要保留本次请求生成的 trkBytes。
AES 参数
| 参数 | 值 |
|---|---|
| 算法/模式/补位 | AES/CBC/PKCS5Padding |
| 密钥长度 | 128 bit(16 字节) |
| IV | trkBytes 原始字节(16 字节) |
| 密钥派生 | 以 trkBytes 为种子,使用 SHA1PRNG + AES KeyGenerator(128) 生成实际 AES 密钥 |
上述密钥派生方式依赖 Java 的
SHA1PRNG与KeyGenerator组合,属于 Java 特有实现。其他语言接入时请先复刻该逻辑,或直接使用官方 SDK。
传输密钥本身使用 RSA/ECB/PKCS1Padding 加密,公钥为平台下发的 RSA 公钥。
Java 参考实现
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.util.Base64;
public final class TransportCrypto {
private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";
public static String encryptPayload(byte[] trk, String plainJson) throws GeneralSecurityException {
byte[] ciphertext = aes(trk, plainJson.getBytes(StandardCharsets.UTF_8), Cipher.ENCRYPT_MODE);
return Base64.getEncoder().encodeToString(ciphertext);
}
public static String decryptPayload(byte[] trk, String base64Ciphertext) throws GeneralSecurityException {
byte[] ciphertext = Base64.getDecoder().decode(base64Ciphertext);
return new String(aes(trk, ciphertext, Cipher.DECRYPT_MODE), StandardCharsets.UTF_8);
}
public static String encryptTrk(PublicKey platformPublicKey, byte[] trk) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, platformPublicKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(trk));
}
private static byte[] aes(byte[] trk, byte[] input, int mode) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
cipher.init(mode, derivedAesKey(trk), new IvParameterSpec(trk));
return cipher.doFinal(input);
}
private static SecretKeySpec derivedAesKey(byte[] trk) throws GeneralSecurityException {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(trk);
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, random);
return new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES");
}
}