RSA加密

简介:

RSA加密是现今使用非常广泛的非对称加密之一。通过公钥加密,然后私钥解密来确保信息的在传输中的安全性,避免了直接传递密钥所造成的被破解的风险。通常个人保存私钥,公钥是公开的(可能同时多人持有)。
ps:

  • 非对称加密:加密和解密使用的是两个不同的密钥。速度相较对称加密较慢,适用于小数据加密,相对安全(RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法))
  • 对称加密:采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密。速度较之快,可适用于大数据加密,相对不安全(DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK)

图解

Created with Raphaël 2.2.0 数据 通过公钥加密 私钥解密 ? 结束 yes no

搭配环境

  1. 安装openssl(命令窗口中输入openssl,如进入openssl则成功)
    在这里插入图片描述
  2. php.ini文件中开启openssl.dll扩展
    去掉前面的分号
  3. 生成私钥 (genrsa -out rsa_private_key.pem 1024)
    生成私钥
  4. 生成公钥 (rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem)
    生成公钥
    秘钥存放地址为软件安装地址

ThinkPHP5示例

app\admin\controller\index\rsa_study

 /*
       *  RSA加密
       * @param  
       */
       public function rsa_study()
       {
           header('Content-Type:text/html;Charset=utft-8');
           //数据
           $data=['code'=>200,'data'=>['id'=>1],'msg'=>'success'];
           $data=json_encode($data);
           //加密
           $return = model('index')->encrypt($data);
           //解密
           $ret_d = model('index')->decrypt($return);
           //签名
           $a='test';
           $x = model('index')->sign($a);
           //验证,成功返回true
           $y = model('index')->verify($a, $x);
         
       }

app\admin\model\index.php

<?php

namespace app\admin\model;

class Index extends \think\Model
{
   public $rsa_private='';
   public $rsa_public='';

   public function __construct()
   {
       if(empty($this->rsa_public)){

          $this->_getPublicKey(ROOT_PATH.'rsa_public_key.pem');
       }
       if(empty($this->rsa_private)){

          $this->_getPrivateKey(ROOT_PATH.'rsa_private_key.pem');
       }

   }

   /**
    * 生成签名
    *
    * @param string 签名材料
    * @param string 签名编码(base64/hex/bin)
    * @return 签名值
    */
   public function sign($data, $code = 'base64')
   {
       $ret = false;
       if (openssl_sign($data, $ret, $this->rsa_private)) {
           $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->rsa_public, $padding)) {
           $ret = $this->_encode($result, $code);
       }
       return $ret;
   }

   /**
    * 解密
    *
    * @param string 密文
    * @param string 密文编码(base64/hex/bin)
    * @param int 填充方式(OPENSSL_PKCS1_PADDING / OPENSSL_NO_PADDING)
    * @param bool 是否翻转明文(When passing Microsoft CryptoAPI-generated RSA cyphertext, revert the bytes in the block)
    * @return string 明文
    */
   public function decrypt($data, $code = 'base64', $padding = OPENSSL_PKCS1_PADDING, $rev = false)
   {
       $ret = false;
       $data = $this->_decode($data, $code);
       if (!$this->_checkPadding($padding, 'de')) $this->_error('padding error');
       if ($data !== false) {
           if (openssl_private_decrypt($data, $result, $this->rsa_private, $padding)) {
               $ret = $rev ? rtrim(strrev($result), "\0") : '' . $result;
           }
       }
       return $ret;
   }

   /**
    * 检测填充类型
    * 加密只支持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;
   }

   private function _decode($data, $code)
   {
       switch (strtolower($code)) {
           case 'base64':
               $data = base64_decode($data);
               break;
           case 'hex':
               $data = $this->_hex2bin($data);
               break;
           case 'bin':
           default:
       }
       return $data;
   }

   private function _hex2bin($hex = false)
   {
       $ret = $hex !== false && preg_match('/^[0-9a-fA-F]+$/i', $hex) ? pack("H*", $hex) : false;
       return $ret;
   }

   // 私有方法
   /**
    * 自定义错误处理
    */
   private function _error($msg)
   {
       die('RSA Error:' . $msg); //TODO
   }

   private function _getPublicKey($file)
   {
       $key_content = $this->_readFile($file);
       if ($key_content) {
           $this->rsa_public = openssl_get_publickey($key_content);
       }

   }

   private function _getPrivateKey($file)
   {
       $key_content = $this->_readFile($file);
       if ($key_content) {
           $this->rsa_private = openssl_get_privatekey($key_content);
       }
   }

   private function _readFile($file)
   {
       $ret = false;
       if (!file_exists($file)) {
           $this->_error("The file {$file} is not exists");
       } else {
           $ret = file_get_contents($file);
       }
       return $ret;
   }

   /**
    * 验证签名
    *
    * @param string 签名材料
    * @param string 签名值
    * @param string 签名编码(base64/hex/bin)
    * @return bool
    */
   public function verify($data, $sign, $code = 'base64')
   {
       $ret = false;
       $sign = $this->_decode($sign, $code);
       if ($sign !== false) {
           switch (openssl_verify($data, $sign, $this->rsa_public)) {
               case 1:
                   $ret = true;
                   break;
               case 0:
               case -1:
               default:
                   $ret = false;
           }
       }
       return $ret;
   }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值