AES-GCM报文加密和报文解密
报文加密和报文解密
ZOLOZ 网关协议提供报文加密能力,确保报文在传输过程中数据不被篡改。
如果商户发送的请求是加密的,ZOLOZ 服务返回的响应也是加密的;否则,ZOLOZ 服务返回的响应不加密。
由于 ZOLOZ 服务处理的数据可能包含敏感信息,为增强报文传输安全性,ZOLOZ 服务会对响应报文进行加密。敏感信息包括所有敏感的个人身份信息(PII),如姓名、身份证号、生日、地址、人脸等。
对称加密算法为 AES-GCM(AEAD,加密与认证一体)。与旧版 RSA_AES 算法(AES-ECB,仅加密)相比,AES-GCM 通过 128 位认证标签提供密文完整性认证。旧版 RSA_AES 算法为兼容旧客户端仍然支持;客户端必须根据响应 Encrypt 头中的 algorithm 字段决定解密算法,而不是依赖本地配置。
加密报文
加密流程
下图展示了从商户视角如何加密请求报文,以及从 ZOLOZ 服务视角如何加密响应报文。

图 1. 报文加密活动图
加密报文的步骤
1. 获取公钥
- 对于请求报文,在商户账户创建时,ZOLOZ 系统会生成一对 RSA 2048 密钥。生成的密钥对每个商户唯一,其中包含一把公钥。商户需要事先获取该公钥。
- 对于响应报文,商户侧必须自行生成一对 RSA 2048 密钥。生成的密钥对包含一把公钥,必须在发送任何请求前注册到 ZOLOZ 系统。此后 ZOLOZ 服务使用该已注册的公钥加密响应报文。
2. 准备待加密内容
待加密内容为业务请求/响应的明文报文,通常是 JSON 字符串。
3. 生成 AES 对称密钥
随机生成 256 位数据作为 AES 对称密钥。
注意: 同一次请求/响应交互中,上下行复用同一把 AES 密钥:商户用它加密请求体,ZOLOZ 服务用它(随请求的
Encrypt头携带)加密响应体。每次新请求必须重新生成随机密钥。
4. 生成初始化向量(IV)
使用密码学安全的随机数生成器,随机生成 12 字节(96 位)IV。同一密钥下每条报文的 IV 必须唯一。IV 不是秘密,以明文形式通过 Encrypt 头传输。
5. 加密内容
使用 AES/GCM/NoPadding 和 128 位认证标签 加密内容,公式如下:
CIPHERTEXT_AND_TAG=aes_gcm_encrypt($CONTENT_TO_BE_ENCRYPTED, $AES_KEY, $IV)
CIPHERTEXT_STRING=base64_encode($CIPHERTEXT)
TAG_STRING=base64urlsafe_encode($TAG)
IV_STRING=base64urlsafe_encode($IV)使用的方法:
aes_gcm_encrypt:使用 AES-GCM 算法对报文进行加密和认证的 AEAD 方法。输出为密文,末尾附加 16 字节(128 位)认证标签。base64_encode:以**标准 Base64(带 padding)**编码密文。结果用作 HTTP body。base64urlsafe_encode:以 Base64URL 无 padding 方式编码二进制数据。结果用于Encrypt头中的iv和tag字段。使用无 padding 是为了避免=字符与头部的key=value语法冲突。
输入参数:
CONTENT_TO_BE_ENCRYPTED:步骤 2 中准备的内容字符串。AES_KEY:步骤 3 生成的 AES 对称密钥。IV:步骤 4 生成的初始化向量。
输出参数:
CIPHERTEXT_STRING:加密后的内容字符串(不含标签),即 HTTP body。IV_STRING:Base64URL 编码的 IV。TAG_STRING:Base64URL 编码的认证标签。
注意: 不使用附加认证数据(AAD)。认证标签仅保护密文。
6. 加密 AES 密钥
使用如下公式加密 AES 密钥:
ENCYRPTED_AES_KEY=urlencode(base64_encode(rsa_encrypt($AES_KEY, $PUBLIC_KEY)))使用的方法:
rsa_encrypt:使用 RSA/ECB/PKCS1Padding 加密 AES 密钥的方法。更多信息见 rsa_encrypt。base64_encode:以标准 Base64 编码加密后的数据。urlencode:对结果做 URL 编码,以便其作为Encrypt头的值被安全携带。
输入参数:
AES_KEY:步骤 3 生成的 AES 对称密钥。PUBLIC_KEY:步骤 1 获取的公钥。
输出参数:
ENCYRPTED_AES_KEY:加密后的 AES 密钥字符串。
7. 配置头和报文体
a. 配置 Encrypt 头。
按以下格式,在 HTTP 头的 Encrypt 字段中指定加密后的 AES 密钥、IV 和认证标签:
Encrypt: algorithm=RSA_AES_GCM, symmetricKey=<ENCYRPTED_AES_KEY>, iv=<IV_STRING>, tag=<TAG_STRING>b. 配置 Content-Type 头。
将 content type 设置为 text/plain :
content-type: text/plainc. 配置 HTTP 报文体。
将加密后的内容字符串(步骤 5 获得的 CIPHERTEXT_STRING,不含 IV 和标签)作为 HTTP body。
解密报文
解密流程
下图展示了从 ZOLOZ 服务视角如何解密请求报文,以及从商户视角如何解密响应报文。

图 2. 报文解密活动图
解密报文的步骤
1. 获取私钥
- 对于请求报文,在商户账户创建时,ZOLOZ 系统会生成一对 RSA 2048 密钥。生成的密钥对每个商户唯一,其中包含一把私钥。ZOLOZ 服务使用该私钥解密随加密请求携带的对称密钥。
- 对于响应报文,商户侧必须自行生成一对 RSA 2048 密钥。生成的密钥对包含一把私钥。商户使用该私钥解密随加密响应携带的对称密钥。
2. 获取待解密内容
待解密内容为整个已加密的 HTTP body(即密文字符串,不含 IV 和标签)。
3. 提取加密参数
从 HTTP 请求/响应头的 Encrypt 字段中,提取加密后的 AES 对称密钥、IV 和认证标签。
Encrypt: algorithm=RSA_AES_GCM, symmetricKey=<ENCRYPTED_AES_KEY>, iv=<IV_STRING>, tag=<TAG_STRING>注意: 根据头中的
algorithm字段决定解密算法。如果值为RSA_AES,使用旧版 AES-ECB 算法解密 body;如果值为RSA_AES_GCM,则按以下步骤执行。这保证了当 ZOLOZ 服务回滚到旧版算法时,客户端仍能正确处理响应。
4. 解密 AES 密钥
使用如下公式解密 AES 密钥:
AES_KEY=rsa_decrypt(base64_decode(urldecode($ENCRYPTED_AES_KEY)), $PRIVATE_KEY)使用的方法:
urldecode:对 URL 编码的值进行解码。base64_decode:对 Base64 编码的数据进行解码。rsa_decrypt:解密密文的方法。更多信息见 rsa_decrypt。
输入参数:
ENCRYPTED_AES_KEY:步骤 3 提取的加密 AES 密钥。PRIVATE_KEY:步骤 1 获取的私钥。
输出参数:
AES_KEY:随机生成的、用于加密报文内容的初始 AES 密钥。
5. 解密并校验内容
对 HTTP body 做 Base64 解码得到密文,对 iv 和 tag 做 Base64URL 解码,然后按如下公式解密并认证内容:
CIPHERTEXT_AND_TAG=concat(base64_decode($Content_To_Be_Decrypted), base64urlsafe_decode($TAG_STRING))
PLAIN_CONTENT_STRING=utf8_encode(aes_gcm_decrypt($CIPHERTEXT_AND_TAG, $AES_KEY, base64urlsafe_decode($IV_STRING)))使用的方法:
concat:将 16 字节认证标签附加到密文末尾(大多数 AES-GCM 实现解密时要求的输入格式)。aes_gcm_decrypt:使用 AES-GCM 算法对报文进行解密和认证的 AEAD 方法。如果认证标签不匹配,解密失败且不返回明文;必须拒绝该报文。utf8_encode:将二进制数据编码为 UTF-8 文本字符串。更多信息见 utf8_encode。
输入参数:
Content_To_Be_Decrypted:待解密内容,即步骤 2 获得的内容。TAG_STRING/IV_STRING:步骤 3 提取的认证标签和 IV。AES_KEY:步骤 4 获得的 AES 对称密钥。
输出参数:
PLAIN_CONTENT_STRING:待消费的明文内容字符串,通常是 JSON 字符串。