php实现RSA加密类实例


Posted in PHP onMarch 26, 2015

本文实例讲述了php实现RSA加密类。分享给大家供大家参考。具体分析如下:

通过openssl实现的签名、验签、非对称加解密,需要配合x.509证书(如crt和pem)文件使用。
由于各种原因,该类并不十分完善,欢迎各种测试!

<?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: linvo
 * @version: 1.0.0
 * @date: 2013/1/23
 */ 
class RSA{ 
 private $pubKey = null; 
 private $priKey = null; 
 /**
  * 自定义错误处理
  */ 
 private function _error($msg){ 
  die('RSA Error:' . $msg); //TODO 
 } 
 /**
  * 构造函数
  *
  * @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); 
  } 
 } 
 /**
  * 生成签名
  *
  * @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; 
 } 
 // 私有方法 
 /**
  * 检测填充类型
  * 加密只支持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; 
 } 
}

测试demo:

<?php 
header('Content-Type:text/html;Charset=utf-8;'); 
include "rsa.php"; 
echo '<pre>'; 
$a = isset($_GET['a']) ? $_GET['a'] : '测试123'; 
////////////////////////////////////// 
$pubfile = 'E:\ssl\cert\pwd.crt'; 
$prifile = 'E:\ssl\cert\pwd.pem'; 
$m = new RSA($pubfile, $prifile); 
$x = $m->sign($a); 
$y = $m->verify($a, $x); 
var_dump($x, $y); 
$x = $m->encrypt($a); 
$y = $m->decrypt($x); 
var_dump($x, $y);

希望本文所述对大家的php程序设计有所帮助。

PHP 相关文章推荐
php的一些小问题
Jul 03 PHP
php文件读取方法实例分析
Jun 20 PHP
Yii多表联合查询操作详解
Jun 02 PHP
Redis使用Eval多个键值自增的操作实例
Nov 04 PHP
PHP数组的定义、初始化和数组元素的显示实现代码
Nov 05 PHP
Laravel接收前端ajax传来的数据的实例代码
Jul 20 PHP
PHP批量删除jQuery操作
Jul 23 PHP
PHP实现的迪科斯彻(Dijkstra)最短路径算法实例
Sep 16 PHP
浅谈PHP实现大流量下抢购方案
Dec 15 PHP
php nginx 实时输出的简单实现方法
Jan 21 PHP
laravel excel 上传文件保存到本地服务器功能
Nov 14 PHP
PHP实现文件上传操作和封装
Mar 04 PHP
PHP中实现crontab代码分享
Mar 26 #PHP
PHP利用hash冲突漏洞进行DDoS攻击的方法分析
Mar 26 #PHP
ThinkPHP、ZF2、Yaf、Laravel框架路由大比拼
Mar 25 #PHP
CentOS 安装 PHP5.5+Redis+XDebug+Nginx+MySQL全纪录
Mar 25 #PHP
MacOS 安装 PHP的图片裁剪扩展Tclip
Mar 25 #PHP
php编写的一个E-mail验证类
Mar 25 #PHP
php取得字符串首字母的方法
Mar 25 #PHP
You might like
DOTA2 探索永无止境 玩家自创强悍插眼攻略
2020/04/20 DOTA
php中计算未知长度的字符串哪个字符出现的次数最多的代码
2012/08/14 PHP
PHP中Socket连接及读写数据超时问题分析
2016/07/19 PHP
PHP常量define和const的区别详解
2019/05/18 PHP
Alliance vs Liquid BO3 第二场2.13
2021/03/10 DOTA
jQuery+HTML5美女瀑布流布局实现方法
2015/09/21 Javascript
JavaScript性能优化之小知识总结
2015/11/20 Javascript
JavaScript实现斗地主游戏的思路
2016/02/29 Javascript
简述JavaScript提交表单的方式 (Using JavaScript Submit Form)
2016/03/18 Javascript
jquery mobile界面数据刷新的实现方法
2016/05/28 Javascript
window.open打开窗口被拦截的快速解决方法
2016/08/04 Javascript
jQuery替换节点用法示例(使用replaceWith方法)
2016/09/08 Javascript
javascript的几种写法总结
2016/09/30 Javascript
浅谈jquery页面初始化的4种方式
2016/11/27 Javascript
解析NodeJs的调试方法
2016/12/11 NodeJs
JS 验证密码 不能为空,必须含有数字、字母、特殊字符,长度在8-12位
2017/06/21 Javascript
JS+CSS实现网页加载中的动画效果
2017/10/27 Javascript
纯js实现隔行变色效果
2017/11/29 Javascript
详解小程序循环require之坑
2019/03/08 Javascript
python使用7z解压apk包的方法
2015/04/18 Python
numpy中矩阵合并的实例
2018/06/15 Python
django主动抛出403异常的方法详解
2019/01/04 Python
Django-xadmin+rule对象级权限的实现方式
2020/03/30 Python
python3代码输出嵌套式对象实例详解
2020/12/03 Python
Python 打印自己设计的字体的实例讲解
2021/01/04 Python
大码女装:Ulla Popken
2019/08/06 全球购物
Java方面的关于数组和继承的笔面试题
2015/09/18 面试题
音乐学院硕士生的自我评价分享
2013/11/01 职场文书
汽车专业毕业生推荐信
2013/11/12 职场文书
优秀求职自荐信怎样写
2013/12/18 职场文书
《湘夫人》教学反思
2014/02/21 职场文书
投资意向书范本
2014/04/01 职场文书
房屋租赁协议书
2014/04/10 职场文书
会议室标语
2014/06/21 职场文书
个人自荐书范文
2015/03/09 职场文书
我的长征观后感
2015/06/09 职场文书