双钥密钥密码算法RSA解析与短密钥实现
来源:互联网 发布:当今网络世界强国 编辑:程序博客网 时间:2024/05/22 09:40
单钥密钥算法,由于其加密的速度相对来说比较快,所以常用来对文本文件加密(如TEA、DES等),而双钥密钥算法(如RSA)由于其加密解密的密钥不同并且采用暴力破解的方式也比较低效(基本不可能被破解),低效的原因通常不是符合加解密的密钥对的空间有多大,而是正确的一对密钥其密钥空间难以确定。但是其加密速度也比较低,所以常用来加密单钥密钥算法的加密秘钥,这样即所谓混合加密。混合密码系统的基本结构如下图所述(解密过程与加密过程相反,并且解密用的公钥密码是接受者的私钥,加密类似于转码组包,解密类似于拆包转码):
对于混合加密系统的左半部分,我们以RSA为例来进行研究。
1、非对称密码与RSA密码算法简介:
RSA是三位开发者Ron Rivest、Adi Shamir和Leonard Adleman的姓氏首字母所组成的。RSA从框架结构理解上来说算法比较简单,为什么简单?因为它的加密解密只需要两个公式(其实是一个公式):
Encryption:
Ciphertext = Plaintext^E mod N(明文Plaintext的E次方对N取余的值为密文)
Decryption:
Plaintext = Ciphertext^D mod N(密文Ciphertext的D次方对N取余的值为明文)
其中{E,N}是加密秘钥,也称为公钥(因为该密钥是不需要可以保密的)。而{D,N}是解密密钥,也称为私钥,是需要保密的。A产生一对密钥K11、K12(公钥和私钥),将公钥K11发送给需要进行通信的发送一方S,私钥K12自己保管。即使公钥被窃听者E获取到,由于没有私钥,窃听者也不能的值通信信息。根据描述,我们可以很清楚地知道,一对密钥只能进行单工通信,不是因为信道做不到双工通信,而是信道达不到安全的双工通信。那么就需要另一方S也产生一对密钥K21、K22,将公钥K21发送A,私钥K22自己保留。则A要S通信只能用K21加密信息给S发送,而该信息只有S能用K22解密。S和A通信也只能用K11加密后给A发送信息,而该信息只能由A用私钥K12解密读取。
看起来比较混乱,用下图来表示:
2、RSA密码算法需要的数论知识:
而加密公式与解密公式中,并不是所有的{E,N}、{D,N}组合都能够组成一对密钥。E、D、N是具有一定的关系的,该组合由数学关系推导出来。关于如何求解一组密钥,后面在慢慢分析。我们先来回顾和学习,与RSA加密解密密钥组合生成相关的一些数学知识:
(1)、质数(素数)的相关概念:
①对于整数Number,只能分解为Number = Number * 1,而不能分解为其它整数相乘,则Number为质数(素数);
②两个质数的乘积是这两个质数的最小公倍数;
③**互质的概念:**A与B互质,并不是说A、B均为质数,而是指A和B的最大公约数是1;如:8和q最大公约数为1,但是8和9都是合数。
④任何大于1的整数Number,能够被分解为如下形式:
Number = P1 * P2 * P3 * … * Pi,(P1 、P2、P3、… 、Pi均为质数)
(2)、mod运算(取模运算):
①取模(mod)与取余(rem):A mod B(A对B取模)、A rem B(A对B取余)
它们返回结果都是余数,但rem和mod唯一的区别在于:
当A、B同号时,两个运算结果是等同的;
当A、B异号时,rem结果的符号和A的符号一样,而mod和B的符号一样。
区分详细可参考:取模运算(mod)和求余(rem)运算不能被混为一谈
②((a mod n) × (b mod n))mod n ≡ (a×b) mod n
如果(a×b)=(a×c) mod n,且a与n互质,则b = c mod n
(3)、费马定理:
如果p是质数,a与p互质,则由a^(p-1) mod p = 1
(4)、欧拉定理:
欧拉函数ψ(n)表示不大于n且与n互质的正整数个数。当n为质数时,ψ(n)=n-1;当n=p * q,(p、q均为质数)时,ψ(n)=ψ(p) * ψ(q)=(p-1) * (q-1)
3、RSA密码算法的流程:
RSA密钥的产生,就需要用到以上的数论知识,我们来具体了解一下RSA密钥(N、E、D)的产生步骤:
(1)、产生N:
N = p * q,p和q是两个非常大的质数(一般来说为512bit,十进制为200位左右),大是因为为了质数的组合空间大,以保证选定的p和q不被轻易“猜出来”。p和q要是被知道了,则密码的破译工作就简单多了。
(2)、产生E:
E、p、q满足两个关系:
①1 < E < lcm((p-1) , (q-1)),其中L = lcm((p-1) , (q-1))是p-1和q-1的最小公倍数(least common multiple)
②gcd(E,L)=1,gcd(E,L)为E和L的最大公约数,即E和 lcm((p-1) , (q-1))要互质(但E不一定为质数)。
由上面两个关系,或者说方程求解出来的E一般不止一个,而我们要用于RSA的E必须是从满足方程的E集合中随机取出的一个。
(3)、产生D:
D、E、L必须满足下列关系式:
①1 < D < L,这点和E是一样的
②E × D mod L = 1,上面提到E和L的最大公约数为1的目的就是为了让该方程有解。如果无解,就不存在前面分析时的K12和K22了,而全部是K??。
关于为什么,当E和L最大公约数是1时,D才会有解的问题,可以参考《图解密码技术》日,结城浩著的第一版:5.5时钟运算。
以上算是密钥对{E,N}、{D,N}的产生(我们只需要保存{D,N}不让其他人知道,并将加密程序和{E,N}公钥发送给需要进行通信的一方,就可以让对方的明文加密后只有自己能解密),而实际的加密解密就只有这两个公式:
Ciphertext = Plaintext^E mod N
Plaintext = Ciphertext^D mod N
注意:由于公式中存在次幂运算,而底数和幂数都十分大,所以数字的计算量十分庞大,虽然数字越大越安全(p、q越大,得到的N越大,破解时根据N来反推p、q空间的难度越大,毕竟到目前为止没有一个有效的办法进行N的分解因式),但是这也就意味着加密效率十分低下,而一般我们用混合加密只用RSA加密单钥密钥的密钥(几十到几百bit,比较小)。而不是加密明文信息。所以效率问题可以接受。
4、从algorithm到code的分析与实现:
实现真正的RSA比较麻烦,因为数字比较大,不能用普通的计算机数据类型来简单表示,而需要大数运算作为支撑。所以这里我们只进行小的质数p、q的密钥产生,以unsigned long作为“大数类型huge_t”。
我们具体分析的算法为,如何对一个大数的大数次幂再对大数取模的式子进行运算?比如99^111 mod 143。99的5次方就已经超过unsigned long的表示范围了,要计算99^111次方先不说效率问题,仅仅是结果溢出丢失真实数据就不能采用该方法,并且该方法的效率也是一个天大的问题,当A^B mod N的A、B、N都是200位整数时,效率问题更为突出。而解决方法为:二进制平方乘算法。
所谓二进制平方乘算法,就是根据依次降幂(二进制从高到低向右移位)对b的每一位进行操作。对于:a^b mod n,如何做呢?首先将b表示成二进制形式(本身就是二进制形式,操作用位运算即可),然后从最右边的位(bit)开始处理。对于b中的每个位,求出a的平方对n取模的结果并将这个结果赋给a。当遇到b中为1的bit时,就用当前a值乘以另外一个值y(初始值为1)对n取模的结果赋给y。一旦迭代至b的最高有效位,y的值就是a^b mod n的结果。
代码描述如下:
//a为输入的信息(明文或密文)、b为幂数(e或d)、n为模数//返回值为加密或解密后的密文或明文const huge_t ModExp(huge_t a, huge_t b, huge_t n){ huge_t y =1;//初始值为1 while(b != 0){//未至b最高位 if(b & 0X01){//如果该bit为1 y = (y * a) % n;//用当前a值乘以另外一个值y,赋给y } a = (a * a) % n; b = b >> 1; } return y;}
整个计算过程中产生的最大值是a²,而不像原来的方法中最大值是a^b,小了不止一点。并且当数字为unsigned long类型时,循环只需要执行32次,而不是b次(b可能为上亿次,b为大数时则更是“天文”次循环)。效率提高的也不是亿万次可以形容的了。
加密测试(加密后的文件内容):
解密测试:
关于整整个从素数产生到选取、秘钥计算、加密解密实现的三个部分的代码,由于文件过多只贴出加解密功能代码,测试用的所有文件(随机数产生、密钥计算)可以下载:RSA密码(需要1下载积分,如果没有下载积分而需要源码的朋友也可以邮箱联系索取)。并且由于这里实现只是用unsigned long实现的比较小的数,大数测试可能不能正确解密。
加密解密:
/* *Function:Test for encryption and descryption *Author:Kangruojin *Mail:mailbox_krj@163.com *Time:2017年7月16日13:39:00 *Version:v1.2 **/#include "ende.h"int main(int argc, char * argv[]){ if(argc != 4){ ErrorOfInput(argv[0]); return 0; } //注意:这里只是测试,这种类似与CBC的分组加密方式是不适合于RSA的 //RSA加密一般只有一组,即使有多组,也不应该采用CBC模式 if(0 == strcmp(argv[1],"-e")){ RsaEncrypt(argv[2], argv[3]); } else if(0 == strcmp(argv[1],"-d")){ RsaDecrypt(argv[2],argv[3]); } else{ ErrorOfInput(argv[0]); } return 0;}void ErrorOfInput(const char * str){ printf("请按格式输入运行:\n"); printf("%s -e 私钥e 私钥n\n",str); printf("%s -d 公钥d 公钥n\n",str);}void RsaEncrypt(const char *argv2, const char *argv3){ huge_t ciphertext; unsigned char plaintext; RsaEK enk; enk.e = (huge_t)atol(argv2); enk.n = (huge_t)atol(argv3); FILE * fpin = fopen("./message/plaintext.txt","rb"); FILE * fpout = fopen("./message/ciphertext.txt","wb"); assert(fpin != NULL); assert(fpout != NULL); fread(&plaintext, sizeof(plaintext), 1 ,fpin);//读取一个明文 while(!feof(fpin)){ //*ciphertext = plaintext^(enk->e) mod (enk->n) ciphertext = ModExp((huge_t)plaintext, enk.e, enk.n);//加密一个字符 fwrite(&ciphertext, sizeof(ciphertext), 1, fpout);//写到秘文文件中 fread(&plaintext, sizeof(plaintext), 1 ,fpin);//读取下一个明文 } printf("加密结束!\n"); fclose(fpin); fclose(fpout);}void RsaDecrypt(const char *argv2, const char *argv3){ unsigned char plaintext,ciphertext; RsaDK dnk; dnk.d = (huge_t)atol(argv2); dnk.n = (huge_t)atol(argv3); FILE * fpin = fopen("./message/ciphertext.txt","rb"); FILE * fpout = fopen("./message/plaintextNew.txt","wb"); assert(fpin != NULL); assert(fpout != NULL); fread(&ciphertext, sizeof(ciphertext), 1 ,fpin);//读取一个秘文 while(!feof(fpin)){ //*plaintext = ciphertext^(dnk->d mod (dnk->n) plaintext = ModExp((huge_t)ciphertext, dnk.d, dnk.n);//解密一个字符 fwrite(&plaintext, sizeof(plaintext), 1, fpout);//写到明文文件中 fseek(fpin, 3, SEEK_CUR);//加密文件中的四个字节中只有一个字节有效 fread(&ciphertext, sizeof(ciphertext), 1 ,fpin);//读取下一个秘文 } printf("解密结束!\n"); fclose(fpin); fclose(fpout);}const huge_t ModExp(huge_t msg, huge_t exp, huge_t mod){//平方乘算法 huge_t y =1; while(exp != 0){ if(exp & 1){ y = (y*msg) % mod; } msg = (msg*msg)%mod; exp = exp >> 1; } return y;}
参考资料推荐:
(1)、《应用密码学–协议算法与C源程序》[美]Bruce Schneier著 ,机械工业出版社【第19章:公开密钥算法】(RSA应用、性能、攻击分析等)。
(2)、《图解密码技术》[日]结城浩著,人民邮电出版社【第五章:公钥密码】(基本的图解流程)。
(3)、《算法导论》【第31章:数论算法】(基本的数论知识与RSA的指数运算的高效算法)。
- 双钥密钥密码算法RSA解析与短密钥实现
- AES密钥与RSA密钥
- linux生成RSA密钥对,实现无密码ssh/scp
- 通过安装RSA密钥实现ssh免密码登陆
- 算法整理——非对称密钥加密RSA数学相关与简单实现
- RSA密钥生成与使用
- RSA密钥生成与使用
- C#中用RSA算法生成公钥和私钥openssl RSA密钥的生成与配置
- Mac下通过SSL获取RSA密钥与公钥
- [密码学]公开密钥体系之RSA算法
- 用RSA算法对密钥加密
- PolarSSL的RSA算法密钥格式
- RSA 公开密钥算法简介和示例
- 利用openssl实现RSA密钥生成
- RSA密钥的生成与配置
- RSA密钥的生成与配置
- RSA密钥的生成与配置
- RSA密钥的生成与配置
- 关键字static
- HashMap 不会重复的Arrays
- Dubbo 简 单 应 用
- POJ 2886 Who Gets the Most Candies?
- 使用Nodejs进行反向代理
- 双钥密钥密码算法RSA解析与短密钥实现
- LCA之ST算法模板
- POJ-2965(DFS路径输出)
- poi中getPhysicalNumberOfRows()和getLastRowNum()区别
- stm32中中断源名和中断处理函数名所在位置
- Linux IO模式及 select、poll、epoll详解
- hibernateUtil工具类的封装
- CSS学习笔记:简单样式与选择器(伪元素选择器存疑)
- KeepAlive详解