(Encryption Basics) RSA

RSA algorithm

RSA is an asymmetric encryption algorithm. If A wants to communicate with B, A uses public key A to encrypt and transfers the ciphertext to B, and B uses private key B to decrypt the plaintext, where the public key is transmitted on the network. The private key is only owned by B and is not transmitted on the network, so even if the public key A is known, the transmitted information cannot be decrypted

RSA algorithm principle and python code implementation

1. Generate public and private keys

1.1 Given two prime numbers P, Q

The larger P and Q here are, the safer the algorithm will be. For the convenience of description, given P=67 and Q=71, then their product n=4757

1.2 Calculate the Euler function φ(n) of n

According to the definition of Euler's function, φ(n) is equal to the number of positive integers less than or equal to n that are relatively prime to n , and because P*Q=n and PQ are all prime numbers, φ(n) = (P -1)(Q-1) = 66 * 70 = 4620

1.3 Randomly select an integer e(1<e<m) and e and m are relatively prime

Here e=101 is randomly selected. Note that when e=m, the public and private keys will be the same

1.4 Given an integer d, make (e*d)%m=1
因为 (e*d)%m=1  

所以 e*d-m*y=1(y为整数),由上述可知 e = 101,m = 4620 

所以 101d-4620y=1

根据相关定理(d,y)=1=101d-4620y

根据扩展欧几里得算法:

4620=101x4+75
101=75x1+26
75=26x2+23
23=3x7+1
3=2x1+1
---->
101x1601-35x4620

得到d等于1601

After the calculation is completed, the public key (n,e)=(4757,101) and the private key (n,d)=(4757,1601) are obtained . According to the effect of the RSA algorithm, no one knows the private key except the receiver . So can you get the private key through the public key?

已知(e*d)%m=1,已知n,e,那么要求d只需要求出n

而我们知道m是n的欧拉函数φ(n),想要知道m就必须将n分解成两个质数的乘积
这里由于数比较小,我们很容易分解出PQ的值,而随着n的增大,分解会变得异常困难

2. Encryption to generate ciphertext

Assuming that the encrypted number is a,
then converting a to int is 97. The
calculation process is as follows:

97^101%4757=3589

Insert picture description here

3. Decrypt the ciphertext

According to the formula
a^d% n = b

We can get the plaintext

Insert picture description here

Python code implementation

Since C language does not support large numbers, it is very troublesome to use C language to implement python code here


# -*- coding: cp936 -*-


def isPrime(number):
    import math
    i = 2
    sqrtnum = (int)(math.sqrt(number))
    for i in range(2, sqrtnum + 1):
        if number % i == 0:
            return False
        i = i + 1
    return True


def is_ET_Prime(ee, tt):
    while tt != 0:
        a = ee
        ee = tt
        tt = a % tt
    if ee == 1:
        return True
    else:
        return False


def get_publickey(k, t):
    d = 0
    while ((d * k) % t != 1):
        d += 1
    return d


def encryption(plain, d, n):
    re = (plain ** d) % n

    return re


if __name__ == "__main__":
    print
    "~" * 70
    Flag = False
    while True:
        p = int(input("please input a prime p:"))
        q = int(input("please input a prime q:"))

        if (isPrime(p) and isPrime(q)):
            break
        else:
            print
            "p or q is not prime!"
            continue

    print
    "p=", p, "q=", q

    n = q * p
    t = (q - 1) * (p - 1)
    print("n=", n, "t=", t)

    print("~" * 70)

    Flag == False
    while Flag == False:
        e = int(input("please input a private key:"))
        Flag = is_ET_Prime(e, t)
        if Flag == False:
            print("e is not prime with the t!")

    print("the private key e=", e)

    d = get_publickey(e, t)
    print("the public key d=", d)

    plain = int(ord(input("please input the plain you want to entrypted:")))

    encry = encryption(plain, d, n)
    print("plain", plain, "is encrypted as", encry)
    #print(encry)
    plain1 = encryption(encry, e, n)
    print("encrypt", encry, "is decrypted as", plain1)

RSA common mode attack

Suppose there is a piece of information m, which is encrypted by two different users using public keys (the e of the two users are generally different, and the modulus n is generally the same)

c1 = m^e1 mod n
c2 = m^e2 mod n

Got two different ciphertexts c1, c2

Common mode attack This gets these two ciphertexts c1, c2, because the public key is public (e1, e2, n) is known

Then the attacker knows the following information in total

gcd(e1, e2) = 1
m = c1^d1 mod n
m = c2^d2 mod n

Then according to the above, the plaintext m can be directly obtained, because gcd(e1,e2)then there are integers s1, s2 e1*s1+e2*s2=1, and because

c1=m^e1 mod n
c2=m^e2 mod n

and so:

c1^s1 mod n=m^(e1*s1) mod n
c2^s2 mod n=m^(e2*s2) mod n
c1^s1*c2^s2 mod n=m^(e1*s1+e2*s2) mod n
又因为e1*s1+e2*s2=1
所以
c1^s1*c2^s2  =m mod n
再由扩展欧几里得算法和e1*s1+e2*s2=1,即可求出s1,s2

Code template:

from libnum import n2s,s2n
from gmpy2 import invert

def egcd(a, b):
if a == 0:
    return (b, 0, 1)
else:
    g, y, x = egcd(b % a, a)
    return (g, x - (b // a) * y, y)

def main():
    n = int(input("请输入一个十六进制数n"),16)
    c1 = int(input("请输入一个十六进制数c1"),16)
    c2 = int(input("请输入一个十六进制数c2"),16)
    e1 = int(input("请输入一个十六进制数e1"),16)
    e2 = int(input("请输入一个十六进制数e2"),16)
    s = egcd(e1, e2)
    s1 = s[1]
    s2 = s[2]
    # 求模反元素
    if s1<0:
        s1 = - s1
        c1 = invert(c1, n)
    elif s2<0:
        s2 = - s2
        c2 = invert(c2, n)

    m = pow(c1,s1,n)*pow(c2,s2,n) % n
    print n2s(m)

if __name__ == '__main__':
  main()

Guess you like

Origin blog.csdn.net/weixin_43632667/article/details/106415454