小程序开发在获取用户的数据信息方面,进行关键信息传输(openid)时是传输的encryptedData,就是加密之后的数据。

更多的说明在小程序文档中有提到:

接口如果涉及敏感数据(如wx.getUserInfo当中的 openId 和unionId ),接口的明文内容将不包含这些敏感数据。开发者如需要获取敏感数据,需要对接口返回的加密数据( encryptedData )进行对称解密。 解密算法如下:

  • 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
  • 对称解密的目标密文为 Base64_Decode(encryptedData)。
  • 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
  • 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。

1.jpg

一、需求

微信小程序官方是提供了一个demo示例,但是单独的文件引用使用等方面的,并不能直接在mvc框架中使用。

如果需要在 MVC开发框架 中使用,需要进行变通,为了之后使用方便,再次记录一下:

二、转成 Model

1. PKCS7Encoder.php


/**
 * Author: Postbird
 * Date  : 2017/5/13
 * time  : 19:10
 * Site  : www.ptbird.cn
 * There I am , in the world more exciting!
 */

class PKCS7Encoder
{
    public static $block_size = 16;

    /**
     * 对需要加密的明文进行填充补位
     * @param $text
     * @return string
     */
    function encode( $text )
    {
        $block_size = PKCS7Encoder::$block_size;
        $text_length = strlen( $text );
        //计算需要填充的位数
        $amount_to_pad = PKCS7Encoder::$block_size - ( $text_length % PKCS7Encoder::$block_size );
        if ( $amount_to_pad == 0 ) {
            $amount_to_pad = PKCS7Encoder::$block_size;
        }
        //获得补位所用的字符
        $pad_chr = chr( $amount_to_pad );
        $tmp = "";
        for ( $index = 0; $index < $amount_to_pad; $index++ ) {
            $tmp .= $pad_chr;
        }
        return $text . $tmp;
    }
    /**
     * 对解密后的明文进行补位删除
     * @param decrypted
     * @return string
     */
    function decode($text)
    {
        $pad = ord(substr($text, -1));
        if ($pad < 1 || $pad > 32) {
            $pad = 0;
        }
        return substr($text, 0, (strlen($text) - $pad));
    }

}

2. Prpcrypt.php


/**
 * Author: Postbird
 * Date  : 2017/5/13
 * time  : 19:11
 * Site  : www.ptbird.cn
 * There I am , in the world more exciting!
 */

class Prpcrypt 
{
    public $key;

    function Prpcrypt( $k )
    {
        $this->key = $k;
    }
    /**
     * 对密文进行解密
     * @param string $aesCipher 需要解密的密文
     * @param string $aesIV 解密的初始向量
     * @return string 解密得到的明文
     */
    public function decrypt( $aesCipher, $aesIV )
    {
        try {
            //解密
            $decrypted = openssl_decrypt(base64_decode($aesCipher), 'aes-128-cbc', base64_decode($this->key), OPENSSL_RAW_DATA, base64_decode($aesIV));
            // dump(($aesCipher));
            // dump(($this->key));
            // dump(($aesIV));
        } catch (\Exception $e) {
            return false;
        }
        try {
            //去除补位字符
            $pkc_encoder = new PKCS7Encoder;
            $result = $pkc_encoder->decode($decrypted);
        } catch (\Exception $e) {
            //print $e;
            return false;
        }
        return $result;
    }
}

3. WXBizDataCrypt.php


class WXBizDataCrypt extends Model
{
    private $appid;
    private $sessionKey;

    /**
     * 构造函数
     * @param $sessionKey string 用户在小程序登录后获取的会话密钥
     * @param $appid string 小程序的appid
     */
    public function WXBizDataCrypt( $appid, $sessionKey)
    {
        $this->sessionKey = $sessionKey;
        $this->appid = $appid;
    }


    /**
     * 检验数据的真实性,并且获取解密后的明文.
     * @param $encryptedData string 加密的用户数据
     * @param $iv string 与用户数据一同返回的初始向量
     * @param $data string 解密后的原文
     *
     * @return int 成功0,失败返回对应的错误码
     */
    public function decryptData( $encryptedData, $iv, &$data )
    {
        if (strlen($this->sessionKey) != 24) {
            // return ErrorCode::$IllegalAesKey;
            return false;
        }
        $aesKey=base64_decode($this->sessionKey);

        
        if (strlen($iv) != 24) {
            // return ErrorCode::$IllegalIv;
            return false;

        }
        $aesIV=base64_decode($iv);

        $aesCipher=base64_decode($encryptedData);

        $pc = new Prpcrypt($aesKey);
        $result = $pc->decrypt($aesCipher,$aesIV);
        
        if ($result[0] != 0) {
            return $result[0];
        }
     
        $dataObj=json_decode( $result[1] );
        if( $dataObj  == NULL )
        {
            // return ErrorCode::$IllegalBuffer;
            return false;
        }
        if( $dataObj->watermark->appid != $this->appid )
        {
            // return ErrorCode::$IllegalBuffer;
            return false;
        }
        $data = $result[1];
        // return ErrorCode::$OK;
        return true;
    }

}

4. 几个变化的地方:

  • 没有使用ErrorCode.php,在框架开发过程中,只返回true或者是false

    • 因为小程序后台开发都是API

三、使用方法

1. 需要在同一个namespace中

2. 需要use

如:我需要进行关键信息的解密

// 解密
$pr=new Prpcrypt();
$pr->Prpcrypt($sessionKey);
$d=$pr->decrypt($encryptedData,$iv);
  • 可以看出只要use了相关的model,直接使用就OK很方便