為了保證安全性,微信支付在回調(diào)通知和平臺證書下載接口中,對關(guān)鍵信息進(jìn)行了AES-256-GCM加密。本章節(jié)詳細(xì)介紹了加密報(bào)文的格式,以及如何進(jìn)行解密。
AES-GCM
是一種NIST標(biāo)準(zhǔn)的認(rèn)證加密算法, 是一種能夠同時保證數(shù)據(jù)的保密性、 完整性和真實(shí)性的一種加密模式。它最廣泛的應(yīng)用是在TLS中。
證書和回調(diào)報(bào)文使用的加密密鑰為
APIv3密鑰。
對于加密的數(shù)據(jù),我們使用了一個獨(dú)立的JSON對象來表示。為了方便閱讀,示例做了Pretty格式化,并加入了注釋。
{
"original_type": "transaction", // 加密前的對象類型
"algorithm": "AEAD_AES_256_GCM", // 加密算法
// Base64編碼后的密文
"ciphertext": "...",
// 加密使用的隨機(jī)串初始化向量)
"nonce": "...",
// 附加數(shù)據(jù)包(可能為空)
"associated_data": ""
}
算法接口的細(xì)節(jié),可以參考RFC 5116。
大部分編程語言(較新版本)都支持了AEAD_AES_256_GCM
。開發(fā)者可以參考下列的示例,了解如何使用您的編程語言實(shí)現(xiàn)解密。
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesUtil {
static final int KEY_LENGTH_BYTE = 32;
static final int TAG_LENGTH_BIT = 128;
private final byte[] aesKey;
public AesUtil(byte[] key) {
if (key.length != KEY_LENGTH_BYTE) {
throw new IllegalArgumentException("無效的ApiV3Key,長度必須為32個字節(jié)");
}
this.aesKey = key;
}
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
throws GeneralSecurityException, IOException {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData);
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
}