================================================================================
BSPHP 客户端请求：加密与签名方式说明（与 C/C#/C++ DEMO 一致）
================================================================================
本文档描述 AppEn 接口在 HTTP 层上的打包、加密、签名与响应解包流程。
实现参考：本仓库 src/com/bsphp/demo/CryptoFlow.as

--------------------------------------------------------------------------------
一、时间与会话相关字段
--------------------------------------------------------------------------------

1) appsafecode（32 位小写十六进制 MD5）
   - 计算对象：当前本地时间字符串
   - 格式：yyyy-MM-dd HH:mm:ss（中间是空格，不是 #）
   - 公式：appsafecode = MD5(上述时间字符串) 的十六进制小写字符串

2) date（参与明文组包的时间）
   - 格式：yyyy-MM-dd#HH:mm:ss（日期与时间之间是 #）
   - 与 appsafecode 使用的时间应对应同一时刻（实现里通常在同一函数内生成）

3) BSphpSeSsL
   - 会话令牌。首次可为空；完成 BSphpSeSsL.in 后填入返回的会话值。
   - 登录成功等接口可能返回新的 SeSsL，需要更新本地保存。

--------------------------------------------------------------------------------
二、明文参数串（加密前）
--------------------------------------------------------------------------------

1) 基础字段（所有接口都会带）
   - api          接口名，例如 internet.in、login.lg
   - BSphpSeSsL   会话
   - date         见上文
   - md5          见下文“自校验 md5”
   - mutualkey    互验密钥（后台配置）
   - appsafecode  见上文

2) 业务字段
   - 按具体接口追加，例如登录：user、pwd、coode、key、maxoror 等。

3) URL 编码规则（明文拼接）
   - 将“键值对”用 & 连接：key1=value1&key2=value2&...
   - 键和值都需要做百分号编码（类似 Uri.EscapeDataString：UTF-8 字节再 %XX）
   - 注意：+ 不要当成空格解码（响应体里 Base64 的 + 必须保留）

4) md5 字段的计算顺序（重要）
   - 第一步：先组“不含 md5 字段”的键值对，按同样规则 URL 编码后拼成一串，记为 plain_without_md5。
   - 第二步：md5_self = MD5(plain_without_md5) 的十六进制小写字符串。
   - 第三步：把 md5 字段加入参数，再拼最终用于加密的完整明文 plain（含 md5）。

--------------------------------------------------------------------------------
三、AES-128-CBC 加密（请求体）
--------------------------------------------------------------------------------

1) AES 密钥推导
   - 材料：服务端 RSA 私钥的 Base64 字符串（配置里的 SERVER_KEY，仅作密钥材料参与哈希，不是把私钥发给服务器）
   - 公式：aes_key_full = MD5(SERVER_KEY_BASE64 + appsafecode) 的十六进制小写字符串
   - 取前 16 个字符作为 AES 密钥：aes_key = aes_key_full.substring(0, 16)
   - 说明：这 16 个字符按 UTF-8 字节作为 128 位密钥使用（与 C# DEMO 一致）

2) 模式与 IV
   - 算法：AES-128-CBC
   - IV：与 Key 相同（16 字节，与密钥字节一致）
   - 填充：PKCS#7（与 PKCS5 在 AES 块大小下等价）

3) 密文形式
   - 对 UTF-8 编码的明文串 plain 加密后，再做 Base64，得到 encrypted_b64（一行，无换行）

--------------------------------------------------------------------------------
四、RSA 签名串与公钥加密（请求体）
--------------------------------------------------------------------------------

1) 对 AES 密文再做 MD5
   - sig_md5 = MD5(encrypted_b64) 的十六进制小写字符串

2) 待 RSA 加密的“签名字符串”（明文，管道分隔）
   - 格式固定为：
     0|AES-128-CBC|<aes_key>|<sig_md5>|<SIGNATURE_TAIL>
   - 其中 <aes_key> 为第三节中的 16 字符密钥
   - SIGNATURE_TAIL 一般为 json（与后台约定；写错会导致服务端验签失败）

3) RSA 加密
   - 使用“客户端 RSA 公钥”（CLIENT_KEY，Base64 DER）
   - 填充：PKCS#1 v1.5（PKCS1）
   - 输出：对密文二进制做 Base64，得到 rsa_b64

--------------------------------------------------------------------------------
五、HTTP POST 形式
--------------------------------------------------------------------------------

1) 拼接
   - payload = encrypted_b64 + "|" + rsa_b64

2) 整段 URL 编码
   - encoded = UrlEncode(payload)   （对整个字符串做百分号编码）

3) POST 正文
   - Content-Type: application/x-www-form-urlencoded
   - Body: parameter=<encoded>

--------------------------------------------------------------------------------
六、响应解密（服务端返回）
--------------------------------------------------------------------------------

1) 原始响应可能是 URL 编码过的，先 UrlDecode 得到 raw。

2) 分段（兼容两种前缀）
   - 若形如：OK...|encrypted_b64|rsa_b64  （三段，首段为 OK 开头）
     则取第二段为 AES 密文，第三段为 RSA 密文。
   - 否则按两段：encrypted_b64|rsa_b64

3) RSA 解密（服务端私钥）
   - 用 SERVER_KEY（PKCS#8 私钥 DER Base64）对 rsa_b64 做 RSA PKCS#1 解密，得到签名字符串 sig_plain。
   - sig_plain 格式与第四节类似，用 | 分段，取其中的 AES 密钥材料（响应侧一般为 32 位 hex 的前 16 字符作为 AES key，与 DEMO 解析方式一致）。

4) AES 解密
   - 用响应中解析出的 AES key（16 字符，UTF-8 字节 + IV 同 key），AES-128-CBC 解密 encrypted_b64，得到 JSON 或 XML 明文。

5) 业务字段
   - JSON：常见结构里可能在根上，也可能在 response 对象下，需解析 code、data、SeSsL、appsafecode 等。

--------------------------------------------------------------------------------
七、安全提示
--------------------------------------------------------------------------------

- SERVER_KEY、CLIENT_KEY、MUTUAL_KEY 属于敏感配置，勿提交到公开仓库或泄露给未授权方。
- 生产环境应使用你们自己后台颁发的密钥对，并替换 DEMO 中的示例地址与参数。

================================================================================
文档结束
================================================================================
