드림핵의 RSA(CRT) 문제를 풀며 RSA의 CRT에 대해 공부해보도록 한다.
암호학에서 매우 널리 쓰이는 공개 키 암호방식 중 하나로 1977년에 Ron Rivest, Adi Shamir, Leonard Adleman 세 사람이 개발해서 이름도 그들의 성(Rivest-Shamir-Adleman)에서 따왔다.
공개키 (Public Key): 누구에게나 공개해서 메시지를 암호화할 때 사용
비밀키 (Private Key): 오직 키 소유자만 가지고 복호화에 사용
키 생성
암호화
평문 𝑀을 암호문 𝐶로 변환


CRT는 여러 개의 서로소인 (서로 나누어떨어지지 않는) 정수들에 대해, 각각의 나머지를 알고 있을 때 원래의 수를 유일하게 복원할 수 있다는 정리
어떤 수 x가 있을 때,
x mod n1 = a1
x mod n2 = a2
.
.
.
x mod nk = ak
에서 n1, n2... nk가 서로소 일 때, 이 때 유일한 x를 찾을 수 있다는 것이 CRT이다.
RSA 복호화는 큰 수의 모듈러 지수 연산을 하는데, 이 계산이 매우 느리다.
즉 CRT를 이용하여 작은 모듈러 연산을 하고, 결과를 합쳐서 전체 연산 속도를 높이기 위해 사용한다.
찾고싶은 수 X가 있다.
조건 :
x % 3 = 2
x % 5 = 3
x % 7 = 2
이라고 한다. 위 값을 만족하는 X를 찾을 것 이다.
p1 = 3
p2 = 5
p3 = 7
c1 = x % 3 = 2
c2 = x % 5 = 3
c3 = x % 7 = 2
N = p1 p2 p3 = 3 5 7 = 105
M1 = N / p1 = 105 / 3 = 35
M2 = N / p2 = 105 / 5 = 21
M3 = N / p3 = 105 / 7 = 15
M1 * inv1 ≡ 1 mod p1을 만족하는 inv1을 찾아야 한다.
위의 수식에서 inv1이 2일 때 조건을 만족한다.
위의 수식에서 inv2는 1일 때 조건을 만족한다.
위의 수식에서 inv3는 1일 때 조건을 만족한다.
x = ( c1 x M1 x inv1 ) + ( c2 × M2 × inv2 ) + ( c3 × M3 × inv3 ) mod N
x = ( 2 35 2 ) + ( 3 21 1 ) + ( 2 15 1 ) mod 105
x = ( 140 + 63 + 30 ) mod 105 = 23
위의 조건을 만족하는 x는 23이다.
23 % 3 = 2
23 % 5 = 3
23 % 7 = 2
이렇게 CRT를 이용하여 알고 싶은 X를 구해낼 수 있다.

먼저 위 문제에서는
서로다른 서로소인 p1 p2 p3가 주어지고,
flag에 대한 모듈러 연산인
flag % p1 = c1
flag % p2 = c2
flag % p3 = c3
로 c1 c2 c3가 주어진다.
CRT를 이용하여 flag를 획득하여야 한다
먼저 p와 c는 문제에서 주어진다.
p1 = 1527207470243143973741530105910986024271649986608148657294882537828034327858594844987775446712917007186537829119357070864918869
p2 = 2019864244456120206428956645997068464122219855220655920467990311571156191223237121636244541173449544034684177250532278907347407
p3 = 1801109020443617827324680638861937237596639325730371475055693399143628803572030079812427637295108153858392360647248339418361407
c1 = 232762450308730030838415167305062079887914561751502831059133765333100914083329837666753704309116795944107100966648563183291808
c2 = 869189375217585206857269997483379374418043159436598804873841035147176525138665409890054486560412505207030359232633223629185304
c3 = 1465704473460472286244828683610388110862719231828602162838215555887249333131331510519650513265133531691347657992103108331793683
수가 매우 크므로 파이썬 스크립트를 작성하도록 하겠다.
N = p1 p2 p3 를 구한다.

Mi = N / pi


이때 모듈러 역원을 구하는 확장 유클리드 알고리즘에 대해 알아본다.
예를 들어 a = 3, m = 7일 때,
3 x X = 1 mod 7 을 만족하는 x를 구한다.
위의 식을 다시 말하면, 3 * x에서 1의 차가 7로 나누어 떨어진다는 말이다.
즉 3 x X - 1 ≡ 0 mod 7 이다.
이는 7에 어떤 값을 곱했을 때, 3 x X - 1이 된다는 말이다.
3 x X - 1 = 7 x k
-> 3 x X = 7 x k + 1
-> 3 x X + 7 x (-k) = 1
이 때 -k를 그냥 Y로 치환
3 x X + 7 x Y = 1 ( 이때 X, Y는 정수 )
gcd(7,3):
7 = 2 * 3 + 1 ( 선형식으로 표현 )
1 = 7 - 2 * 3
7 x 1 + 3 x (-2) = 1
만족하는 x , y를 찾아냈다.
x = 1, y= -2

이제 모듈러 역원을 구했고, CRT 공식을 이용하여 전체 값을 얻는다.

먼저 flag의 int값은
3252605711388626316882631631674717103450798162113861327856306348774981010636439640993654302182152291893666887426485817372503250437288712874365

이제 int값을 이용해서 바이트 단위로 변경한 다음 디코딩 한다.

flag의 길이가 8의 배수가 아닐 때를 생각하여 7을 더한 다음 8로 나누어 1바이트 단위로 나눈다. 그리고 빅엔디언으로 표현한다.
처음에 flag는 bytes_to_long을 이용하여 int값으로 바뀌었다. 그러므로 복호화를 할 때는 to_bytes함수를 이용하여 다시 byte값으로 만들어주었다.
이렇게 하면 FLAG값을 구할 수 있다.

Flag : DH{Th3Ch1n35e_r3m4iNd3r_tHe0r3m_w4s_qu1T3_345y_r1ght??:)}
공부를 하며 의문점이 생겼다. 3단계에서 inv1은 5일 때도 위의 수식을 만족한다. 그렇다면 inv를 구할 때 조건은 가장 작은 자연수를 선택하는 것인가?
답은 모듈러 연산에서는 0보다 크고, m보다 작은 값 중에서 가장 작은 값 하나를 사용하는 것이 관례이다.
즉, mod m 안에서 가장 작은 양의 정수 값이라고 한다.
모듈러 연산에서 동일한 값을 내놓는 것들. 즉 위의 연산에서는 2와 5와 8이 같은 것으로 간주된다고 한다.
또한 확장 유클리드 알고리즘은 아직 더 이해가 필요해 보인다. 정리하긴 했지만, 완전히 이해하는데에는 어려움이 있다.. 직관적으로 쉬운 예시를 들을 때는 이해가 갔지만, 큰 수를 대입하여 코드상으로 작성하려니 어려움이 있었다.