이 글은 암호학 교육 및 온라인 저지를 제공하는 사이트 cryptohack.org의 입문 코스인 "Introduction to Cryptohack"의 요약 과 번역 및 간단한 역자의 풀이를 적은 글입니다.
Overview
암호학(Cryptography)에 입문을 돕습니다. 이 장에서는 암호학에서 흔히 쓰이는 데이터 타입간의 인코딩과 디코딩을 배웁니다. 그 뒤, 대칭키 암호 시스템(Symmetric cryptosystem)의 중심에 있는 배타적 논리합(eXclusive OR; XOR) 연산을 쉽게 받아들일 것입니다. 마지막으로, 장의 끝에는 재밌는 XOR 퍼즐로 실력을 테스트합니다.
Introduction - Challenges
Finding Flags
문제를 해결하려면 'Flag'를 찾아야 합니다. 이러한 'Flag'는 crypto{...}
형식으로 주어집니다. 이 'Flag'를 제출하면 채점받을 수 있습니다.
Great Snakes
현대 암호학에서는 코드가 수반됩니다. 가장 추천하는 언어는 python3입니다. 암호화 스크립트와 공격을 빠르게 작성할 수 있어 좋습니다. 왜 그런지는 FAQ를 참고하면 알 수 있습니다.
문제에서 주어진 코드를 받은 뒤 실행시키면 'Flag'를 찾을 수 있습니다.
General - Encoding
ASCII
ASCII 코드는 8비트 부호 있는 정수로, 0~127 사이의 정수를 사용하여 문자를 표현합니다. 문제에서 주어진 정수 배열을 속 ASCII 코드 들을 ASCII 문자로 변환시키면 'Flag'를 찾을 수 있습니다.
chr()
함수는 정수 ASCII 코드를 대응되는 ASCII 문자로 변환합니다. 반대로,ord()
함수는 문자에서 코드로 변환합니다.
Hex
실제로 암호화 시에 생성되는 암호문(Ciphertext)은 출력 가능한 ASCII 문자가 아닌 비트열(Bytes)로 표현됩니다. 왜냐하면 데이터 공유 시 더 사용하기 수월하고 휴대하기 쉬워야 하기 때문입니다.
문제에 주어진 'Flag'는 16진 문자열(Hex string)으로 인코딩(Encoding)되어 있습니다. 이를 디코딩(Decoding)하여 비트열로 변환해 'Flag'를 얻으세요.
bytes.fromhex()
함수는 16진 문자열을 비트열로 변환합니다. 반대로,.hex()
메소드는 비트열을 16진 문자열으로 변환합니다.
Base64
또다른 인코딩 방식으로는 Base64가 있습니다. 이는 64가지의 문자를 이용하여 ASCII 코드를 표현합니다.
따라서 [Base64 1문자 : 6bit 비트열 1개 = Base64 4문자 : 24bit 비트열 1개 = Base64 4문자 : 8bit 비트열 3개]로 대응됨을 알 수 있습니다.
Base64는 온라인에서 가장 많이 사용되는 형태이다. 대표적으로 이미지가 Base64 형태로 쓰입니다.
주어진 16진 문자열을 비트열로 디코딩 한 뒤 Base64로 인코딩하세요.
import base64
구문을 통해base64
모듈을 불러온 뒤,base64.b64encode()
함수를 사용할 수 있습니다.
주의: 이 문제는 'Flag'가base64
문자열 형태입니다.
Bytes and Big Integers
RSA와 같은 암호 시스템은 '수'로 작동하지만 메시지는 '문자'로 구성됩니다. 수학적 연산을 적용하기 위해 메시지를 '수'로 변환시켜야 합니다.
가장 일반적으로 변환시키는 방법은 메시지를 16진수로 변환하는 것입니다. 이것은 16진법으로 표현할 수도 있고, 10진법으로 표현할 수도 있습니다.
message: HELLO
ascii bytes: [72, 69, 76, 76, 79]
hex bytes: [0x48, 0x45, 0x4c, 0x4c, 0x4f]
base-16: 0x48454c4c4f
base-10: 310400273487
PyCryptodome 라이브러리에는Crypto.Util.number.bytes_to_long()
과Crypto.Util.number.long_to_bytes()
메소드가 있습니다. 물론 코드 상단에는from Crypto.Util.number import *
구문을 작성해줍니다.
General - XOR
XOR Starter
XOR은 같으면 $0$, 다르면 1을 반환하는 비트 연산자입니다. 보통 수식적으로는 $\oplus$로, 프로그래밍 언어에서는 ^
로 표기합니다.
10진수를 2진수로 변환하면 XOR을 다룰 수 있습니다. 먼저 각 문자를 Unicode 문자를 나타내는 정수로 변환하여 XOR 문자열을 만들 수 있습니다.
문제: 문자열 "label"의 각 문자에 $13$을 XOR 취한 문자열이 플래그입니다. 플래그를 찾으세요.
* pwntools
의 xor
함수를 이용하면 쉽게 구현할 수 있습니다.
* 역자: ascii code는 unicode의 부분집합입니다.
from pwn import *
print("crypto{"+str(xor('label',13),"UTF-8")+"}")
XOR Properties
XOR은 교환법칙과 결합법칙이 성립하고, $0$을 항등원으로 갖는 이항 연산입니다.
또한, 역원이 자기 자신이라는 특성이 있습니다. 구체적으로, $A\oplus A=0$이 성립합니다.
문제: KEY1, KEY2 ^ KEY1, KEY2 ^ KEY3, FLAG ^ KEY1 ^ KEY3 ^ KEY2가 주어질 때, 플래그를 찾으세요.
from Crypto.Util.number import *
KEY1 = bytes_to_long(bytes.fromhex("a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313"))
KEY2 = KEY1 ^ bytes_to_long(bytes.fromhex("37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e"))
KEY3 = KEY2 ^ bytes_to_long(bytes.fromhex("c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1"))
FLAG = bytes_to_long(bytes.fromhex("04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf")) ^ KEY1 ^ KEY2 ^ KEY3
print(str(long_to_bytes(FLAG),"UTF-8"))
Favorite byte
문제: 암호문이 주어집니다. 플래그를 찾으세요.
'Flag'의 형식을 맞추기 위해 앞부분은 "crypto{"가 되어야 한다는 점을 고려해 확인해보면, 전부 16으로 이루어졌음을 알 수 있습니다.
from Crypto.Util.number import *
from pwn import *
Bytes = bytes.fromhex("73626960647f6b206821204f21254f7d694f7624662065622127234f726927756d")
for b in Bytes:
print(chr(b^16),end='')
You either know, XOR you don't
문제: 암호문이 주어집니다. 플래그를 찾으세요.
직전 문제와 유사한데, key가 적용되는 패턴이 있다는 걸 찾아서 풀 수 있습니다.
from Crypto.Util.number import *
from pwn import *
Bytes = bytes.fromhex("0e0b213f26041e480b26217f27342e175d0e070a3c5b103e2526217f27342e175d0e077e263451150104")
Key = [109,121,88,79,82,107,101,121]
i = 0
for b in Bytes:
print(chr(b^Key[i%8]),end='')
i += 1
'기타' 카테고리의 다른 글
KOI 고등부 Checklist (0) | 2022.05.16 |
---|---|
PS 관련 이모저모 및 상반기 목표 (0) | 2022.05.15 |
H4CKING GAME (0) | 2022.03.20 |
kmo 오일러 1차 (0) | 2021.06.11 |
맥북 누전..! (2) | 2021.05.18 |