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 pcntl_fork和pcntl_fork 的用法
Apr 13 PHP
UCenter Home二次开发指南
May 28 PHP
php从右向左/从左向右截取字符串的实现方法
Nov 28 PHP
php函数array_merge用法一例(合并同类数组)
Feb 03 PHP
深入php self与$this的详解
Jun 08 PHP
PHP 解决session死锁的方法
Jun 20 PHP
PHP生成压缩文件实例
Feb 07 PHP
适用于初学者的简易PHP文件上传类
Oct 29 PHP
Yii框架实现邮箱激活的方法【数字签名】
Oct 18 PHP
ThinkPHP框架分布式数据库连接方法详解
Mar 14 PHP
PHP 文件锁与进程锁的使用示例
Aug 07 PHP
Laravel-admin之修改操作日志的方法
Sep 30 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
php将会员数据导入到ucenter的代码
2010/07/18 PHP
php压缩多个CSS为一个css的代码并缓存
2011/04/21 PHP
PHP数组遍历知识汇总(包含遍历方法、数组指针操作函数、数组遍历测速)
2014/07/05 PHP
PHP7.1方括号数组符号多值复制及指定键值赋值用法分析
2016/09/26 PHP
Draggable Elements 元素拖拽功能实现代码
2011/03/30 Javascript
20款效果非常棒的 jQuery 插件小结分享
2011/11/18 Javascript
按钮接受回车事件的三种实现方法
2014/06/06 Javascript
浅析基于WEB前端页面的页面内容搜索的实现思路
2014/06/10 Javascript
js的image onload事件使用遇到的问题
2014/07/15 Javascript
js构造函数、索引数组和属性的实现方式和使用
2014/11/16 Javascript
javascript制作坦克大战全纪录(2)
2014/11/27 Javascript
Jquery跨浏览器文本复制插件Zero Clipboard的使用方法
2016/02/28 Javascript
拥Bootstrap入怀——导航栏篇
2016/05/30 Javascript
js删除局部变量的实现方法
2016/06/25 Javascript
jquery请求servlet实现ajax异步请求的示例
2017/06/03 jQuery
微信小程序的分类页面制作
2017/06/27 Javascript
jQuery实现的简单无刷新评论功能示例
2017/11/08 jQuery
详解vuex中mapState,mapGetters,mapMutations,mapActions的作用
2018/04/13 Javascript
Vue2.0 实现移动端图片上传功能
2018/05/30 Javascript
vue表单自定义校验规则介绍
2018/08/28 Javascript
Jquery实现获取子元素的方法分析
2019/08/24 jQuery
小程序使用watch监听数据变化的方法详解
2019/09/20 Javascript
JavaScript eval()函数定义及使用方法详解
2020/07/07 Javascript
token 机制和实现方式
2020/12/15 Javascript
Vue项目中使用mock.js的完整步骤
2021/01/12 Vue.js
python进阶教程之动态类型详解
2014/08/30 Python
如何安装2019Pycharm最新版本(详细教程)
2019/09/26 Python
wxPython之wx.DC绘制形状
2019/11/19 Python
python 爬虫基本使用——统计杭电oj题目正确率并排序
2020/10/26 Python
美国名牌手表折扣网站:Jomashop
2020/05/22 全球购物
如何开启linux的ssh服务
2015/02/14 面试题
《猴子种树》教学反思
2014/02/14 职场文书
单身证明范本
2015/06/15 职场文书
新教师教学工作总结
2015/08/12 职场文书
详解OpenCV获取高动态范围(HDR)成像
2022/04/29 Python
MySql统计函数COUNT的具体使用详解
2022/08/14 MySQL