玩转RSA

举报
DRS技术快客 发表于 2021/04/30 16:31:52 2021/04/30
【摘要】 通常说非对称加密,我们就能想到RSA,RSA的原理是什么呢,这就得从数据理论开始说起了 RSA数学理论: 欧拉定理:(a^φ(n))%n=1即两个互素的数a和n,(a<n)存在:a的φ(n)次方与n的余数为1,其中φ(n)为小于n,并且与n互素的个数如:a为4,n为7,两个互为素数,φ(7)=6(因为7本身是素数,所以小于7并与其互素的数字有1,2,3,4,5,6), 4^6=4096=75...

通常说非对称加密,我们就能想到RSA,RSA的原理是什么呢,这就得从数据理论开始说起了

RSA数学理论:

欧拉定理:(a^φ(n))%n=1

即两个互素的数a和n,(a<n)存在:a的φ(n)次方与n的余数为1,其中φ(n)为小于n,并且与n互素的个数
如:
a为4,n为7,两个互为素数,φ(7)=6(因为7本身是素数,所以小于7并与其互素的数字有1,2,3,4,5,6), 4^6=4096=7585+1,即4^6%7=1
a为5,n为8,两个互为素数,φ(8)=4(小于8并与其互素的数字有1,3,5,7), 5^4=625=8
78+1,即5^5%8=1

简单推导如下:

如果一个正整数n,小于且与n互素的数的集合为{x1,x2,x3……xφ(n)},用A0表示, a∈A0
设P0=x1x2x3……xφ(n),则P0与n互素
设P1=((x1a)(x2a)(x3a)……(xφ(n)a)),设xia=yin+zi(zi∈A0)做替换,则P1=(y1n+z1)(y2n+z2)(y3n+z3)……(yφ(n)n+zφ(n)),其中z1,z2,z3……zφ(n)都不相等(因为xia=yin+zi,xja=yjn+zj => xia-xja=yin+z-yjn-zj=(yi-yj)n-(zi-zj) 假设zi-zj=0 => (xi-xj)a=(yi-yj)n,xi-xj小于n,a与n互素,产生矛盾),则zi∈A0 P1=(xxxx)n+z1z2z3……zφ(n)
可得P1%n=P0%n,即((x1
a)
(x2a)(x3a)……(xφ(n)a))%n=x1x2x3……xφ(n)%n,简化为(a^φ(n)P0)%n=P0%n
因则P0与n互素,则(a^φ(n))%n=1,即为欧拉定理
如:
n为7时,A0={1,2,3,4,5,6},取a为4,P0=1
23456,P1=(14)(24)(34)(44)(54)(64)=(70+4)(71+1)(71+5)(72+2)(72+6)(73+3)=xxx7+415263,即P1%7=P0%7
a为5,n为8,A0={1,3,5,7},P0=1357, P1=(15)(35)(55)(57)=(80+5)(81+7)(83+1)(84+3)=xxx8+571*3,所以P1%8=P0%8

####RSA加密公式:b^(kφ(n)+1)%n=b
即,当一个正整数n为两个素数的乘积的时候,任何小于n的正整数b,都有b^(kφ(n)+1)%n=b公式成立
两个素数p、q,设n=p
q,则与n不互素的数有p,2p……pq, q,2q……(p-1)q,总共有q+p-1个,其它都与n互素的,因此φ(n)=n-(q+p-1)=pq-q-p+1=(p-1)*(q-1)
如:
p=2,p=3 => n=6, φ(n)=2 => 2^(2+1)%6=8%6=2, 3^(2+1)%6=27%6=3, 4^(2+1)%6=64%6=4, 5^(2+1)%6=125%6=5
p=3,p=4 => n=12, φ(n)=6 => 5^(6+1)%12=78125%12=5, 5^(6+1)%12=78125%12=5, 11^(6+1)%12=19487171%12=11

######简单推导如下:
1、如果b与n互为素数,
则b^φ(n)%n=1 => b^(kφ(n))%n=1 => b^(kφ(n)+1)%n=b
2、如果b与n不互素,则b一定是p或者q的倍数,设b=mp,
则b与q互素 => b^φ(q)%q=1
因q为素数,所以φ(q)=q-1 => b^(q-1)=k1q+1 => b^(k(q-1)(p-1))=k2q+1 => b^(k(q-1)(p-1))b=k2qb+b => b^(kφ(n)+1)=k2mqp+b => b^(kφ(n)+1)=k2mn+b => b^(k*φ(n)+1)%n=b

####RSA加密解密元理:
依据 b^(kφ(n)+1)%n=b,如果能把b^(kφ(n)+1变成两个数的e和d的乘积,即kφ(n)+1=ed
则b^(ed)%n=b => ((b^e)^d)%n=b 可以分解成两步,c=(b^e)%n, (c^d)%n=b,这两步就分别为加密和解密
如果b为明文,那么c就是密文,(e,n)为公钥,(d,n)即为私钥
如:
n=15,φ(15)=8,
取k=4,则k
φ(n)+1=33,可以取d=3,e=11, 那么对于明文为小于15的正数,

加密:  1^3%15=                       1%15 = 1 解密: 1^11%15=                       1%15= 1
加密:  2^3%15=                       8%15 = 8 解密: 8^11%15=              8589934592%15= 2
加密:  3^3%15=                      27%15 =12 解密:12^11%15=            743008370688%15= 3
加密:  4^3%15=                      64%15 = 4 解密: 4^11%15=                 4194304%15= 4
加密:  5^3%15=                     125%15 = 5 解密: 5^11%15=                48828125%15= 5
加密:  6^3%15=                     216%15 = 6 解密: 6^11%15=               362797056%15= 6
加密:  7^3%15=                     343%15 =13 解密:13^11%15=           1792160394037%15= 7
加密:  8^3%15=                     512%15 = 2 解密: 2^11%15=                    2048%15= 8
加密:  9^3%15=                     729%15 = 9 解密: 9^11%15=             31381059609%15= 9
加密: 10^3%15=                    1000%15 =10 解密:10^11%15=            100000000000%15=10
加密: 11^3%15=                    1331%15 =11 解密:11^11%15=            285311670611%15=11
加密: 12^3%15=                    1728%15 = 3 解密: 3^11%15=                  177147%15=12
加密: 13^3%15=                    2197%15 = 7 解密: 7^11%15=              1977326743%15=13
加密: 14^3%15=                    2744%15 =14 解密:14^11%15=           4049565169664%15=14

取k=13,则k*φ(n)+1=115,可以取d=7,e=15,

加密:  1^7%15=                       1%15 = 1 解密: 1^15%15=                       1%15= 1
加密:  2^7%15=                     128%15 = 8 解密: 8^15%15=          35184372088832%15= 2
加密:  3^7%15=                    2187%15 =12 解密:12^15%15=       15407021574586368%15= 3
加密:  4^7%15=                   16384%15 = 4 解密: 4^15%15=              1073741824%15= 4
加密:  5^7%15=                   78125%15 = 5 解密: 5^15%15=             30517578125%15= 5
加密:  6^7%15=                  279936%15 = 6 解密: 6^15%15=            470184984576%15= 6
加密:  7^7%15=                  823543%15 =13 解密:13^15%15=       51185893014090760%15=10
加密:  8^7%15=                 2097152%15 = 2 解密: 2^15%15=                   32768%15= 8
加密:  9^7%15=                 4782969%15 = 9 解密: 9^15%15=         205891132094649%15= 9
加密: 10^7%15=                10000000%15 =10 解密:10^15%15=        1000000000000000%15=10
加密: 11^7%15=                19487171%15 =11 解密:11^15%15=        4177248169415651%15=11
加密: 12^7%15=                35831808%15 = 3 解密: 3^15%15=                14348907%15=12
加密: 13^7%15=                62748517%15 = 7 解密: 7^15%15=           4747561509943%15=13
加密: 14^7%15=               105413504%15 =14 解密:14^15%15=      155568095557812224%15=14

可见,e和d也是多对的,还可以替换n,e,d的值用如下代码做验证(注意防止类型溢出)

long n = 15;
int e = 3;
int d = 11;

String pattern = "加密:%8s=\t%23s\t=%2s\t解密:%8s=\t%23s=%2s";
for (int i=1; i<n; i++) {
    long j = (long)Math.pow(i, e);
    long k = (long)Math.pow((j % n), d);
    System.out.println(String.format(pattern, i + "^" + e + "%" + n, j + "%" + n, j % n, (j % n) + "^" + d + "%" + n, k + "%" + n, k % n));
}

####求解二元二次方程ed=kφ(n)+1,其中φ(n)为已知,e,d,k都为正整数
此时如果固定d不变,
设e=x,k=-y,方程可以转换成d
x+φy=1
由此可知我们取的d满足的条件为:d和φ要互素(如果d与φ不互素的话,如果它们有公约数θ,那么就有θ
(ix+jy)=1,等式无法成立,因为i,j,x,y都为整数)
设d1=d%φ, m=(d-d1)/φ => d1=d-mφ
则(d-mφ+mφ)x+φy=1 => d1x+φ*(mx+y)=1 可以表示为 d1x1 + φ1y1=1
经过多次迭代之后dnxn+φnyn=1其中dn=0或者φn=1的时候,就有xn+φnyn=1
此时方程的根为:(xn, yn)为(1,0),(-φn+1,1)……(-m
φn+1,m)……
再反向逆推出(x,y)来

用程序求dx+φy=1的代码如下①:
public static int[] getxy(int d, int φ) {
    if (d < φ) {
        int[] ret = getxy(φ, d);
        ret[0] = ret[1] + ret[0];
        ret[1] = ret[0] - ret[1];
        ret[0] = ret[0] - ret[1];
        return ret;
    }
    if (φ == 1) {
        return new int[] {0, 1};
    }
    int c = d / φ;
    int d1 = d % φ;
    if (d1 == 0) {
        throw new RuntimeException("nums not prime");
    }
    int[] ret = getxy(d1, φ);
    return new int[] {ret[0], ret[1] - c * ret[0]};
}

d=3,φ=8 => [3,-1] => x=3+8m,k=1+3m(m为整数) (k=-y), (e,k)可以为(11,4),(19,7),(27,10)……
d=5,φ=8 => [3,-1] => x=-3+8m,k=-2+5m(m为整数)
d=7,φ=8 => [3,-1] => x=-1+8m,y=-1+7m(m为整数),(e,k)可以为(15,13),(23,20),(31,27)……

加密(求指数并取模)简化

x1%n=y1,x2%n=y2,则可表示为:x1=k1n+y1,x2=k2n+y2 => x1x2=(k1k2n+y1k2+y2k1)n+y1y2 => (x1x2)%n=y1y2=((x1%n)(x2%n))%n
因此(a^m)%n=(((a^(m-1))%n)*(a%n)%n,因此求指数并取余可以用代码替代②

private static int getMode(int num, int exp, int module) {
    int calNum = 1;
    for (int i = 0; i < exp; i++) {
        calNum *= num;
        calNum = calNum % module;
    }
    return calNum;
}

long n = 15;
int e = 3;
int d = 11;

String pattern = "加密:%8s=\t%23s\t=%2s\t解密:%8s=\t%23s=%2s";
for (int i=1; i<n; i++) {
    int j = getMode(i, e, 15);
    int k = getMode(j, d, 15);
    System.out.println(String.format(pattern, i + "^" + e + "%" + n, j + "%" + n, j % n, (j % n) + "^" + d + "%" + n, k + "%" + n, k % n));
}

RSA使用

生成RSA公钥与私钥

根据上文的原理解析,可知生成RSA密钥文件,过程大致为
1、取两个大素数,p,q,令n=pq, 则φ(n)=(p-1)(q-1)
2、取一个与φ(n)互素的数d,一般都是用65537
3、根据函数②求出一对(e,k)来

######用openssl生成密钥对
1、利用openssl可以随机生成一个512位的(512指私钥的)私钥文件 private_key.pem
openssl genrsa -out private_key.pem 512
2、根据私钥生成一个公钥 public_key.pem
openssl rsa -in private_key.pem -pubout -out public_key.pem

查看

查看公钥
openssl rsa -pubin -in public_key.pem -text -noout

RSA Public-Key: (512 bit)
Modulus:
    00:ea:6b:cb:90:9f:1d:44:74:b6:c3:ff:fb:f5:bb:
    25:e9:ac:3c:ce:60:9c:98:3b:ed:1e:4e:1a:10:ee:
    e1:19:62:9d:16:26:69:df:85:a7:9a:a8:44:d2:80:
    61:d8:cf:98:db:81:a6:01:a2:41:29:1b:c5:7c:c9:
    39:b2:4a:0f:51
Exponent: 65537 (0x10001)
公钥格式
RSAPublicKey ::= SEQUENCE {
   modulus           INTEGER,  -- n
   publicExponent    INTEGER   -- e
}

查看私钥
openssl rsa -in private_key.pem -text -noout

RSA Private-Key: (512 bit, 2 primes)
modulus:
    00:ea:6b:cb:90:9f:1d:44:74:b6:c3:ff:fb:f5:bb:
    25:e9:ac:3c:ce:60:9c:98:3b:ed:1e:4e:1a:10:ee:
    e1:19:62:9d:16:26:69:df:85:a7:9a:a8:44:d2:80:
    61:d8:cf:98:db:81:a6:01:a2:41:29:1b:c5:7c:c9:
    39:b2:4a:0f:51
publicExponent: 65537 (0x10001)
privateExponent:
    00:c9:2c:6c:eb:d5:c0:d6:28:9b:58:24:ec:63:7b:
    92:13:b0:be:16:16:0f:0d:0e:10:75:bb:6c:df:2f:
    41:79:f7:e4:7e:37:df:64:b4:42:5d:cd:d6:e1:44:
    cb:c5:ae:d0:a5:87:ad:98:21:e2:8d:10:b9:a1:d2:
    70:9f:a0:04:01
prime1:
    00:f7:9d:dc:f8:67:c3:cd:37:d1:46:1a:d8:29:13:
    94:ea:24:b9:48:32:0b:71:4c:7b:c8:92:8b:af:54:
    48:8f:e1
prime2:
    00:f2:5b:90:49:df:bd:3b:93:30:0a:df:ea:12:65:
    9c:c0:cf:6a:52:6e:af:3e:20:de:43:0e:1b:a0:bb:
    f8:2d:71
exponent1:
    0f:ba:9c:65:bf:19:a5:f8:8c:b7:9a:4e:ee:d5:0a:
    99:90:f9:a0:07:65:c8:ad:a6:13:48:93:cc:f0:5a:
    a7:a1
exponent2:
    00:96:17:84:ad:6b:85:da:fe:55:93:76:86:94:ec:
    1e:fe:fd:b5:3f:e5:d2:5b:ac:a9:59:67:c4:4e:6f:
    fa:cb:d1
coefficient:
    39:42:b8:82:32:32:af:e1:b2:77:ad:d1:1b:f2:78:
    8e:e5:53:ac:e5:74:6e:2e:f0:a2:6e:81:88:39:67:
    85:7b

私钥格式
RSAPrivateKey ::= SEQUENCE {
 version Version,
 modulus INTEGER, -- n
 publicExponent INTEGER, -- e
 privateExponent INTEGER, -- d
 prime1 INTEGER, -- p
 prime2 INTEGER, -- q
 exponent1 INTEGER, -- d mod (p-1)
 exponent2 INTEGER, -- d mod (q-1)
 coefficient INTEGER -- (inverse of q) mod p 
}

可见私钥里面包含了所有的p、q、e、d、n等信息

验证
//转换成16进制的数字格式
> openssl rsa -in private_key.pem -text -noout|sed 's/://g'|tr 'a-z' 'A-Z'|awk '{if(match($0,/^[A-Z]+/)){print str;str=$0":"}else{str=str$1}}END{print str}'

RSA PRIVATE-KEY (512 BIT, 2 PRIMES):
MODULUS:00DF4D54818D8ACCD56E5F72985BBD69BB2F4957DE177FB221C6756B9F4CDD1EE1667330C466E3B3138DDEC9F7FF4A36EC2387C853B4EB0FAF5317CF924CEDACE3
PUBLICEXPONENT 65537 (0X10001):
PRIVATEEXPONENT:009DEFE2F252BB364F4AE68575CF8533D02A0CD4F2076AD101E48D4E567895F8ED1F066690B28D1A9422758B6840475EE9A512082E296CC429D90D9543A00391F1
PRIME1:00F8312B334BCC4B6FB5D45638D535A1640C4BC99D1C4289077556FBE7EA47669B
PRIME2:00E653B547E3924AF129D48CCCA88CC6CA2918D466D94809EF8783037419909359
EXPONENT1:511D68BC141AC9D0D1C17B088A0E4417F9B8CF44CCD6A6084CFE47C82D1676DF
EXPONENT2:00AF775FE8576750AE6EC69D4920B2B692B6425335D31BFD6DBC57C3DEC3C70F69

//验证p*q-n=0
> echo "ibase=16;obase=10;00F8312B334BCC4B6FB5D45638D535A1640C4BC99D1C4289077556FBE7EA47669B*00E653B547E3924AF129D48CCCA88CC6CA2918D466D94809EF8783037419909359-00DF4D54818D8ACCD56E5F72985BBD69BB2F4957DE177FB221C6756B9F4CDD1EE1667330C466E3B3138DDEC9F7FF4A36EC2387C853B4EB0FAF5317CF924CEDACE3"|bc
0

//验证(e*d)%((p-1)*(q-1))=1
> echo "ibase=16;obase=10;(10001*009DEFE2F252BB364F4AE68575CF8533D02A0CD4F2076AD101E48D4E567895F8ED1F066690B28D1A9422758B6840475EE9A512082E296CC429D90D9543A00391F1)%((00F8312B334BCC4B6FB5D45638D535A1640C4BC99D1C4289077556FBE7EA47669B-1)*(00E653B547E3924AF129D48CCCA88CC6CA2918D466D94809EF8783037419909359-1))"|bc
1

使用

加密一个字符串

echo “hello world”|openssl rsautl -encrypt -pubin -inkey public_key.pem |base64 -w 200
ETEiZkXmHhYLLp5M5H/SWwFliSwfdXStsNGT6Yx+UGPas+1s38e35zN8mb3Vqic07VOTvqxg2d+xONsCDLFNLmsRmok/sMb0hOYy97RCzPdsrHb0wfEEnze6yQVbp31qguI2KKTjb5+cwT3rOCMGzLlib5kr2OwsxNfIk0PyNms=

解密字符串

echo ‘O7W4OS1pEmkil5fNNok0qsXjiQLLuwGYUwbYTK8ax+AvvlNlHjUmXZFC/gOw8pJQTkvYR1ouXyNswgQf8OkScypDog38hoJFAcFNiWN4qZa+OImCjyLEuLCiRn5AJnHDnwugvP7dyqZjcbkFkcCelglx4IcJSdzRRfyTSfNUmYU=’|base64 -d|openssl rsautl -decrypt -inkey private_key.pem
hello world

加密解密成功了
看看RSA是不是很简单?

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。