AES-GCM报文加密和报文解密

报文加密和报文解密

ZOLOZ 网关协议提供报文加密能力,确保报文在传输过程中数据不被篡改。

如果商户发送的请求是加密的,ZOLOZ 服务返回的响应也是加密的;否则,ZOLOZ 服务返回的响应不加密。

由于 ZOLOZ 服务处理的数据可能包含敏感信息,为增强报文传输安全性,ZOLOZ 服务会对响应报文进行加密。敏感信息包括所有敏感的个人身份信息(PII),如姓名、身份证号、生日、地址、人脸等。

对称加密算法为 AES-GCM(AEAD,加密与认证一体)。与旧版 RSA_AES 算法(AES-ECB,仅加密)相比,AES-GCM 通过 128 位认证标签提供密文完整性认证。旧版 RSA_AES 算法为兼容旧客户端仍然支持;客户端必须根据响应 Encrypt 头中的 algorithm 字段决定解密算法,而不是依赖本地配置。

加密报文

加密流程

下图展示了从商户视角如何加密请求报文,以及从 ZOLOZ 服务视角如何加密响应报文。

image

图 1. 报文加密活动图

加密报文的步骤

1. 获取公钥

  1. 对于请求报文,在商户账户创建时,ZOLOZ 系统会生成一对 RSA 2048 密钥。生成的密钥对每个商户唯一,其中包含一把公钥。商户需要事先获取该公钥。
  2. 对于响应报文,商户侧必须自行生成一对 RSA 2048 密钥。生成的密钥对包含一把公钥,必须在发送任何请求前注册到 ZOLOZ 系统。此后 ZOLOZ 服务使用该已注册的公钥加密响应报文。

2. 准备待加密内容

待加密内容为业务请求/响应的明文报文,通常是 JSON 字符串。

3. 生成 AES 对称密钥

随机生成 256 位数据作为 AES 对称密钥。

注意: 同一次请求/响应交互中,上下行复用同一把 AES 密钥:商户用它加密请求体,ZOLOZ 服务用它(随请求的 Encrypt 头携带)加密响应体。每次新请求必须重新生成随机密钥。

4. 生成初始化向量(IV)

使用密码学安全的随机数生成器,随机生成 12 字节(96 位)IV。同一密钥下每条报文的 IV 必须唯一。IV 不是秘密,以明文形式通过 Encrypt 头传输。

5. 加密内容

使用 AES/GCM/NoPadding128 位认证标签 加密内容,公式如下:

copy
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 头中的 ivtag 字段。使用无 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 密钥:

copy
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 和认证标签:

copy
Encrypt: algorithm=RSA_AES_GCM, symmetricKey=<ENCYRPTED_AES_KEY>, iv=<IV_STRING>, tag=<TAG_STRING>

b. 配置 Content-Type 头。

将 content type 设置为 text/plain :

copy
content-type: text/plain

c. 配置 HTTP 报文体。

将加密后的内容字符串(步骤 5 获得的 CIPHERTEXT_STRING不含 IV 和标签)作为 HTTP body。

解密报文

解密流程

下图展示了从 ZOLOZ 服务视角如何解密请求报文,以及从商户视角如何解密响应报文。

image

图 2. 报文解密活动图

解密报文的步骤

1. 获取私钥

  • 对于请求报文,在商户账户创建时,ZOLOZ 系统会生成一对 RSA 2048 密钥。生成的密钥对每个商户唯一,其中包含一把私钥。ZOLOZ 服务使用该私钥解密随加密请求携带的对称密钥。
  • 对于响应报文,商户侧必须自行生成一对 RSA 2048 密钥。生成的密钥对包含一把私钥。商户使用该私钥解密随加密响应携带的对称密钥。

2. 获取待解密内容

待解密内容为整个已加密的 HTTP body(即密文字符串,不含 IV 和标签)。

3. 提取加密参数

从 HTTP 请求/响应头的 Encrypt 字段中,提取加密后的 AES 对称密钥、IV 和认证标签。

copy
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 密钥:

copy
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 解码得到密文,对 ivtag 做 Base64URL 解码,然后按如下公式解密并认证内容:

copy
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 字符串。