永强接着教你加解密:非对称篇(四)

2019-11-12 23:08:18 浏览数 (1)

大家好,我是老李,下面是我想说的话:

  • 首先这是一篇本应该发布在春节后的三个月前文章
  • 文章封面图是永强自己选的

大家好,我是许久未露面投稿的永强,下面是我想说的话:

  • 虽然过年我没有收到压岁钱
  • 但是我过年也没有收到任何年终奖

别人背地里都这么跟我说:永强啊,你的文章都是老李那里难产时候上去顶包凑数量的,阅读量不超过50!

MD,净说实话

我最近去搞工业机器人这件事情是一件人尽皆知(包括老李在内的好几个人都知道)的事情,没有了老王公司的氛围,我的生活和学习的乐趣都快没了。一天天净对着不长眼的机器人瞎折腾,那玩意程序一弄不好就跟没头苍蝇似的做布朗运动。

布朗运动...???...怎么听着这么耳熟?

好了,言归正传,我准备开始充数了。

其实过年期间我就给上高中、初中的少年一代用加解密技术装了一波儿大逼,一点儿都不出乎预料:

根本没人鸟我

让我感到惊讶的是,他们这些人一天天除了斗地主就是王者荣耀,一天天抱着个手机跟特么屎壳郎滚粪球子似的,我上去问个质数、合数竟然都特么忘记了,让我感到十分欣慰。

没想到除了西方国家的财富外,属于全人类的知识也会两极分化

其实今天的话题和质数真的有关系,如果你要也不知道质数是什么了,趁着过年还在老家,赶紧去找你小学数学老师去问问,然后你就可以精通质数了。

非对称加解密的典型代表就是RSA,而且RSA用的最广泛最多,所以,实际上这篇就是来普及RSA的。我本来想起一个类似于《论RSA的音容笑貌和尺寸长短》这样的标题,不过老李不让,他说这样会破坏标题的队列感和仪式感,同时也会让本篇文章产生孤独感,破坏风水。

实际上RSA算法都是公开的,算式都是公开了,任何一个人都可以从互联网上查阅到这个公开算法过程是什么:

代码语言:javascript复制
密文 = 明文^E mod N明文 = 密文^D mod N

以上就是RSA加密和解密的过程,就是这么简单粗暴。只要上过学,就知道上面算式是什么意思。

在下面的课程开始前,请事先了解一下如下几个名词的含义:

  • 质数
  • 最大公约数
  • 最小公倍数
  • mod,即余数

好了,我开始准备数学实战演练RSA算法的数学计算过程了:

  • 准备两个随机的质数p和q,其中p=13,q=17,然后令N=p*q,即N=221
  • 令L为p-1(12)和q-1(16)的最小公倍数,即L=48
  • 有数字E,E需要满足如下条件:1 < E < L(L=48)、E和L最大公约数为1,我凭信仰选了一个5
  • 有数字D,D需要满足如下条件:1 < D < L、E * D mod L = 1,所以,这个很简单,可以求出D=29(怎么求的自己去算)
  • 所以N=221,L=48,E=5,D=29

所以,请记住:

{E,N}即{5,221}就是公钥,{D,N}即{29,221}就是私钥

那么,我们将这两个数字代入到RSA加密和解密的工程中去尝试一把。假如明文是123,那么代入到加密公式中:

123^5 mod 221 = 106

所以106就是密文。将密文代入到解密公式中,如下:

106^29 mod 221 = 123

解出密文为123

完美!完美!简直完美!比老王的meshbox还完美

TIPS:如何计算106的29次方。由于结果太大,很多计算器一般都是直接GG。所以,可以化解一下106的29次方:

106^29 = 106^(6 6 6 6 5) = (106^6)*(106^6)*(106^6)*(106^6)*(106^5)

取余的时候:

( (106^6) mod 221 ) * ( (106^6) mod 221 ) * ( (106^6) mod 221 ) * ( (106^6) mod 221 ) * ( (106^5) mod 221 ) mod 221

以上就是RSA数学理论推演过程,上面这些数学因素是如何在程序里得到体现的呢?

代码语言:javascript复制
<?php// 产生一个一对新的RSA公私钥$res = openssl_pkey_new();// 该函数获取一下私钥openssl_pkey_export( $res, $private_key, "123456" );// 该函数获取公钥$public_key = openssl_pkey_get_details( $res );echo PHP_EOL;echo $private_key;echo PHP_EOL.PHP_EOL;echo $public_key['key'].PHP_EOL.PHP_EOL;// 打印相关信息$n = bin2hex( $public_key['rsa']['n'] );$n = gmp_init( $n, 16 );  $n = gmp_strval( $n, 10 );echo 'n:'.$n.PHP_EOL.PHP_EOL;$e = bin2hex( $public_key['rsa']['e'] );$e = gmp_init( $e, 16 );  $e = gmp_strval( $e, 10 );echo 'e:'.$e.PHP_EOL.PHP_EOL;$d = bin2hex( $public_key['rsa']['d'] );$d = gmp_init( $d, 16 );  $d = gmp_strval( $d, 10 );echo 'd:'.$d.PHP_EOL.PHP_EOL;$p = bin2hex( $public_key['rsa']['p'] );$p = gmp_init( $p, 16 );  $p = gmp_strval( $p, 10 );echo 'p:'.$p.PHP_EOL.PHP_EOL;$q = bin2hex( $public_key['rsa']['q'] );$q = gmp_init( $q, 16 );  $q = gmp_strval( $q, 10 );echo 'q:'.$q.PHP_EOL.PHP_EOL;

上面代码保存运行一下,至于你们那里能不能运行,反正我这里能运行:

代码解析:我们知道,一般使用RSA的时候都需要什么私钥pem文件之类的,实际上就是一坨base64文本,实际上通过PHP的openssl函数可以直接生成一对RSA公私钥,也就是代码中openssl_pkey_new函数,然后我们可以直接将私钥和公钥内容可以直接打印出来。那么,我们在数学理论中那一大坨p、q、e、d、n这些数值是如何体现的呢?这些全都保存在上述演示代码的public_key数组中去了,但是,由于p、q等这些数值可能会非常非常巨大,所以,必须要使用gmp进行转换后才能显示。

私钥pem文件中的那坨base64就是按照一定的规则和方式将p、q、e等这些数值进行编码排序后最后进行一次base64编码,所以,你知道了私钥pem文件中的内容就可以根据相反的规则解析出相应的p、q、e等数字,然后开始进行RSA的解密了~

具体使用RSA进行加解密的demo代码,这一系列文章写到这个份上,演示demo代码我就不用写了吧。文章写到这里(加解密系列的第四篇)这种代码你自己查查php手册就是可以搞定了的,github上也有大量的库可以直接薅下来用。

0 人点赞