0x00 前言
我们这学期的课程《信息安全与保密》要求期末作业实现一个密码算法及对应的加解密系统,其中做RSA的要求实现加解密、数字签名。考虑到我因为太菜,当初遇到了不少问题,莆田搜索RSA算法实现想参考一下的时候找不到PHP版本的,所以我完成作业后打算自己整一篇以供有需要的后来者参考
考虑到我们期末作业主要任务是“实现RSA加解密、数字签名”,故没有采用大整数运算,受PHP的数据精度限制,素数范围在2的32到48次方(4.29E9~2.81E14),标题中的“简化版”即此意
由于在学校的时候事情比较多,所以一直拖到了放假才开始写,时间有点久了,有些细节记得不大清楚,而且受限于自己的水平,应该会有不少错漏;当时时间比较紧迫,函数封装等也不甚合理
文中内容主要摘自段云所、卫仕民、唐礼勇、陈钟所编《信息安全概论》(高等教育出版社,2003.9)及我上课记的笔记(特别注明之处除外),我的笔记可能也会有错漏之处,烦请海涵并指正 */建立一个RSA密码体制的过程如下: 选择两个大素数p和q
计算乘积n=pq和fai(n)=(p-1)(q-1)
选择大于1小于fai(n)的随机整数e,使得gcd(e, fai(n))=1
计算d使得de与1mod fai(n)同余
对每一个密钥k=(n,p,q,d,e),定义加密变换为Ek(x)=x^e mod n,解密变换为Dk(x)=y^d mod n,这里x,y属于整数
以{e,n}为公开密钥,{p,q,d}为私有密钥
//其中的fai(n)即欧拉函数,意为“和n互素的数的数量”
0x01 Miller-Rabin算法(素性检测)
密钥中的p和q须为素数,而素数选取需要用到素性检测,Miller-Rabin算法可以实现素性检测。由William Stallings所著的《密码编码学与网络安全——原理与实践(第七版)》可知Miller-Rabin算法如下:过程TEST输入整数n,若n不是素数,则返回“合数”,若n可能是素数,也可能不是素数时,返回“不确定”
TEST(n) 找出整数k, q,其中k>0, q是奇数,使(n-1=(2^k)*q)
随机选取整数a, 1
if a^q mod n=1, then 返回“不确定”
for j=0 to k-1 do
if a^((2^j)*q) mod n=n-1 then 返回“不确定”
返回“合数”
而对合数n=13*17=221应用上述测试,若选取a=5,则算法返回“合数”;假设我们选取a=21,则21^55mod221=200, (21^55)^2mod221=220,则测试算法返回“不确定”,意即221可能是素数
故我们需要重复使用Miller-Rabin算法:对随机选取的a重复调用TEST(n),如果某时刻TEST返回“合数”,则n一定不是素数;若TEST连续t次返回“不确定”,当t足够大时,我们可以相信n是素数
实现如下:function millerRabinAlgorithmV2($n) //参照William Stallings所著的《密码编码学与网络安全——原理与实践(第七版)》实现的Miller-Rabin算法,素性检测
{
$k = 1;
$q = ($n - 1) / 2;
while (pow(2, $k) < $n - 1) { //1.找 n-1 = 2^k *q 中的k和q
$q = ($n - 1) / 2;
while (pow(2, $k) * $q < $n - 1) {
if (pow(2, $k) * $q == $n - 1) { //若满足条件,说明找到了对应的k和q,终止循环,否则q减小,继续寻找对应的q
break;
}
$q -= 2;
}
if (pow(2, $k) * $q == $n - 1) { //若满足条件,说明上面的内部循环找到了对应的k和q,则终止外部循环,否则说明没有找到对应的q,故k增大,继续寻找满足条件的k和q
break;
}
$k++;
}
$flags = []; //用数组存储重复调用Miller-Rabin算法产生的结果
while (true) {
$flags = [];
for ($times = 0; $times < 10; $times++) { //设t为10,重复调用10次
$flag = false; //6. 若下面的条件都不满足,$flag没有置true,则不是素数
$a = mt_rand(2, $n - 2); //2. 随机选取整数a, 1