上篇文章介绍了对称加密的原理,可是它的最大问题就是加密和解密的密钥是相同的,而且不能保证密钥能安全的送到双方手里,即便安全的送到双方手里,免不了内部会有"卧底"的存在php
既然有对称加密,那么天然会联想到非对称加密。非对称加密的核心在于加密和解密使用的是不一样的密钥,如何作到使用不一样的密钥呢?
好比我有一个只能用钥匙打开的存钱罐,平时你们只能把零钱放到储钱罐中,可是只有我才有取钱的钥匙。放到储钱罐的硬币能够当作加密后的内容,而只有用钥匙才能将"加密"后的硬币取出来。
这样咱们就能够把用来加密的密钥(公钥)给了任何人,咱们只要本身保存好解密的密钥(私钥)就能够安全的保护咱们的数据。
非对称算法有不少:RSA、Elgamal、背包算法、Rabin、D-H、ECC等,下面咱们来简单介绍一下RSA算法。程序员
RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一块儿提出的。1987年首次公布,当时他们三人都在麻省理工学院工做。RSA就是他们三人姓氏开头字母拼在一块儿组成的(啥时候以我名字命名一个呢)。
RSA是目前最有影响力的公钥加密算法,它可以抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。算法
//注意:明文为数字,实际计算过程咱们能够经过ASCII码转换 密文 = (明文 ^ E) % N; //其中的E和N就是咱们的公钥 明文 = (密文 ^ D) % N; //其中的D和N就是咱们的私钥
公钥和私钥不是随便弄几个数字就能够的,是通过严格的数学公式计算出来的。数据库
N = P * Q;
L = (P - 1) * (Q - 1); //图解密码技术中说须要计算乘积以后的最小公倍数,可是通过代码测试并不许确,哪位大侠了解麻烦留言告知一下~
//E须要同时知足下面两个条件 1. 1 < E < L 2. E和L的最大公约数为一(欧几里得算法,这些恶魔啊,E和L必须互质,这样才能保证必定能够计算出私钥D)
//D须要知足下面公式 (E * D) % L = 1; //想要保证结果为1,E和L必须互质!!!
上面就是整个计算过程,为了保证数据的安全现实中,P和Q会选用特别大的数(1024比特或者更大)安全
上面已经提到过加密和解密的方法,咱们用具体的数字实践一下,加深理解吧。函数
假设:P = 七、Q = 11(均为质数) 那么:N = P * Q = 7 * 11 = 77
L = (P - 1) * (Q - 1) = 6 * 10 = 60
1 < E < 60 E和L的最大公约数为一,咱们假设E=23
(23 * D) % 60 = 1; D = 47;
那么我就获得了公钥(E=23,N=77),私钥(D=47,N=77)学习
咱们假设须要加密数字:12
公式:密文 = (明文 ^ E) % N;
12 ^ 23 % 77 = 6624737266949237011120128 % 77 = 45;
这个45就是咱们加密后的密文测试
解密
公式:明文 = (密文 ^ D) % N;
45 ^ 47 % 77 = 502328880013965819626664594350710696732674427522624682751484215259552001953125 % 77 = 12;
得出原文:12加密
下面是我用PHP实现的加密&解密示例,供你们参考(由于指数运算的结果集会很大,咱们必须使用PHP中提供的BC Math系列函数计算)spa
/** * 冒牌RSA算法 * @author zhjx922 */ /** * 判断数字是否为质数 * @param $num * @return bool */ function isPrimeNumber($num) { $k = 0;//定义次数变量 for ($i = 1; $i <= $num; $i++) { if (bcmod($num, $i) == 0) { $k++;//若是取模等于0,次数k自加 } } if ($k == 2) { return true; } return false; } //求最小公倍数 function minMultiple($a, $b) { if($b==0) //必定要考虑除数不能为零 { return $b; } else { $m = bccomp($a, $b) == 1 ? $a : $b; $n = bccomp($b, $a) == 1 ? $b : $a; for($i=2; ; $i++) { $mul = bcmul($m, $i); if(bcmod($mul, $n) == 0) { return $mul; } } } return bcmul($a, $b); } //求最大公约数 function maxDivisor($a,$b) { $n = bccomp($a, $b) == 1 ? $b : $a; for($i = $n; $i>1; $i--) { if(bcmod($a, $i) == 0 && bcmod($b, $i) == 0) { return $i; //此处若是用echo $i;则输出结果为432;故应区分echo、return的区别 } } return 1; } do{ //随机一个质数P $p = mt_rand(101, 197); } while(!isPrimeNumber($p)); do{ //随机一个质数Q $q = mt_rand(101, 197); } while(!isPrimeNumber($q)); $n = bcmul($p, $q); //$l = minMultiple($p - 1, $q - 1); //经测试不可用 $l = bcmul($p - 1, $q - 1); do { $e = mt_rand(2, $l - 1); }while(maxDivisor($e, $l) != 1); $d = 1; while(bcmod(bcmul($e,++$d), $l) != 1) { } echo 'p:' . $p . PHP_EOL; echo 'q:' . $q . PHP_EOL; echo 'n:' . $n . PHP_EOL; echo 'l:' . $l . PHP_EOL; echo 'e:' . $e . PHP_EOL; echo 'd:' . $d . PHP_EOL; echo "公钥:e={$e},n={$n}" . PHP_EOL; echo "私钥:d={$d},n={$n}" . PHP_EOL; //加密 function encode($e, $n, $string) { $enString = ''; $len = strlen($string); for($i = 0; $i < $len; $i++) { $pow = bcpow(ord($string{$i}), $e); $mod = bcmod($pow, $n); $enString .= pack('L', $mod); } return $enString; } //解密 function decode($d, $n, $string) { $deString = ''; $string = unpack('L*', $string); $len = count($string); for($i = 1; $i <= $len; $i++) { $pow = bcpow($string[$i], $d); $mod = bcmod($pow, $n); $deString .= chr($mod); } return $deString; } $startTime = microtime(true); $string = '欢迎关注"伪装是个程序员"公众号'; echo "原文:" . $string . PHP_EOL; $encodeString = encode($e, $n, $string); echo "密文:" . $encodeString . PHP_EOL; $decodeString = decode($d, $n, $encodeString); echo "解密后:" . $decodeString . PHP_EOL; $endTime = microtime(true); echo "Total:" . ($endTime - $startTime) . 's.' . PHP_EOL;
没有什么加密方式能一直保持绝对的安全,尤为经常使用的MD5,若是你的数据库中密码仍是使用MD5的哈希结果不要笑话人家直接用明文存密码的人,五十步笑百步而已。。。
最近谷歌宣布破解了SHA-1,随着计算能力的提升,SHA-256,RSA等等也是早晚的事儿。。
欢迎关注个人公众号,一块儿交流学习~