微信/支付宝的付款码,你知道怎么实现的吗?

付款码,你真的熟悉它吗?
付款码,你真的熟悉它吗?

付款码大家司空见惯了,每天都用,但是有多少人了解它呢? 平时新闻里面经常说不要把付款码泄露给别人,真的有那么危险吗?

其实,数学家和算法工程师才没那么笨,现在介绍几个算法,来探究一下付款码是怎么实现的。

付款码的交互流程

所谓的付款码,实际上是一串动态数字密码,由微信/支付宝生成,商户扫了付款码后,上传到微信/支付宝服务器,通过验证后,系统提取用户ID后即可完成扣费操作。

动态令牌算法

动态令牌算法叫做OTP(One-Time-Password,一次性密码),其中对于次数限制和时间限制,会有两种略有差别的算法:

  • HOTP (HMAC-based One-Time Password),表示基于特定数值算法加密的一次性密码。
  • TOTP (Time-based One-Time Password),表示基于时间戳算法的一次性密码。

TOTP实际上是HOTP的一种变种算法,只是将特定数值跟时间关联起来。

TOTP签名生成原理

首先,厂商一般会在软件内置两个参数:密钥K质数M

其中密钥K是用来生成签名信息,质数M是用来做用户ID分割。


HTOP的运算公式为:

//K为密钥字符串
//C为特定值,一般情况下为随机值
//Truncate函数是将截取加密后的串,并取加密后串的某些字段组成一个数字
HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

TOTP的运算公式为:

//T 表示当前Unix时间戳,单位秒
//一般T0 = 0
//X 表示时间步数,也就是说多长时间产生一个动态密码,这个时间间隔就是时间步数X,比如支付宝是60秒
//这个公式表达是从系统起始到现在,当前属于第几个密码周期
C = (T - T0) / X

//直接调用HOTP即可计算出来
TOTP(K,C) = HOTP(K,C)

不同厂家,X参数会有不同:

  • 阿里巴巴的身份宝使用的时间步数是60秒;
  • 工商银行U盾令牌使用的时间步数是5分钟;
  • Google的 身份验证器的时间步数是30秒;
  • 腾讯的Token时间步数是60秒;

付款码生成

初中数学老师教过,由于质数是的约数只有1和自己,所以通过简单的除法求余就能轻松分离TOTP签名用户ID。数学就是那么魔幻炫酷。

//质数M取值需要大于最大用户ID,如:当前系统设计最大承受用户有9990人,则质数可以设定必须大于9990
付款码=TOTP签名 * 质数M +  用户ID

付款码还原

TOTP签名 = 付款码 / 质数M

用户ID = 付款码 % 质数M

拿到用户ID后,就可以查询数据库,取出用户的密钥K,通过当前的时间周期进行同步签名验证TOTP签名,如果签名通过,说明用户是在有效期内上传的付款码,接下来就是判断付款码是否使用过,没用过的话,就可以继续走风控和扣款流程了。

实际开发中,并不会将用户ID放进来,而且改成密钥ID,这样子同一个用户在不同设备上,就可以使用不同的密钥K生成不一样的付款码了,也利于厂商追踪支付渠道。

总结

  • 通过以上算法可以得知,用户ID质数M是公开的,只有密钥K是必须保密的
  • 微信、支付宝等都会使用加密和空间去存储这个密钥K,而且会定时同步更新服务器时间
  • 银行U盾这种离线设备,就会将密钥K加密存到硬件内部
  • 不必要担心截图付款码就会被人盗刷,毕竟付款码有效期只有短短的60秒