회고 - Encryptor(Rev)
문제 해결 주요 과정
main
실행 및 구조 분석
main
은 암호화된 입력 파일을 읽고, 특정 연산 후 .enc
확장자를 추가한 파일을 출력
strings
와 IDA
로 실행 파일을 분석하여 다음과 같은 정보를 추출:
- 입력 파일을 bit shuffle
및 XOR
연산으로 암호화
rand()
함수 호출로 난수 시퀀스를 생성
srand(time(0))
를 사용했기 때문에, 실행 시점의 timestamp를 복원하면 동일한 난수 시퀀스를 재현 가능
난수 시퀀스 복구
- 문제에서
flag.png.enc
의 수정 시간을 통해 정확한 time(0)
값을 계산
- Python의
random
모듈로 동일한 난수 시퀀스를 재현하여 암호화 시 사용된 난수를 추출
복호화 로직 구현
main
파일의 디컴파일된 코드를 기반으로 복호화 과정 구현:
- 비트 순서를 섞은 데이터의 역변환(
reverse_bit_shuffle
)
- XOR 변환을 제거
- 데이터 블록마다 적용된 체크섬 계산을 검증
- Python 스크립트로 복호화 과정을 작성하여
flag.png.enc
를 입력으로 받아 flag.png
를 생성
결과 확인
- 복호화된
flag.png
를 열어 플래그를 확인
회고 시의 특기사항
암호화 방식 분석
- 암호화는 단순한
bit shuffle
및 XOR
기반으로 구현.
- 암호화 과정에서 난수 시퀀스가 결정적(
srand(time(0))
)으로 생성되었기 때문에 복구가 가능
취약점 파악
- 난수 시퀀스의 결정론적 인자 사용은 보안상 큰 취약점:
- 공격자가 실행 시점의 time(0)
값을 복원하면 동일한 난수 시퀀스를 재현할 수 있음
- 복호화 과정의 단순성:
- 암호화 알고리즘이 공개되어 있었기 때문에, 로직 분석을 통해 복호화가 가능
문제 풀이에서 배운 점
- 난수 시퀀스 생성에 있어
time(0)
과 같은 간단한 시드 값은 사용하지 않아야 함
- 복호화 로직 구현 시, 암호화 알고리즘의 동작을 이해하고 정확히 역변환을 수행해야 함
성공 코드
import ctypes
from ctypes import CDLL
libc = CDLL("libc.so.6")
def block_checksum(block):
x = 0
for i in range(7):
x = x ^ block[i]
for j in range(8):
if ctypes.c_int8(x).value < 0:
x = x * 2 ^ 7
x &= 0xff
else:
x = x << 1
x &= 0xff
return x
def decrypt_block(block):
found = False
block = list(block)
for i in range(8):
for j in range(8):
test_block = block[::]
test_block[i] ^= 1 << j
if block_checksum(test_block) == test_block[7]:
block = test_block
found = True
break
if found:
break
bits = []
for i in range(7):
for j in range(8):
bits.append((block[i] >> j) & 1)
swap_offset = libc.rand() % 7
for i in range(55, -1, -1):
if i + swap_offset < 56:
temp = bits[i]
bits[i] = bits[i + swap_offset]
bits[i + swap_offset] = temp
dec_block = [0] * 7
for i in range(7):
for j in range(8):
dec_block[i] |= bits[i * 8 + j] << j
return bytes(dec_block)
enc = open("./flag.png.enc", 'rb').read()
libc.srand(1730806261)
dec = b''
for i in range(len(enc) // 8):
dec += decrypt_block(enc[i * 8:(i * 8 + 8)])
out = open(f'./flag.png', 'wb')
out.write(dec)
out.close()
print('Complete!')
놓친 점
-
**체크섬 검증과 역변환
- 기존 접근에서
block_checksum
과 같이 데이터를 검증하며 역변환하는 과정을 제대로 수행하지 못함
- 특히, 변조된 비트를 확인하고 복구하는 과정을 소홀히 했습니다.
-
비트 셔플링의 순서
- 암호화 과정에서 비트들이 랜덤하게 섞였기 때문에 이를 역순으로 정확히 복구해야 했음
- 기존 시도에서는 이 역순 변환 과정을 놓쳤거나 잘못 구현
-
블록 단위 작업
- 데이터가 8바이트씩 분리되어 7바이트 데이터와 1바이트 체크섬으로 구성된 구조임을 알았으나, 이를 블록 단위로 다루는 데 실패
코드 설명
체크섬 검증 함수: block_checksum
- 목적: 블록의 데이터 무결성을 검증하기 위한 체크섬 계산
- 과정:
- 첫 번째 바이트부터 7바이트까지 XOR 연산으로 값을 누적
- 누적된 값을 비트 시프트 및 특정 조건(
<0
)에 따라 조작
- 결과적으로 1바이트 크기의 체크섬 값을 반환
def block_checksum(block):
x = 0
for i in range(7):
x = x ^ block[i]
for j in range(8):
if ctypes.c_int8(x).value < 0:
x = x * 2 ^ 7
x &= 0xff
else:
x = x << 1
x &= 0xff
return x
블록 복호화 함수: decrypt_block
- 목적: 암호화된 블록(8바이트)을 복호화하여 원래 데이터를 복구
- 과정:
- 비트 플립 탐색:
- 블록의 모든 비트를 뒤집어 체크섬과 일치하는 블록을 찾음
- 변조된 비트를 복구
- 비트 배열 변환:
- 역 셔플링:
- 암호화 시 수행된 비트 섞기를 랜덤 오프셋(
swap_offset
)을 기반으로 역변환
- 복호화된 데이터 생성:
- 복원된 비트 배열을 다시 7바이트 데이터로 변환
def decrypt_block(block):
found = False
block = list(block)
for i in range(8):
for j in range(8):
test_block = block[::]
test_block[i] ^= 1 << j
if block_checksum(test_block) == test_block[7]:
block = test_block
found = True
break
if found:
break
bits = []
for i in range(7):
for j in range(8):
bits.append((block[i] >> j) & 1)
swap_offset = libc.rand() % 7
for i in range(55, -1, -1):
if i + swap_offset < 56:
temp = bits[i]
bits[i] = bits[i + swap_offset]
bits[i + swap_offset] = temp
dec_block = [0] * 7
for i in range(7):
for j in range(8):
dec_block[i] |= bits[i * 8 + j] << j
return bytes(dec_block)
파일 복호화
- 목적: 암호화된 파일을 블록 단위로 읽어 원본 데이터를 복호화
- 과정:
- 암호화된 데이터를 8바이트씩 나눔
- 각 블록에 대해
decrypt_block
함수 호출
- 복호화된 데이터를 결합하여 원본 파일 생성
enc = open("./flag.png.enc", 'rb').read()
libc.srand(1730806261) # 암호화 시 사용된 시드로 랜덤 시퀀스 재현
dec = b''
for i in range(len(enc) // 8):
dec += decrypt_block(enc[i * 8:(i * 8 + 8)])
out = open(f'./flag.png', 'wb')
out.write(dec)
out.close()
print('Complete!')
회고 - Kkkk(Crypto)
1. ECDSA 소개
1.1 디지털 서명의 개념
- 디지털 서명이란 무엇인가?
- 디지털 서명의 주요 특징:
1.2 ECDSA 개요
- ECDSA의 정의와 목적
- 기존 DSA와의 차이점
- DSA (Digital Signature Algorithm)의 확장
- 타원 곡선을 활용한 키 크기 및 효율성 개선
2. 타원 곡선 암호학 기초
2.1 타원 곡선이란?
- 타원 곡선의 정의:
- 일반적인 방정식: y2=x3+ax+b
- ECDSA에서 사용되는 Weierstrass 형태
- 타원 곡선의 시각적 이해:
2.2 군 이론과 타원 곡선
- 군 연산의 정의:
- 점 덧셈 (Point Addition)
- 점 두 배 연산 (Point Doubling)
- 군의 성질:
- 타원 곡선 군의 응용:
- 비밀키와 공개키의 관계
- 점 곱 연산의 계산 복잡성과 안전성
2.3 유한체(Galois Field)에서의 타원 곡선
- 유한체의 정의와 성질
- GF(p): 소수 p를 모듈로 하는 체
- 유한체 위의 타원 곡선:
- 암호학에서의 응용:
3. ECDSA의 수학적 원리
3.1 주요 구성 요소
- 타원 곡선 파라미터:
- 소수 체 p, 곡선 파라미터 a,b
- 기본점 G, 군의 순서 n
- 개인키와 공개키의 관계:
- 개인키 d: 비밀 값
- 공개키 Q=d⋅G
3.2 서명 생성 과정
- 해시 값 계산:
- 서명할 메시지를 SHA-256 등으로 해싱하여 hhh 생성
- 랜덤 Nonce 생성:
- 서명 값 계산:
- R=k⋅G에서 x-좌표를 r로 정의
- s=k−1(h+r⋅d)mod n
3.3 서명 검증 과정
- 서명 값 검증:
- 입력: 메시지 해시 hhh, 공개키 QQQ, 서명 (r,s)(r, s)(r,s)
- 조건: 1≤r,s<n
- 검증 식 계산:
- u1=h⋅s−1mod nu1=h⋅s−1modnu1=h⋅s−1modn
- u2=r⋅s−1mod nu2=r⋅s−1modnu2=r⋅s−1modn
- V=u1⋅G+u2⋅QV=u1⋅G+u2⋅QV=u1⋅G+u2⋅Q
- 검증: r=?x-좌표 of V
3.4 공격 가능한 부분
- Nonce k의 재사용:
- 동일한 k로 다른 메시지를 서명하면 d 복구 가능
- Nonce k의 상관관계:
- k가 결정론적으로 생성되거나 일부 알려질 경우 취약
4. 문제에 적용된 ECDSA의 취약점
4.1 문제의 주요 취약점 분석
- 랜덤 Nonce k의 생성 방식:
- k=mul⋅k+inc
mul
, inc
가 고정되어 있어 k가 예측 가능
- 서명 요청에서 kkk의 상관관계를 유도:
4.2 개인키 ddd 복구 방법
- 두 서명 (r1,s1),(r2,s2)에서의 관계:
- r1=r2: 동일한 k가 사용됨
- s1=k−1(h1+r1⋅d)
- s2=k−1(h2+r2⋅d)
- kkk 제거 및 개인키 계산:
- d=(s1⋅h2−s2⋅h1)/(s2⋅r1−s1⋅r2)mod n
5. SageMath를 활용한 문제 풀이
5.1 SageMath로 수학적 계산하기
- 서명 관계를 입력하여 연립방정식 풀이
- 타원 곡선 연산을 활용하여 개인키 ddd 복구
5.2 스크립트 예제
- SageMath 스크립트를 사용한 개인키 계산 과정
- 복구한 개인키로 문제 해결
6. 결론
6.1 이번 문제를 통해 배운 점
- ECDSA의 수학적 원리와 구조적 취약점
- 랜덤 Nonce의 중요성
6.2 추가 학습 방향
- 타원 곡선 암호학의 심화 학습
- SageMath 및 암호 분석 도구 활용 능력 강화
1. ECDSA 소개
1.1 디지털 서명의 개념
디지털 서명은 현대 암호학에서 데이터를 보호하고 인증하는 데 중요한 기술입니다. 디지털 서명은 물리적 문서의 서명과 유사한 역할을 하지만, 전자 문서나 데이터를 위한 것으로, 데이터의 출처를 확인하고 데이터가 위변조되지 않았음을 보장합니다. 이를 위해 디지털 서명은 공개 키 암호화를 기반으로 동작하며, 데이터를 서명한 개인의 비밀키와 이를 검증할 수 있는 공개키로 구성됩니다.
디지털 서명의 주요 역할
-
데이터 무결성 보장
- 디지털 서명은 데이터가 전송 중 변경되지 않았음을 보장
- 서명을 생성할 때 데이터의 해시값이 사용되므로, 데이터가 변경되면 해시값도 달라져 서명이 무효
- 이를 통해 데이터가 위변조되었는지 확인할 수 있음
-
인증 (Authentication)
- 서명은 특정 개인이나 엔터티의 비밀키로만 생성 가능
- 수신자는 서명된 데이터를 공개키로 검증함으로써 서명자가 데이터를 생성했음을 확인 가능
- 예를 들어, 은행에서 보낸 디지털 서명된 문서는 수신자가 은행의 공개키로 검증할 수 있어, 문서의 출처를 확인할 수 있음
-
부인 방지 (Non-repudiation)
- 서명자는 자신의 비밀키로 데이터를 서명했기 때문에, 이후 서명 사실을 부인할 수 없음
- 이는 계약서나 법적 문서의 전자 서명에 매우 유용하며, 서명자가 데이터를 생성하고 보냈음을 증명하는 데 사용
디지털 서명의 작동 원리
디지털 서명은 대체로 다음 세 단계로 작동합니다.
-
서명 생성 (Signing)
- 서명자는 데이터를 해시 함수를 사용하여 고정된 길이의 해시값을 계산
- 계산된 해시값은 서명자의 비밀키로 암호화되어 서명을 생성
-
서명 전달 (Transmission)
- 서명자는 원본 데이터와 디지털 서명을 수신자에게 전송
-
서명 검증 (Verification)
- 수신자는 데이터를 해싱하여 새로운 해시값을 계산
- 서명은 서명자의 공개키로 복호화되어 서명 시 사용된 해시값을 복원
- 복원된 해시값과 새로 계산된 해시값이 일치하면, 데이터의 무결성과 서명자의 인증이 검증
디지털 서명의 구조
디지털 서명은 일반적으로 두 가지 구성 요소로 이루어져 있습니다.
-
개인키 (Private Key)
서명을 생성하는 데 사용되며, 서명자만이 알고 있는 비밀키
이 키는 절대로 다른 사람과 공유되어서는 안 됨
-
공개키 (Public Key)
서명을 검증하는 데 사용되며, 서명자가 다른 사람에게 공개할 수 있음
이 키는 데이터를 암호화하는 데 사용되지 않으므로, 공유해도 보안에 문제가 없음
디지털 서명의 주요 특징
-
안전성 (Security)
- 디지털 서명은 개인키와 공개키의 수학적 연관성을 기반으로 동작
- 개인키를 알지 못하면 애초에 서명을 위조할 수 없음
-
효율성 (Efficiency)
- 디지털 서명은 짧은 시간 안에 서명 생성 및 검증이 가능
- 네트워크와 컴퓨팅 리소스의 사용을 최적화
-
표준화 (Standardization)
- 디지털 서명은 다양한 표준 프로토콜(예: RSA, DSA, ECDSA)에 따라 설계되어 상호운용성이 뛰어남
디지털 서명의 응용 분야
-
전자 상거래
- 디지털 서명은 온라인 트랜잭션에서 고객과 판매자 간 신뢰를 구축하는 데 사용
-
전자 계약
- 디지털 서명은 법적 구속력이 있는 계약서에 사용되며, 계약 당사자의 인증과 계약 내용의 무결성을 보장
-
소프트웨어 배포
- 디지털 서명은 소프트웨어 개발자가 배포한 프로그램이 위변조되지 않았음을 보증하는 데 사용
-
정부 및 공공 서비스
- 전자 여권, 디지털 신분증, 전자 투표 시스템 등에서 디지털 서명이 사용
디지털 서명의 장점과 단점
장점 | 단점 |
---|
데이터의 인증 및 무결성을 보장 | 비밀키 유출 시 서명 위조 가능 |
서명자의 부인 방지 | 서명 생성 및 검증에 연산 자원이 필요 |
네트워크 및 데이터 저장 비용 절감 | 암호학적 안전성에 대한 의존 |
디지털 서명은 현대 정보사회에서 데이터의 신뢰성과 보안을 보장하기 위해 필수적인 기술로 자리 잡고 있습니다. ECDSA는 이러한 디지털 서명 기술 중 하나로, 높은 보안성과 효율성을 제공합니다.
1.2 ECDSA 개요
ECDSA(Elliptic Curve Digital Signature Algorithm)는 디지털 서명의 한 형태로, 기존의 DSA를 타원 곡선 암호학으로 확장한 알고리즘입니다. 주요 장점은 다음과 같습니다.
- 짧은 키 크기: 동일한 보안 강도를 유지하면서 기존 DSA나 RSA보다 훨씬 짧은 키 크기를 가짐
- 높은 성능: 키 생성, 서명, 검증 속도가 빠름
- 효율적 저장: 짧은 키 크기로 인해 메모리 및 대역폭 효율성이 높음
ECDSA는 타원 곡선의 군 연산을 기반으로 동작하며, 암호학적 안전성을 제공합니다.
2. 타원 곡선 암호학 기초
2.1 타원 곡선이란?
타원 곡선은 다음과 같은 형태의 방정식으로 정의됩니다.
y2=x3+ax+b
여기서 a와 b는 곡선의 형태를 결정하는 파라미터이며, x와 y는 곡선 위의 점을 나타냅니다.
- a, b: 곡선의 형태를 결정하는 상수
- x, y: 곡선 위의 점을 나타내는 좌표
- p: 소수(Prime Number)로, 유한체에서의 계산을 위해 사용
타원 곡선은 암호학에서 다음과 같은 특성을 가집니다.
-
대칭성:
- 타원 곡선 위의 모든 점 P(x,y)P(x, y)P(x,y)에 대해 P′(x,−y)P'(x, -y)P′(x,−y)도 곡선 위에 존재
- 이 두 점은 xxx-축에 대해 대칭
-
곡선 위의 점들의 연산 가능:
- 곡선 위의 점들은 특정 연산 규칙을 통해 새로운 점을 생성할 수 있음
- 이러한 연산은 암호학의 핵심
-
암호학적 응용:
- 타원 곡선은 키 크기에 비례하여 높은 보안성을 제공
- 상대적으로 작은 키 크기로도 RSA와 같은 기존 암호 알고리즘과 비슷한 수준의 보안을 제공
2.2 군 이론과 타원 곡선
군(Group)의 정의
군은 수학적 구조로, 다음과 같은 성질을 만족하는 집합과 연산의 쌍입니다:
- 폐쇄성: 두 원소의 연산 결과가 항상 집합의 원소입니다.
- 결합법칙: 연산은 결합법칙을 만족합니다.
(a+b)+c=a+(b+c)
- 항등원 존재: 집합에는 항등원이 존재하며, 연산 후 원소가 변하지 않습니다.
- 역원 존재: 각 원소는 자신의 역원이 존재하여, 연산 결과가 항등원이 됩니다.
타원 곡선 위의 점들로 이루어진 군
타원 곡선 위의 점들은 군의 성질을 가집니다. 여기서 연산은 점 덧셈(Point Addition)과 점 두 배(Point Doubling)로 정의됩니다.
곡선 위의 점들과 군 연산은 암호학적 작업의 기본 단위입니다.
-
덧셈 연산 (Point Addition):
두 점 P(x1,y1),Q(x2,y2)에 대해, R=P+Q는 다음과 같이 계산됩니다:
- 기울기: m=x2−x1y2−y1(modp)
- 새로운 점: x3=m2−x1−x2(modp),y3=m(x1−x3)−y1(modp)
-
점 두 배 (Point Doubling):
점 P(x1,y1)에 대해 R=2P는 다음과 같이 계산됩니다:
- 기울기: m=2y13x12+a(modp)
- 새로운 점: x3=m2−2x1(modp),y3=m(x1−x3)−y1(modp)
-
스칼라 곱 (Scalar Multiplication):
- k⋅P: 점 P를 k번 더한 결과입니다.
- 이 연산은 효율적으로 계산하기 위해 Double-and-Add Algorithm 같은 방법이 사용됩니다.
2.3 유한체(Galois Field)에서의 타원 곡선
유한체 GF(p)
유한체는 정수 집합 {0,1,2,...,p−1}에서 덧셈과 곱셈을 모듈로 p 연산으로 정의한 체(Field)입니다. 여기서 p는 소수(Prime Number)여야 하며, 연산 결과는 항상 p로 나눈 나머지가 됩니다. 즉,
-
덧셈:
(a+b)modp
-
곱셈:
(a⋅b)modp
-
역원:
a에 대해 b가 존재하여 a⋅b≡1(modp)
유한체에서의 타원 곡선
암호학에서는 유한체 GF(p) 위에서 타원 곡선을 정의합니다. 유한체를 사용하면 타원 곡선 위의 점의 개수가 유한하며, 이 점들의 집합으로 군을 형성할 수 있습니다.
-
곡선의 정의:
y2≡x3+ax+b(modp)
-
곡선 위의 점들:
모든 가능한 x,y∈GF(p)를 대입하여 방정식을 만족하는 점들을 찾습니다.
-
군의 크기 (Order):
곡선 위의 점들의 총 개수는 군의 크기로, 곡선의 보안 강도에 직접적인 영향을 미칩니다.
타원 곡선 난이도 문제 (ECDLP)
타원 곡선 암호학의 보안은 타원 곡선 이산 로그 문제 (Elliptic Curve Discrete Logarithm Problem, ECDLP)에 기반합니다:
- P,Q∈E(Fp)에 대해, Q=k⋅P일 때, k를 구하는 것은 매우 어렵습니다.
이 문제의 계산 복잡도는 기존의 이산 로그 문제보다 훨씬 높아, 같은 보안 강도를 가진 암호 알고리즘에서 필요한 키 크기를 크게 줄일 수 있습니다. 예를 들어, 256비트의 타원 곡선 암호는 약 3072비트의 RSA 키와 비슷한 보안을 제공합니다.
3. ECDSA의 수학적 원리
c.f: https://blog.naver.com/aepkoreanet/221178375642
3.1 주요 구성 요소
-
타원 곡선 파라미터:
- p: 소수 체(모듈러스)
- a,b: 곡선의 정의
- G: 기본점(Generator Point)
- n: 기본점의 순환군의 크기(Order)
-
키 구성:
- 개인키 d: 임의의 정수 1≤d<n
- 공개키 Q:Q=d⋅G, 개인키에 기본점을 곱한 값
3.2 서명 생성 과정
- 메시지 해싱:
- 메시지 M을 SHA-256 등으로 해싱하여 h 생성.
- 랜덤 Nonce k 생성:
- k는 서명 과정에서 매번 새롭게 생성되는 난수
- 서명 값 계산:
- R=k⋅G,r=x 좌표 of R
- s=k−1⋅(h+r⋅d)modn
- 최종 서명은 (r,s)
3.3 서명 검증 과정
- 입력:
- 계산:
- u1=h⋅s−1modn,u2=r⋅s−1modn
- V=u1⋅G+u2⋅Q
- 검증: r=?x 좌표 of V
3.4 취약점
- Nonce k의 재사용:
- 동일한 k로 다른 메시지를 서명하면 d를 복구 가능
- Nonce k의 상관관계:
- k가 결정론적으로 생성되거나 일부 노출되면 공격 가능
4. 문제 분석
4.1 랜덤 Nonce k 생성 취약점
문제에서 k는 다음과 같이 생성:
k=mul⋅k+inc
여기서 mul과 inc는 고정된 값이라고 가정하면 k가 난수처럼 보이지만 결정론적 관계를 가지므로 k 간의 상관관계를 분석할 수 있을 것
5. 수학적 풀이
5.1 Nonce 재사용 공격
두 개의 서명 (r1,s1),(r2,s2)가 동일한 k로 생성되었다면, 다음 관계를 이용해 d를 복구할 수 있을 것
d=s2⋅r1−s1⋅r2s1⋅h2−s2⋅h1modn
6. 학습 내용 요약
- ECDSA의 강점: 짧은 키 크기와 효율적인 서명/검증 속도.
- 취약점: Nonce k의 안전한 생성이 중요.
- 학습 방향:
- 타원 곡선 암호학 심화 학습
- SageMath를 활용한 자동화된 분석