이 두키의 최대 공약수는 613이고, 다른 키들 중 이를 나누어 다른 인수를 구할 수 있다.
그럼 이번문제는
두 키가 하나의 인수에 대해 가지고 있으면,
p와 q를 알 수 있는 50개의 키값 중 같은 최대 공약수 1이 아닌 수가 있는지 확인 후,
다른 RSA문제 처럼 오일러의 피함수로 개인 인수를 계산하여 메시지를 복호화 할 수 있\다.
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from math import gcd
n=[]
c=[]
e=[]
for i inrange(1, 51):
key = RSA.importKey(open(f"keys_and_messages\{i}.pem", 'r').read())
cipher = open(f"keys_and_messages\{i}.ciphertext", 'r').read()
n.append(key.n)
c.append(cipher)
e.append(key.e)
N = 0for i inrange(len(n)):
for j inrange(i,len(n)):
gcd_between = gcd(n[i], n[j])
if gcd_between != 1and n[i]!=n[j]:
print(i)
print(j)
N =gcd_between
p_find = i
21번째(문제에서 사용한 코드 번호)와 34번째가 같은 인수가 나온 걸 볼 수 있다.
그래서 21번째 N의 값에 플래그값이 있으므로,
p는 최대공약수 값, q는 최대공약수를 나눈 값으로 잡고,
오일러의 피함수의 공식인 (p-1)*(q-1)값을 만들고,
비밀 인수 d를 만들고
공개키 암호화로 키를 만든 후 이를 복호화 시켰다.
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Util.number import *
from math import gcd
n=[]
c=[]
e=[]
for i inrange(1, 51):
key = RSA.importKey(open(f"keys_and_messages\{i}.pem", 'r').read())
cipher = open(f"keys_and_messages\{i}.ciphertext", 'r').read()
n.append(key.n)
c.append(cipher)
e.append(key.e)
N = 0for i inrange(len(n)):
for j inrange(i,len(n)):
gcd_between = gcd(n[i], n[j])
if gcd_between != 1and n[i]!=n[j]:
#print(i+1)#print(j+1)
N =gcd_between
p_find = i
ciphertext=bytes.fromhex(c[p_find])
e=e[p_find]
p=N
q=n[p_find]//N
euler=(p-1)*(q-1)
d=inverse(e, euler)
key= RSA.construct((n[p_find], e, d))
cipher = PKCS1_OAEP.new(key)
plaintext = cipher.decrypt(ciphertext)
print(plaintext)