INCOGNITO 2022

RSA 암호화 알고리즘 분석

kchabin 2022. 8. 13. 01:53

RSA 알고리즘이란?

현대 컴퓨터 시스템 및 다른 전자기기에서 데이터를 암호화/복호화할 때 사용.

두 개의 다른 key를 사용하는 비대칭(asymmetric) 암호학 알고리즘이다. 

 


유클리드 알고리즘(유클리드 호제법)

1. a,b 두 수가 주어짐.(a>b)
2. b가 0이면 a를 리턴함.
3. a가 b로 나눠 떨어지지 않으면 a를 b로, b를 a에서 b로 나눈 나머지를 대입하고 1번으로 돌아감.
a = b
b = a%b
위 코드를
temp = a%b
a = b
b = temp
이런 식으로도 쓸 수 있다.

유클리드 알고리즘을 이용해 38, 10의 최대공약수 구하기
38%10 = 8
a= 10, b= 8 (a에는 b, b에는 a%b 대입)
다시 나눈다.
10%8 = 2
a= 8, b=2
8%2= 0
최대공약수는 2가 된다.

gcd함수 구현 안하고도 math 라이브러리에서 gcd import해서 사용할 수 있다.

 

오일러 피 함수(Euler's totient function)

1부터 n까지의 양의 정수 중에 n과 서로소인 것의 개수를 나타내는 함수.

 

φ(9) = 6 

1~9까지의 자연수 중 9와 최대공약수가 1인 수(서로소인 수)는  1, 2, 4, 5, 7, 8


RSA 알고리즘의 구현

매우 큰 소수 p와 q를 선택.

n = pq, k = φ(n)을 구한 후

e*d = 1+k에서 e와 d를 구한다.

 

n과 e(공개키)는 public으로 공개되고, d는 개인키이다. 

0<m<n인 정수 m으로 표현되는 메시지는 계산에 의해서 암호화된다.

암호화

C = m^e mod n

복호화

t = c^d mod n 
#복호화된 메시지 t = 오리지널 메시지 m

RSA 알고리즘 7단계

1. 두개의 소수 p, q 정하기(너무 작으면 제대로 암/복호화가 이루어지지 않는다.)

 

2. 두 키의 계수인 n=p*q를 구한다.

 

3. 오일러의 피 함수 = (p-1)(q-1)

 

4. 1<e<totient, gcd(e, totient) = 1인 e를 구한다.  -> e는 공개키이다.

 

5. e*d % totient == 1이 되는 d를 구한다. -> d는 개인키이다.

 

6. 암호화된 메시지 c= m^e%n을 구한다. 

m = 메시지 각각의 단일 문자를 아스키 코드로 변환한 값.

 

7. m = c^d%n을 이용 복호화된 메시지 구하기

 

 


공개키, 개인키 만들기
1. 두 소수 p(=11), q(=13)를 준비한다.
두 소수의 곱은 공개키(2개) 중 하나가 된다.

2. phi = (p-1)(q-1)= 10*12=120을 구한다.

3. phi = (p-1)(q-1)와 서로소인 정수 e(ecryption, =7)를 준비한다.
-> 120과 서로소인 정수
또한 1< e<phi 여야 한다.
e는 공개키가 된다.
보통 1의 비트가 2개인 3(11)이나 65537 같은 소수를 쓴다.

4. ed(=7*d)를 phi=120으로 나눈 나머지가 1이 되도록 하는 d(decryption, =103)를 찾는다.
또한 1<d<phi여야한다.
d는 개인키가 된다.
e가 (p-1)(q-1)과 서로소가 아니면 이를 만족하는 d는 존재하지 않는다.

5. N=pq(=143)을 계산한 후, 공개키인 N과 e(=7)를 공개한다.
d는 개인키이므로 숨겨둔다.

#서로소를 따지려면 최대공약수 함수가 필요하다.

from math import gcd

import math

p = 991
q = 997  #서로 다른 두 소수

n = p*q # 두 소수의 계수
tot = (p-1)*(q-1) #오일러 피함수

def gcd(a, b): #최대공약수 구하기
    while b!=0:
        temp = a%b
        a = b
        b = temp
    return a

 
def find_e(tot): #공개키 구하기
    e = 2
    for i in range(2,tot):
        if gcd(tot, i) == 1:
            e = i
            break
    return e

def find_d(tot, e): #개인키 구하기
    d = 3
    for i in range(tot//e, tot):
        if e*i%tot == 1:
            d = i
            break
    return d



 

def enc(pk, plaintext): #암호화 
    key, n = pk 

    cipher = [(ord(char)**key)%n for char in plaintext]
    return cipher

    

def dec(pk, ciphertext): #복호화
    key, n = pk

    plain = [chr((char**key)%n)for char in ciphertext]
    return ''.join(plain)




e = find_e(tot) #공개키 구하는 함수에 위에서 구한 오일러 피함수 대입
d = find_d(tot, e) # 인자로 오일러 피함수와 공개키 대입

m = str(input("암호화할 문장 입력:")) #평문입력받기

encrypted = enc((e,n), m) #암호문
print("암호문 : ", ''.join(map(lambda x: str(x), encrypted))) #암호문 출력
decrypted = dec((d,n), encrypted) #복호문
print("복호문 : ", decrypted) #복호문 출력

'INCOGNITO 2022' 카테고리의 다른 글

Cryptohack - ASCII  (0) 2022.08.10
Cryptohack - Network Attacks  (0) 2022.08.07