设为首页 收藏本站
查看: 669|回复: 0

[经验分享] php 的rsa密匙生成!加密解密

[复制链接]
累计签到:29 天
连续签到:1 天
发表于 2015-8-25 09:34:19 | 显示全部楼层 |阅读模式
  最近研究了一下crypt rsa for php!
  RSA方法,简单地说,是生成一组数字n、e和d。用n和e加密明文(明文要求小于n),用n和d解密密文。
  寻找一组n、e、d很容易,但当n足够大时,由n和e求出d很难。这是RSA的安全性所在。
  https不需说了。这里说的是,如何在non-https环境使用JavaScript和PHP实现RSA加密/解密:在浏览器使用JavaScript加密信息,在服务器用PHP解密信息。
一,用JavaScript加密
有关RSA,比较好的JavaScript见http://ohdave.com/rsa/(该页面还有密钥生成程序下载)。用法也简单:
1,设置参数
setMaxDigits(d);
函数的参数d跟n的位数有关。关系是
d=n的十六进制位数/2+3
比如n是十六进制16位(对应二进制125~128位),d就设成19。
2,设置密钥
key=new RSAKeyPair(e,d,n);
参数e、d、n是十六进制表示。加密只需要e和n,d给空串。如:
key=new RSAKeyPair('3d','','a090f4fdaba1c60975fb3b9ea6937a27');
3,加密
ct=encryptedString(key,pt+'\x01');
这个函数把明文pt加密为密文ct(十六进制字符串)。对长信息,则分段加密(但PEAR::Crypt_RSA不认可,下文将解决这个问题)。
'\x01'这个字节,是PEAR::Crypt_RSA要求的结尾符。保证PEAR::Crypt_RSA可以成功解密的一组明文长度(字节)为:
n的十六进制位数/2-3
对2的密钥,一次可以加密13个字节(14个也可能成功,看密钥和明文的情况)。
二,用PHP解密
PEAR::Crypt_RSA的安装很简单,这里不说了。
1,打开数学库
require_once('Crypt/RSA.php');//一般是这个路径
$math_obj = &Crypt_RSA_MathLoader::loadWrapper();
PHP 的数学库有GMP、BigInt、BCMath。如果不给loadWrapper指定参数,他会按照这个顺序选择已经加载的数学库(分别对应 Crypt_RSA_Math_GMP类、Crypt_RSA_Math_BigInt类和Crypt_RSA_Math_BCMath类)。 BCMath是php的默认配置,但比起GMP,实在是慢多了。不了解BigInt,不好说。
2,载入密钥
$dd = $math_obj->int2bin('0x'.$d);
$nn = $math_obj->int2bin('0x'.$n);
$pk = new Crypt_RSA_Key($nn, $dd, 'private');
$rsa_obj = new Crypt_RSA;
$rsa_obj->setParams(array('dec_key' => $pk));
3,解密
$pt = $rsa_obj->decryptBinary($math_obj->int2bin('0x'.$ct));
PEAR::Crypt_RSA可以使用十六进制密钥,也可以解密十六进制密文。但对Crypt_RSA_Math_BCMath类必须修改一下int2bin的代码,使他能够把十六进制数字转换为内部格式。
当然,如果是十进制密钥/密文,'0x'前缀就不用加了。
对Crypt_RSA_Math_BCMath::int2bin()的改动是在函数的开头加上:


$p=substr($num,0,2);
if($p=='0x'||$p=='0X'){
  $len=strlen($num);
  $result = 0;
  $factor = 1;
  for($i=$len-1;$i>=2;$i--){
  $result=bcadd($result,bcmul(hexdec($num[$i]),$factor));
  $factor=bcmul($factor,16);
  }
  $num=$result;
}  

三,解决JavaScript加密功能浪费问题
JavaScript的encryptedString()函数对长信息分段加密,密文用空格分割各个段落。而Crypt_RSA类的decryptBinary()函数不能适应这一点。为了利用充分JavaScript的加密功能,只能给Crypt_RSA类增加一个函数:


function decryptString($s, $key = null)
{
  $result = ‘’;
  if($key==null)
  $key = $this->_dec_key;
  $exp = $this->_math_obj->bin2int($key->getExponent());
  $modulus = $this->_math_obj->bin2int($key->getModulus());
  $chunk_len = $key->getKeyLength() - 1;
  $block_len = (int) ceil($chunk_len / 8);
  $radix=10;
  if(substr($s,0,2)=='0x'){
  $radix=16;
  $s=substr($s,2);
  }
  $blocks = explode(" ",$s);
  for($i = 0; $i < count($blocks); ++$i){
  $enc_data=$blocks[$i];
  if ($radix == 16)
  $enc_data='0x'.$enc_data;
  $enc_data=$this->_math_obj->int2bin($enc_data);
  $data_len = strlen($enc_data);
  $curr_pos = 0;
  $bit_pos = 0;
  $plain_data = $this->_math_obj->bin2int("\0");
  while ($curr_pos < $data_len){
  $tmp = $this->_math_obj->bin2int(substr($enc_data, $curr_pos, $block_len));
  $tmp = $this->_math_obj->powmod($tmp, $exp, $modulus);
  $plain_data = $this->_math_obj->bitOr($plain_data, $tmp, $bit_pos);
  $bit_pos += $chunk_len;
  $curr_pos += $block_len;
  }
  $result .= $this->_math_obj->int2bin($plain_data);
  }
  if (ord($result{strlen($result) - 1}) == 0)
  $result = substr($result,0, strlen($result) - 1);
  return $result;
}  

  这个函数对密文分段解密。加密时也不必在末尾增加字节('\x01')了。解密调用如下:
$rsa_obj->decryptString('0x'.$ct);//十进制不加0x前缀
四,用PHP生成密钥
PEAR::Crypt_RSA的Crypt_RSA_KeyPair类可以生成密钥。调用步骤如下:


require_once('Crypt/RSA.php');
$math_obj = &Crypt_RSA_MathLoader::loadWrapper();
$key_pair = new Crypt_RSA_KeyPair($key_lenth);
if (!$key_pair->isError()){
  $public_key = $key_pair->getPublicKey();
  $private_key = $key_pair->getPrivateKey();
  $e =$math_obj->hexstr($math_obj->bin2int($public_key->getExponent()));
  $d =$math_obj->hexstr($math_obj->bin2int($private_key->getExponent()));
  $n =$math_obj->hexstr($math_obj->bin2int($public_key->getModulus()));
}  

hexstr()是自己添加的函数,用来把十进制字符串转换为十六进制。对Crypt_RSA_Math_GMP很简单,只需:


function hexstr($num){
  return gmp_strval($num,16);
}  

对Crypt_RSA_Math_BCMath略麻烦些:


function hexstr($num){
  $result = '';
  do{
  $result = sprintf('%02x',intval(bcmod($num,256))).$result;
  $num = bcdiv($num, 256);
  }while(bccomp($num, 0));
  return ltrim($result,'0');
}  

五,用php生成密钥(二)
为了提高加密速度,一般选一个较小的e。比较常用的是3、17、257、65537几个素数。
generate()生成密钥的算法是依次计算p,q,n,e,d。因此做了如下改动,以便可以自己选e值:
原来的:
function Crypt_RSA_KeyPair($key_len, $wrapper_name = 'default', $error_handler = '')
改后增加一个参数e:
function Crypt_RSA_KeyPair($key_len, $e = null, $wrapper_name = 'default', $error_handler = '')
这个函数调用generate()。效应地:
function generate($key_len = null)
也增加一个参数e:
function generate($key_len = null, $e = null)
把CRYPT_RSA-1.0.0的KeyPair.php中属于generate()的245~271行改动顺序,由e确定p和q:


if($e != null&&$this->_math_obj->cmpAbs($e,2)>0)
  $e = $this->_math_obj->nextPrime($this->_math_obj->dec($e));//取个素数
else
{
  while(true)
  {
  $e = $this->_math_obj->getRand($q_len, $this->_random_generator);
  if ($this->_math_obj->cmpAbs($e,2)<=0)
  continue;
  $e = $this->_math_obj->nextPrime($this->_math_obj->dec($e));
  break;
  }
}
do{
  $p = $this->_math_obj->getRand($p_len, $this->_random_generator, true);
  $p = $this->_math_obj->nextPrime($p);
  do{
  do{
  $q = $this->_math_obj->getRand($q_len, $this->_random_generator, true);
  $tmp_len = $this->_math_obj->bitLen($this->_math_obj->mul($p, $q));
  if ($tmp_len < $key_len)
  $q_len++;
  elseif ($tmp_len > $key_len)
  $q_len--;
  } while ($tmp_len != $key_len);
  $q = $this->_math_obj->nextPrime($q);
  $tmp = $this->_math_obj->mul($p, $q);
  } while ($this->_math_obj->bitLen($tmp) != $key_len);
  // $n - is shared modulus
  $n = $this->_math_obj->mul($p, $q);
  // generate public ($e) and private ($d) keys
  $pq = $this->_math_obj->mul($this->_math_obj->dec($p), $this->_math_obj->dec($q));
  if($this->_math_obj->isZero($this->_math_obj->dec($this->_math_obj->gcd($e, $pq))))
  break;
}while(true);  


(网易的服务真体贴啊,连pre标记里面的东西都给改。还改不好)这样,如果要生成e为3的1024位密钥,可以如下调用:
$key_pair = new Crypt_RSA_KeyPair(1024,3);
六,干什么用
  加密比较重要的数据。比如注册时用户输入的密码。
  登录时把密码hmac一下就可以防止重放攻击(replay attack)了。对注册不存在这种攻击,但有密码泄露的危险。上传密码hash那点安全性根本不算什么。这个可以用RSA加密解决。
  不过,对中间人攻击还是没办法。


另外一个

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-103877-1-1.html 上篇帖子: linux下安装eaccelerator加速php执行效率 下篇帖子: CentOS6.5 单独编译安装PHP gd库扩展
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表