Tuesday, June 9, 2015

Project Euler #59 - XOR 암호 해독

프로젝트 오일러 59번 - XOR decryption
이진수로 된 문자열 '10011101'을 '0101'이라는 key를 이용해서 XOR 암호화한다고 하자.
우선 앞부분 1001 과 key를 비교하면 1100 이 된다.(XOR은 같으면 0, 다르면 1로 만든다)
뒷부분 1101 과 key를 비교하면 1000 이 된다.
그래서 10011101 을 암호화하면 11001000이 된다. 
같은 방법으로, 11001000 을 '0101'로 XOR연산을 하면, 10011101 이 되어 암호를 풀게 된다.
key가 3자리 소문자 알파벳일 때 첨부한 파일의 암호를 풀고, 풀린 텍스트의 ASCII값을 모두 더하라.

1. 암호를 찾는다.
1) (1,4,7,10, ... 자리의 문자), (2,5,8,... 자리의 문자), (3,6,9,...자리의 문자)를 나눈다. 이들 각각에 대하여,
2) 모든 소문자에 대하여, 암호가 a일 때 '풀린 문자'가 정상적인 영어 알파벳인 개수, ...., 암호가 z일 때... 를 센다. 정상적인 영어 알파벳이 가장 많은 경우를 암호로 본다. 
2. 암호를 푼다.

#ord('A')=>65, ord('Z')=>90, ord('a')=>97, ord('z')=>122, ord(' ')=>32, ord('.')=>46
eng = set(range(65,91)+range(97,123)+[32,46])
encrypted = [int(x) for x in open('p059_cipher.txt').read().split(',')]
passwd = []
for i in range(3):
    enc3=[x for k,x in enumerate(encrypted) if k%3==i]
    tmpdic = {}
    for pw in range(97,123):
        tmpdic[pw] = len([x^pw for x in enc3 if x^pw in eng])
    passwd.append( max(tmpdic, key=tmpdic.get))

decrypted = [x^passwd[k%3] for k, x in enumerate(encrypted)]
#print passwd
#print ''.join([chr(x) for x in decrypted])

print sum(decrypted)

암호는 'god' (103,111,100), 암호화된 본문은 요한복음 1장 앞부분이다.
ord는 22번에서 나왔던 함수.
XOR은 컴퓨터에는 기본적인 연산이라 간단히 쓰는 방법이 있을 듯 했다. 역시나 구글링해보았더니 ^를 쓰면 된다고 한다. 어려워 보였지만, 보기만큼 어렵지는 않았다.

No comments: