美文网首页PHP经验分享PHP开发记录
PHP中的RSA非对称加密,让数据不再裸跑

PHP中的RSA非对称加密,让数据不再裸跑

作者: 猪大圣三七 | 来源:发表于2020-03-04 15:02 被阅读0次

    前言:由于项目快速发展,敏感数据的保密传输也不够完善,前期开发写的比较简陋从而埋下隐患。迫切需要提升安全。翻阅相关文档也写到:‘’PHP服务端客户端交互或者提供开放API时,通常需要对敏感的数据进行加密。这时候RSA非对称加密就可以派上用处。“对此记录开发过程,总结心得。

    翻阅资料,先了解什么是非对称加密算法

    在非对称加密中使用的主要算法有:RSA、Elgamal、ESA、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等。不同算法的实现机制不同,可参考对应算法的详细资料。

    非对称加密算法:
    需要两个密钥来进行加密和解密,这两个秘钥是公开密钥(public key,简称公钥)私有密钥(private key,简称私钥)

    工作原理:用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;
    如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。
    因为加密和解密使用的是两个不同的密钥,所以这种算法叫作[非对称加密算法]

    与对称加密算法的对比
    优点:其安全性更好,对称加密的通信双方使用相同的秘钥,如果一方的秘钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存的,不需要像对称加密那样在通信之前要先同步秘钥。
    缺点:非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。

    前期准备

    前提:本文章是在TP5下操作。

    1.准备RSA算法类https://www.kancloud.cn/mikkle/thinkphp5_study/343303
    2.准备jsencrypt.jshttps://www.bootcdn.cn/jsencrypt/
    3.在线生产RSA秘钥工具。http://web.chacuo.net/netrsakeypair

    开始实操

    先上一个我修改过的RSA算法类

    <?php
    
    /**
     * Created by PhpStorm.
     * User: ***
     * Date: 2020/3/4
     */
    
    namespace Library;
    
    /**
     * RSA算法类
     * 签名及密文编码:base64字符串/十六进制字符串/二进制字符串流
     * 填充方式: PKCS1Padding(加解密)/NOPadding(解密)
     *
     * Notice:Only accepts a single block. Block size is equal to the RSA key size!
     * 如密钥长度为1024 bit,则加密时数据需小于128字节,加上PKCS1Padding本身的11字节信息,所以明文需小于117字节
     *
     * 加入生成私匙和公匙
     */
    class RsaEncryption
    {
    
        public $pubKey;
    
        private $priKey;
    
    
        /**
         * 初始化
         *
         */
        public function __construct()
        {
            $this->pubKey = '你的公钥';
            $this->priKey = '你的私钥';
        }
    
        /**
         * 自定义错误处理
         */
    
        private function _error($msg)
        {
            die('RSA Error:' . $msg); //TODO
        }
    
        /**
         * 生成签名
         *
         * @param string 签名材料
         * @param string 签名编码(base64/hex/bin)
         * @return 签名值
         */
    
        public function sign($data, $code = 'base64')
        {
            $ret = false;
            if (openssl_sign($data, $ret, $this->priKey)) {
                $ret = $this->_encode($ret, $code);
            }
            return $ret;
        }
    
    
        /**
         * 加密
         *
         * @param string 明文
         * @param string 密文编码(base64/hex/bin)
         * @param int 填充方式(貌似php有bug,所以目前仅支持OPENSSL_PKCS1_PADDING)
         * @return string 密文
         */
    
        public function encrypt($data, $code = 'base64', $padding = OPENSSL_PKCS1_PADDING)
        {
            $ret = false;
            if (!$this->_checkPadding($padding, 'en')) $this->_error('padding error');
            if (openssl_public_encrypt($data, $result, $this->pubKey, $padding)) {
                $ret = $this->_encode($result, $code);
            }
            return $ret;
        }
    
        /**
         * 解密
         * @param string $encryptString
         * @return string
         */
        public function privateDecrypt($encryptString = '')
        {
            $decrypted = '';
            $key = $this->priKey;
            $key_eol   = (string) implode("\n", str_split((string) $key, 64));
            $privateKey = (string) "-----BEGIN RSA PRIVATE KEY-----\n" . $key_eol . "\n-----END RSA PRIVATE KEY-----";
    
            openssl_private_decrypt(base64_decode($encryptString), $decrypted, $privateKey);
            return $decrypted;
        }
    
        /**
         * 加密
         * @param string $data
         * @return string
         */
        public function publicEncrypt($data = '')
        {
            $encrypt_data = '';
            $key = $this->pubKey;
    
            $key_eol   = (string) implode("\n", str_split((string) $key, 64));
            $publicKey = (string) "-----BEGIN PUBLIC KEY-----\n" . $key_eol . "\n-----END PUBLIC KEY-----";
            openssl_public_encrypt($data, $encrypt_data, $publicKey);
            $encrypt_data = base64_encode($encrypt_data);
            return $encrypt_data;
        }
    
        // 私有方法
    
        /**
         * 检测填充类型
         * 加密只支持PKCS1_PADDING
         * 解密支持PKCS1_PADDING和NO_PADDING
         *
         * @param int 填充模式
         * @param string 加密en/解密de
         * @return bool
         */
    
        private function _checkPadding($padding, $type)
        {
            if ($type == 'en') {
                switch ($padding) {
                    case OPENSSL_PKCS1_PADDING:
                        $ret = true;
                        break;
                    default:
                        $ret = false;
                }
            } else {
                switch ($padding) {
                    case OPENSSL_PKCS1_PADDING:
                    case OPENSSL_NO_PADDING:
                        $ret = true;
                        break;
                    default:
                        $ret = false;
                }
            }
            return $ret;
        }
        private function _encode($data, $code)
        {
            switch (strtolower($code)) {
                case 'base64':
                    $data = base64_encode('' . $data);
                    break;
                case 'hex':
                    $data = bin2hex($data);
                    break;
                case 'bin':
                default:
            }
            return $data;
        }
    }
    

    1.先引用RSA

    use Library\RsaEncryption;
    

    2.在需要加密数据的页面给公钥

    public function index()
        {
            $rsa = new RsaEncryption();
            $key = $rsa->pubKey;
            $this->assign('key', $key);
            //$redisInstall = Cache::getInstance('redis');
            return $this->fetch();
        }
    

    3.前端页面进行加密处理
    比如在表单提交需要对密码加密

    //需要加密的数据
    var pas = $('#password').val();
    
    var encrypt = new JSEncrypt();
    //用传来的公钥进行加密
    encrypt.setPublicKey('拿到的公钥');
    var encrypted = encrypt.encrypt(pas);
    
    //返给后端加密过后的数据
    var pwd = document.getElementById('pwd');
    pwd.value = encrypted;
    

    4.在后端解密

    $rsa = new RsaEncryption();
    $rsaPass = $rsa->privateDecrypt('传回来的数据');
    
    注意

    密钥不对可是会报以下错误。


    image.png

    切记格式要正确,不可有换行,要去头去尾。


    image.png

    总结

    以上是我对RSA加解密一些简单操作的一个记录,如果有帮助到大家,就可以了~ 望大佬勿喷勿喷。。

    相关文章

      网友评论

        本文标题:PHP中的RSA非对称加密,让数据不再裸跑

        本文链接:https://www.haomeiwen.com/subject/rqgplhtx.html