epay_crypto (erlang_pay v0.3.2)

View Source

支付密码学原语 / Payment cryptographic primitives

仅依赖 OTP 内置 crypto / public_key,无第三方依赖。覆盖三家网关 live 分支所需的全部算法(对标官方 wechatpay-go/utils 与 stripe-go):

  • RSA SHA256withRSA(PKCS#1 v1.5) 签名/验签(支付宝 RSA2、微信 APIv3)
  • HMAC-SHA256(Stripe Webhook)
  • AES-256-GCM 解密(微信 v3 回调 resource 解密;APIv3 key 直用,无 KDF)
  • 常量时间比较(防时序攻击)
  • PEM 私钥/公钥解析(支持裸 base64 公钥自动补 PEM 头,适配支付宝)
  • 小写 hex(Stripe 签名为小写 hex)

安全约束:本模块不打印任何密钥/签名/明文;调用方亦不得将其入日志。

Summary

Functions

AES-256-GCM 解密。 微信约定:密文 = base64(密文 || 16 字节 GCM Tag);Key=APIv3Key(32 字节, 直接使用,不做任何 KDF 派生);Nonce/AAD 为明文字符串字节。 Tag 校验失败(认证失败/密文被篡改)返回 {error, auth_failed}。

常量时间二进制比较,防时序侧信道。等长才逐字节异或累计;不等长直接 false(长度本身非秘密)。

HMAC-SHA256,返回原始字节。

HMAC-SHA256,返回小写 hex(Stripe v1 签名格式)。

原始字节转小写 hex。

生成 N 字节强随机数的小写 hex 串(请求 nonce_str 用)。

用 PEM 私钥对 Message 做 SHA256withRSA 签名,返回原始签名字节。 支持 PKCS#1(-----BEGIN RSA PRIVATE KEY-----)与 PKCS#8(-----BEGIN PRIVATE KEY-----)两种私钥格式。

用 PEM 公钥(或 X.509 SubjectPublicKeyInfo / 裸 base64 公钥)验证 SHA256withRSA 签名。Signature 为原始签名字节(非 base64/hex)。

Functions

aes_256_gcm_decrypt(CipherB64, Key, Nonce, Aad)

-spec aes_256_gcm_decrypt(binary(), binary(), binary(), binary()) -> {ok, binary()} | {error, atom()}.

AES-256-GCM 解密。 微信约定:密文 = base64(密文 || 16 字节 GCM Tag);Key=APIv3Key(32 字节, 直接使用,不做任何 KDF 派生);Nonce/AAD 为明文字符串字节。 Tag 校验失败(认证失败/密文被篡改)返回 {error, auth_failed}。

constant_time_equal/2

-spec constant_time_equal(binary(), binary()) -> boolean().

常量时间二进制比较,防时序侧信道。等长才逐字节异或累计;不等长直接 false(长度本身非秘密)。

hmac_sha256(Key, Data)

-spec hmac_sha256(binary(), binary()) -> binary().

HMAC-SHA256,返回原始字节。

hmac_sha256_hex(Key, Data)

-spec hmac_sha256_hex(binary(), binary()) -> binary().

HMAC-SHA256,返回小写 hex(Stripe v1 签名格式)。

lower_hex(Bin)

-spec lower_hex(binary()) -> binary().

原始字节转小写 hex。

nonce(NBytes)

-spec nonce(pos_integer()) -> binary().

生成 N 字节强随机数的小写 hex 串(请求 nonce_str 用)。

rsa_sign_sha256/2

-spec rsa_sign_sha256(binary(), binary()) -> {ok, binary()} | {error, atom()}.

用 PEM 私钥对 Message 做 SHA256withRSA 签名,返回原始签名字节。 支持 PKCS#1(-----BEGIN RSA PRIVATE KEY-----)与 PKCS#8(-----BEGIN PRIVATE KEY-----)两种私钥格式。

rsa_verify_sha256/3

-spec rsa_verify_sha256(binary(), binary(), binary()) -> boolean().

用 PEM 公钥(或 X.509 SubjectPublicKeyInfo / 裸 base64 公钥)验证 SHA256withRSA 签名。Signature 为原始签名字节(非 base64/hex)。