最近开发的项目中用到RSA签名算法,给数据加密解密。php端是如何实现RSA加密解密的呢?
RSA的概念 RSA是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名。RSA以它的三个发明者Ron Rivest, Adi Shamir, Leonard Adleman的名字首字母命名,这个算法经受住了多年深入的密码分析,虽然密码分析者既不能证明也不能否定RSA的安全性,但这恰恰说明该算法有一定的可信性,目前它已经成为最流行的公开密钥算法。
RSA的安全基于大数分解的难度。其公钥和私钥是一对大素数(100到200位十进制数或更大)的函数。从一个公钥和密文恢复出明文的难度,等价于分解两个大素数之积(这是公认的数学难题)。
RSA的公钥、私钥的组成,以及加密、解密的公式可见于下表:
RSA为何难于破解?有什么劣势? 在RSA密码应用中,公钥KU是被公开的,即e和n的数值可以被第三方窃听者得到。破解RSA密码的问题就是从已知的e和n的数值(n等于pq),想法求出d的数值,这样就可以得到私钥来破解密文。从上文中的公式:d ≡e-1 (mod((p-1)(q-1)))或de≡1 (mod((p-1)(q-1))) 我们可以看出。密码破解的实质问题是:从Pq的数值,去求出(p-1)和(q-1)。换句话说,只要求出p和q的值,我们就能求出d的值而得到私钥。 当p和q是一个大素数的时候,从它们的积pq去分解因子p和q,这是一个公认的数学难题。比如当pq大到1024位时,迄今为止还没有人能够利用任何计算工具去完成分解因子的任务。因此,RSA从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。
然而,虽然RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价。即RSA的重大缺陷是无法从理论上把握它的保密性能如何。
此外,RSA的缺点还有:A)产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。B)分组长度太大,为保证安全性,n 至少也要 600 bits
以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。因此,使用RSA只能加密少量数据,大量的数据加密还要靠对称密码算法。
简单案例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <?php $private_key = "-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQCpS7mxdU6svbDcs10qbq9f9t5D4yfqC1jLmZD3GDD4D/8TbNkf vcYDvde6nyPRSxrnzl9YmZhJKlP2iCIwdwwmW6yulXZyvPurfN/1AJt4JYDxnN/q u1bSG5DZMribLsR2dlfA5J0D6lQ7g40eSgp4D6UWy8ezLy6UWFQCrnUHEQIDAQAB AoGAQCQeoKtvOWdNIPEb9T2mWFdx8oqXzsapx8nQ8K1LsFBvNe7hfHMsGLLOjzhI G7223eiEm07mMaJF2XvOaEpSYX/qQ1LZRSdBrzCec1lcDbB95dcRg9NmgBuCpUxE 3SGYm3VB8rurfsrRUUYoIbjWz8qyuIGdMbaNkHG/CpnUYpkCQQDfWYDYtQ3DxCt+ JBoLfuCykk8+nIV12CIYb023naoR2s/aQQRk9BkGCkDrdOAgZAN3BGOHYseKAfTP nARDzfiDAkEAwgtYfgCDTOfW5/kJK1lZO21CdCCZnePwGYmWDLPzNiJIn8k0U6Ig 9GmxG+0GKzY71XO8W3Nh18ilZbX9dYel2wJASQ+AJGNlc0pyZ7rrgiMo4YEWxwZw adIfpRqTs6KxhVGseFqYU2W94cns3pjG0BGnSIF5BUp8t1pYeKkyg/OWfQJBAK1w mq41IycQaoR5kfqPKDT32dgWc3gvDqKk2duM1KzkQ+meXAkM90u/VLDTURo6pYyK oCdVoHTRQRUCcAQnNNUCQQCO/zDRaY+5ssjPqj77eJqWfAhtbSDRRw+NurmUSas1 FT1cD5nil+uT48bIRoC5nk/XWfvAvMg/Yw5bslGUNx7f -----END RSA PRIVATE KEY-----"; $public_key = "-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpS7mxdU6svbDcs10qbq9f9t5D 4yfqC1jLmZD3GDD4D/8TbNkfvcYDvde6nyPRSxrnzl9YmZhJKlP2iCIwdwwmW6yu lXZyvPurfN/1AJt4JYDxnN/qu1bSG5DZMribLsR2dlfA5J0D6lQ7g40eSgp4D6UW y8ezLy6UWFQCrnUHEQIDAQAB -----END PUBLIC KEY-----"; //获取所有支持算法,cipher 就是密码,算法计算的意思 $methods=openssl_get_cipher_methods(); // var_dump($methods); $data="原始数据为: 用私钥加密origin data1"; $method="AES-128-CBC"; //通过私钥加密,生成$crypted; openssl_private_encrypt($data, $crypted, $private_key); // 由于php 进行openssl_public_encrypt 加密后返回的是二进制数据,需要对其返回的加密后的数据进行二进制16进制编码base64_encode才可以显示,$crypted为加密后的串 $crypted=base64_encode($crypted); echo "私钥加密后的结果为:".$crypted."\n"; //相应的:加密后生产的16进制加密字符串需要进行base64_decode进行解密后在进行openssl_private_decrypt $crypted=base64_decode($crypted); openssl_public_decrypt($crypted, $decrypted , $public_key); echo "用公钥解密的结果为".($decrypted)."\n"; echo"===================我是分割线==============\n"; $data="用公钥加密origin data2\n"; $method="AES-128-CBC"; //通过公钥加密,生成$crypted; openssl_public_encrypt($data, $crypted, $public_key); // 由于php 进行openssl_public_encrypt 加密后返回的是二进制数据,需要对其返回的加密后的数据进行二进制16进制编码base64_encode才可以显示,$crypted为加密后的串 $crypted=base64_encode($crypted); echo "公钥加密后的结果为:".$crypted."\n"; //相应的:加密后生产的16进制加密字符串需要进行base64_decode进行解密后在进行openssl_private_decrypt $crypted=base64_decode($crypted); openssl_private_decrypt($crypted, $decrypted , $private_key); echo "用私钥解密的结果为".($decrypted)."\n";
通用类实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 <?php namespace ApiPub; class Algorithm { const RSA_ENCRYPT_BLOCK_SIZE = 117; const RSA_DECRYPT_BLOCK_SIZE = 128; /** * 利用约定数据和私钥生成数字签名 * @param $data 待签数据 * @return String 返回签名 */ public static function sign($data='') { if (empty($data)) { return False; } $private_key = file_get_contents(dirname(__FILE__).'/rsa_private_key.pem'); if (empty($private_key)) { echo "私钥异常!"; return False; } $pkeyid = openssl_get_privatekey($private_key); if (empty($pkeyid)) { echo "私钥资源标识符错误!"; return False; } $verify = openssl_sign($data, $signature, $pkeyid, OPENSSL_ALGO_MD5); openssl_free_key($pkeyid); return $signature; } /** * 利用公钥和数字签名以及约定数据验证合法性 * @param $data 待验证数据 * @param $signature 数字签名 * @return -1:error验证错误 1:success验证成功 0:fail验证失败 */ public static function isValid($data='', $signature='') { if (empty($data) || empty($signature)) { return False; } $public_key = file_get_contents(dirname(__FILE__).'/rsa_public_key.pem'); if (empty($public_key)) { echo "公钥异常"; return False; } $pkeyid = openssl_get_publickey($public_key); if (empty($pkeyid)) { echo "公钥资源标识符错误e!"; return False; } $ret = openssl_verify($data, $signature, $pkeyid, OPENSSL_ALGO_MD5); switch ($ret) { case -1: echo "错误"; break; default: echo $ret==1 ? "success" : "fail";//0:fail break; } return $ret; } /** * RSA数据加密解密 私钥-加密解密 * @param type $data * @param type $type encode加密 decode解密 $public_key 密钥 * @Description: 字符过长的话需要分段加密/解密 * @return 加密或解密后的字符 */ public static function RAS_Do($dataStr = '测试字符',$type='encode',$public_key){ if (empty($dataStr)) { return 'data参数不能为空'; } if ($type=='decode') { //私钥解密 $data=base64_decode($dataStr); $result = ''; $data = str_split($data, self::RSA_DECRYPT_BLOCK_SIZE); foreach ($data as $block) { openssl_private_decrypt($block, $decrypted, $public_key,OPENSSL_PKCS1_PADDING); $result .= $decrypted; } return $result; }else{ //私钥加密 $result = ''; $data = str_split($dataStr, self::RSA_ENCRYPT_BLOCK_SIZE); foreach ($data as $block) { openssl_private_encrypt($block, $crypted, $public_key,OPENSSL_PKCS1_PADDING); $result .= $crypted; } $result=base64_encode($result); return $result; } } }
<
TP5提升性能的几个小技巧
Oracle数据库创建自增字段
>