开放平台Token加密方式



版本:v0.0.1

最新更新日期:2022-03-17

更新日志

日期

变更类别

说明

2022-03-17

更新

token生成方式


一、背景介绍

根据商家需求需要与蓉卡系统对接。

信息输出方:商户

信息接收方:成都蓉卡科技有限公司


二、技术方案

成都蓉卡科技有限公司出具接口文档的约定(本文档下文)。

 

三、接入步骤

  1. 商家向蓉卡销售人员获取(mid、rsa私钥);

  2. 根据蓉卡科技有限公司提供的接口上传数据;


四、接口协议

4.1 接口签名方案

商家请求接口时,会带上签名参数。因此厂商接口需要校验签名是否合法,避免被第三方恶意调用,导致信息泄漏。

请求接口的HTTP header中加上这些http请求头(全部小写)


'mid': 'xxxx',
'token': 'xxxxx'


其中mid为颁发的mid,token为商家rsa私钥加密的随机字符串。

签名的构建方式是:sign=a&timestamp=1648287087,timestamp为当前十位时间戳(秒),sign为传输数据按字母排序后MD5小写的数据;

另外,timestamp有5分钟过期的判断。

签名的mid和rsa私钥由蓉卡销售人员提供

HTTP的Content-Type请使用application/json


接口里的鉴权php代码示例:

SIGN签名生成:
/**
 * @param $data
 * 获取需要的签名
 */
protected function getSign($data)
{
    ksort($data);
    $str = "";
    foreach ($data as $k => $value) $str .= '&' . $k . '=' . $value;
    $str = substr($str, 1);
    return md5($str);
}


TOKEN生成:
$token = ['timestamp' => time(),'sign' => $this->getSign()];
$token = http_build_query($token);
$rsa = RSA::rsaPrivateEncrypt($key->private_secret, $token);

/**
 * @param $private :私钥字符串
 * @param $str :待加密的字符串
 * @return false:加密失败,true成功返回base64数据
 * 私钥加密PHP版本
 */
public function rsaPrivateEncrypt($private, $str)
{
    $private = openssl_pkey_get_private($private);
    if (!$private) {
        return false;
    }
    $crypto = '';
    foreach (str_split($str, 117) as $chunk) {
        openssl_private_encrypt($chunk, $encryptData, $private);
        $crypto .= $encryptData;
    }
    if (!$crypto) {
        return false;
    }
    return base64_encode($crypto);
}


接口里的鉴权java代码示例:


         /**
     * 加密算法RSA
     */
    private val KEY_ALGORITHM = "RSA"

    /**
     * 加密算法RSA
     */
    private val KEY_TRANSFORMATION = "RSA/ECB/PKCS1Padding"

    /**
     * RSA最大加密明文大小
     */
    private val MAX_ENCRYPT_BLOCK = 117

    /**
     * RSA最大解密密文大小
     */
    private val MAX_DECRYPT_BLOCK = 128
    
     /**
     * 私钥加密
     * @param   data 源数据
     * @param   privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    fun encryptByPrivateKey(data: ByteArray, privateKey: String?): ByteArray? {
        val keyBytes: ByteArray = base64Decode(privateKey)
        val pkcs8KeySpec = PKCS8EncodedKeySpec(keyBytes)
        val keyFactory = KeyFactory.getInstance(KEY_ALGORITHM)
        val privateK: Key = keyFactory.generatePrivate(pkcs8KeySpec)
        val cipher = Cipher.getInstance(KEY_TRANSFORMATION)
        cipher.init(Cipher.ENCRYPT_MODE, privateK)
        val inputLen = data.size
        val out = ByteArrayOutputStream()
        var offSet = 0
        var cache: ByteArray
        var i = 0
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            cache = if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK)
            } else {
                cipher.doFinal(data, offSet, inputLen - offSet)
            }
            out.write(cache, 0, cache.size)
            i++
            offSet = i * MAX_ENCRYPT_BLOCK
        }
        val encryptedData = out.toByteArray()
        out.close()
        return encryptedData
    }