PHP的RSA加密解密方法以及开发接口使用


Posted in PHP onFebruary 11, 2018

网络安全问题很重要,尤其是保证数据安全,遇到很多在写接口的程序员直接都是明文数据传输,在我看来这是很不专业的。本人提倡经过接口的数据都要进行加密解密之后进行使用。

这篇文章主要介绍使用PHP开发接口,数据实现RSA加密解密后使用,实例分析了PHP自定义RSA类实现加密与解密的技巧,非常具有实用价值,需要的朋友可以参考下。

简单介绍RSA

RSA加密算法是最常用的非对称加密算法,CFCA在证书服务中离不了它。但是有不少新手对它不太了解。下面仅作简要介绍。RSA是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名。RSA以它的三个发明者Ron Rivest, Adi Shamir, Leonard Adleman的名字首字母命名,这个算法经受住了多年深入的密码分析,虽然密码分析者既不能证明也不能否定RSA的安全性,但这恰恰说明该算法有一定的可信性,目前它已经成为最流行的公开密钥算法。RSA的安全基于大数分解的难度。其公钥和私钥是一对大素数(100到200位十进制数或更大)的函数。从一个公钥和密文恢复出明文的难度,等价于分解两个大素数之积(这是公认的数学难题)。

下面为具体类、实例:

<?php 
 
/** 
 * 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字节 
 * 
 * @author: ZHIHUA_WEI 
 * @version: 1.0.0 
 * @date: 2017/06/30 
 */ 
class RSA 
{ 
  private $pubKey = null; 
  private $priKey = null; 
 
  /** 
   * 构造函数 
   * 
   * @param string 公钥文件(验签和加密时传入) 
   * @param string 私钥文件(签名和解密时传入) 
   */ 
  public function __construct($public_key_file = '', $private_key_file = '') 
  { 
    if ($public_key_file) { 
      $this->_getPublicKey($public_key_file); 
    } 
    if ($private_key_file) { 
      $this->_getPrivateKey($private_key_file); 
    } 
  } 
 
  // 私有方法 
  /** 
   * 自定义错误处理 
   */ 
  private function _error($msg) 
  { 
    die('RSA Error:' . $msg); //TODO 
  } 
 
  /** 
   * 检测填充类型 
   * 加密只支持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 _getPublicKey($file) 
  { 
    $key_content = $this->_readFile($file); 
    if ($key_content) { 
      $this->pubKey = openssl_get_publickey($key_content); 
    } 
  } 
 
  private function _getPrivateKey($file) 
  { 
    $key_content = $this->_readFile($file); 
    if ($key_content) { 
      $this->priKey = 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; 
  } 
 
  private function _hex2bin($hex = false) 
  { 
    $ret = $hex !== false && preg_match('/^[0-9a-fA-F]+$/i', $hex) ? pack("H*", $hex) : false; 
    return $ret; 
  } 
 
  /** 
   * 生成签名 
   * 
   * @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 签名值 
   * @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->pubKey)) { 
        case 1: 
          $ret = true; 
          break; 
        case 0: 
        case -1: 
        default: 
          $ret = false; 
      } 
    } 
    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 密文 
   * @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->priKey, $padding)) { 
        $ret = $rev ? rtrim(strrev($result), "\0") : '' . $result; 
      } 
    } 
    return $ret; 
  } 
}

此为具体的RSA类

<?php 
/** 
 * Author: Wei ZhiHua 
 * Date: 2017/6/30 0030 
 * Time: 上午 10:15 
 */ 
header('Content-Type:text/html;Charset=utf-8;'); 
include "RSA.php"; 
echo '<pre>'; 
 
$pubfile = 'D:\WWW\test\rsa_public_key.pem'; 
$prifile = 'D:\WWW\test\rsa_private_key.pem'; 
$rsa = new RSA($pubfile, $prifile); 
$rst = array( 
  'ret' => 200, 
  'code' => 1, 
  'data' => array(1, 2, 3, 4, 5, 6), 
  'msg' => "success", 
); 
$ex = json_encode($rst); 
//加密 
$ret_e = $rsa->encrypt($ex); 
//解密 
$ret_d = $rsa->decrypt($ret_e); 
echo $ret_e; 
echo '<pre>'; 
echo $ret_d; 
echo '<pre>';  
$a = 'test'; 
//签名 
$x = $rsa->sign($a); 
//验证 
$y = $rsa->verify($a, $x); 
var_dump($x, $y); 
exit;
PHP 相关文章推荐
详细介绍:Apache+PHP+MySQL配置攻略
Sep 05 PHP
下载文件的点击数回填
Oct 09 PHP
如何在PHP程序中防止盗链
Apr 09 PHP
基于PHP Web开发MVC框架的Smarty使用说明
Apr 19 PHP
php常用Output和ptions/Info函数集介绍
Jun 19 PHP
解析如何通过PHP函数获取当前运行的环境 来进行判断执行逻辑(小技巧)
Jun 25 PHP
输入值/表单提交参数过滤有效防止sql注入的方法
Dec 25 PHP
Windows7下的php环境配置教程
Feb 28 PHP
PHP+AJAX实现投票功能的方法
Sep 28 PHP
win7 wamp 64位 php环境开启curl服务遇到的问题及解决方法
Sep 16 PHP
Laravel学习笔记之Artisan命令生成自定义模板的方法
Nov 22 PHP
Laravel5.1 框架表单验证操作实例详解
Jan 07 PHP
php+ajax实现无刷新文件上传功能(ajaxuploadfile)
Feb 11 #PHP
PHP实现的多维数组排序算法分析
Feb 10 #PHP
ThinkPHP整合datatables实现服务端分页的示例代码
Feb 10 #PHP
PHP实现APP微信支付的实例讲解
Feb 10 #PHP
PHP有序表查找之插值查找算法示例
Feb 10 #PHP
PHP有序表查找之二分查找(折半查找)算法示例
Feb 09 #PHP
php在windows环境下获得cpu内存实时使用率(推荐)
Feb 08 #PHP
You might like
PHP has encountered an Access Violation
2007/01/15 PHP
php array的学习笔记
2012/05/16 PHP
使用PHP备份MYSQL数据的多种方法
2014/01/15 PHP
thinkphp控制器调度使用示例
2014/02/24 PHP
PHP性能分析工具XHProf安装使用教程
2015/05/13 PHP
PHP迭代与递归实现无限级分类
2017/08/28 PHP
php实现微信和支付宝支付的示例代码
2020/08/11 PHP
Packer 3.0 JS压缩及混淆工具 下载
2007/05/03 Javascript
jQuery插件开发精品教程(让你的jQuery更上一个台阶)
2015/11/07 Javascript
js点击按钮实现带遮罩层的弹出视频效果
2015/12/19 Javascript
js仿QQ中对联系人向左滑动、滑出删除按钮的操作
2016/04/07 Javascript
微信支付 JS API支付接口详解
2016/07/11 Javascript
javascript实现根据汉字获取简拼
2016/09/25 Javascript
js 动态生成html 触发事件传参字符转义的实例
2017/02/14 Javascript
JS实现json对象数组按对象属性排序操作示例
2018/05/18 Javascript
图解NodeJS实现登录注册功能
2019/09/16 NodeJs
如何在selenium中使用js实现定位
2020/08/18 Javascript
js正则表达式简单校验方法
2021/01/03 Javascript
[04:59]2018DOTA2亚洲邀请赛 4.7 Mineski夺冠时刻
2018/04/09 DOTA
Python下使用Psyco模块优化运行速度
2015/04/05 Python
详解Python网络爬虫功能的基本写法
2016/01/28 Python
Python编写电话薄实现增删改查功能
2016/05/07 Python
Python PyQt4实现QQ抽屉效果
2018/04/20 Python
python的格式化输出(format,%)实例详解
2018/06/01 Python
对python中dict和json的区别详解
2018/12/18 Python
Python利用pandas处理Excel数据的应用详解
2019/06/18 Python
Python求均值,方差,标准差的实例
2019/06/29 Python
Pytorch中index_select() 函数的实现理解
2019/11/19 Python
使用canvas压缩图片上传的方法示例
2020/02/07 HTML / CSS
Ellesse英国官网:意大利高级运动品牌
2019/07/23 全球购物
人力资源部经理的岗位职责
2014/03/04 职场文书
网站客服岗位职责
2014/04/05 职场文书
防灾减灾标语
2014/10/07 职场文书
2015年保卫科工作总结
2015/05/14 职场文书
美丽的大脚观后感
2015/06/03 职场文书
vue中data改变后让视图同步更新的方法
2021/03/29 Vue.js