要把同道的人当作朋友,而不必把同利的人当作朋友。 --罗兰
上次曾经分享过一个自己写的微信操作类,虽然有注释,但是看起来还是有些费力。今天同样给大伙带来一篇微信相关的文章,今天主要谈的是微信数据加密类的实现,这次的分享,我会细致的一步步的说明这个类的工作原理。不过值得一提的是,我用的加密类是98%官方源码+2%自定义代码。所以,想要看明白并且成功的用起来,还是需要有一定PHP基础的。
文件名及文件作用
 1. ErrorCode.php [ 定义错误码 ]
 2. Pkcs7Encoder.php [ 基于PKCS7算法的加解密 ]
 3. Prpcrypt.php [ 加解密接口 ]
 4. Sha1.php [ 用SHA1算法生成安全签名 ]
 5. WxCrypt.php [ 应对各个场景做的函数封装相比于加解密接口更具有针对性 ]ErrorCode.php
这个文件主要是统一返回码的,对各个错误类型进行了全局的控制,为调试带来便利,这个文件没啥好说的,就是定义了一堆常量而已。
| 常量名 | 常量值 | 说明 | 
|---|---|---|
| OK | 0 | 没有错误 | 
| ValidateSignatureError | -40001 | 签名验证错误 | 
| ParseXmlError | -40002 | xml解析失败 | 
| ComputeSignatureError | -40003 | sha加密生成签名失败 | 
| IllegalAesKey | -40004 | encodingAesKey非法 | 
| ValidateCorpidError | -40005 | corpid 校验错误 | 
| EncryptAESError | -40006 | aes 加密失败 | 
| DecryptAESError | -40007 | aes 解密失败 | 
| IllegalBuffer | -40008 | 解密后得到的buffer非法 | 
| EncodeBase64Error | -40009 | base64加密失败 | 
| DecodeBase64Error | -40010 | base64解密失败 | 
| GenReturnXmlError | -40011 | 生成xml失败 | 
我们从错误类型就可以看出,微信为了提高安全性,对数据进行了两层加密,分别是AES和Base64。同时微信加密的身份令牌是用sha这个Hash算法计算出来的。最后就是在微信加解密的类库中,自带了关于XML的操作函数。
Pkcs7Encoder.php
这个类主要是用来实现基于PKCS7算法的加解密,何为PKCS7算法呢?我也不去百度了,直接根据代码,上个demo就可以了。
class Pkcs7Encoder {
    public static $block_size = 32; //最终字符串长度必定是这个值得整数倍数
    /**
    * 对需要加密的明文进行填充补位
    * @param $text 需要进行填充补位操作的明文
    * @return 补齐明文字符串
    */
    public function encode($text){
        $block_size = self::$block_size;
        //这里计算出现有字符串长度,假设现在字符串为“zxczxczxc”  那么它的长度就是9
        $text_length = strlen($text);
        //因为我们最终的字符长度一定是$block_size的整数倍,所以我们计算出后面还需要补上的字符个数,我们这里需要补上23个字符
        $amount_to_pad = $block_size - ($text_length % $block_size);
        //如果很凑巧原始字符串的长度就是$block_size的整数倍,那么我们就在原始字符串后边在接上长度为$block_size的字符串
        if ($amount_to_pad == 0) {
            $amount_to_pad = $block_size;
        }
        //根据需要补位的位数获得补位所用的字符,我们这里就是chr(23)
        $pad_chr = chr($amount_to_pad);
        $tmp = "";
        for ($index = 0; $index < $amount_to_pad; $index++) {
            $tmp .= $pad_chr;
        }
        //最终在原始字符串后边补上23个字符chr(23)
        return $text . $tmp;
    }
    /**
    * 对解密后的明文进行补位删除
    * @param decrypted 解密后的明文
    * @return 删除填充补位后的明文
    */
    public function decode($text){
        //根据补位函数,我们不难看出,字符串在补位后,最后一个字符一定是我们计算出来的特殊字符,也就是上面说的chr(23),这里用ord函数获得整数23 ,这个23就表示了我们最终在字符串后拼接了23个特殊字符
        $pad = ord(substr($text, -1));
        if ($pad < 1 || $pad > self::$block_size) {
            $pad = 0;
        }
        //用substr函数截取出我们的原始字符串
        return substr($text, 0, (strlen($text) - $pad));
    }
}这个类为原始的字符串进行了扰码的添加,更加提高了其安全性能。到这里我虽然还是不明白PKCS7的具体定义,但是可以知道,通过PKCS7可以为字符串加上扰码。
Sha1.php
这个类主要是用来生成计算身份令牌的,用于身份确认的。
    //这个类,也就只有这么一个函数
    public function getSHA1($token, $timestamp, $nonce, $encrypt_msg){
        //排序
        try {
            //组成一个特定数组
            $array = array($encrypt_msg, $token, $timestamp, $nonce);
            //这是进行参数排序,其实这一步我个人认为是没有必要的,因为上一步我们已经手工排好了顺序了,这里再次排序就显得有点多余。当然,这里的排序代码不能去掉,因为微信服务端做了排序了,如果你去掉,那么验证肯定没法通过的。
            sort($array, SORT_STRING);
            $str = implode($array);
            return array(ErrorCode::OK, sha1($str));
        } catch (\Exception $e) {
            print $e . "\n";
            return array(ErrorCode::ComputeSignatureError, null);
        }
    }基于时间戳,基于随机字符串,基于Token等计算出一个signal,从这里可以看出,微信在确认请求者身份这件事情上,也并没有什么特别的方法,也用了这种常见的认证方法。
最后说两句:今天我将加密系列类中的较为简单的三个类说了下,还有两个较为复杂的,甚至还夹杂了些业务逻辑的类,我打算明天再聊。另外,我希望这套接口验证,及数据加密形式能够给大家带来灵感,让大家的API变的更加安全可靠。
			本文由 陌上花开 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jul 1, 2016 at 06:15 am