The Early School
Crypto
Description:Welcome to ASIS Early School.
#!/usr/bin/pythonfrom Crypto.Util.number import *from flag import FLAG, rounddef encrypt(msg):assert set(msg) == set(['0', '1'])enc = [msg[i:i+2] + str(int(msg[i]) ^ int(msg[min(i+1, len(msg)-1)])) for i in range(0, len(msg), 2)]return ''.join(enc)ENC = bin(bytes_to_long(FLAG))[2:]for _ in xrange(round):ENC = encrypt(ENC)fp = open('FLAG.enc', 'w')fp.write(long_to_bytes(int(ENC, 2)))fp.close()
このPythonプログラムの処理の内容は次のようなものです。
- FLAG文字列を2進数の文字コードで表す。
- それをencrypt関数に渡して暗号化する操作をround回行う。
- encrypt関数では渡された2進文字列を先頭から2文字ずつ処理を行う。
- その2文字を1文字に分けてそのXORを取った結果を連結して3文字の文字列にする。
- 2文字ずつ処理を行う際、最後に1文字だけ残った場合はその1文字どおしのXORを取った結果(つまり0)を連結した2文字になる。
- それらを連結した結果をencrypt関数の戻り値とする。
具体的な例で確認すると、元のデータが'A'という文字列とすると、まず2進数文字列で表した1000001
をencrypt関数に渡します。2文字ずつ処理するので、10 00 00 1に分割して処理します。XORを取った結果を付加するので、101 000 000 10になります。
したがって、この暗号を復号するdecrypt関数は、次のような処理になります。
- 2進文字列を3文字ずつ区切って処理をする。
- 3文字目は不要なので切り捨てて2文字だけを残す。
- 最後が2文字になったときは、2文字目は不要で、1文字目だけ残す。
- 残したものを連結したものが復号結果となる。
roundの値は分からないので、decryptを繰り返し、先頭がフラグ形式のA=1000001になった時点でデータを表示するようにしてみます。
#!/usr/bin/pythonfrom Crypto.Util.number import *def decrypt(enc):msg = [enc[i:min(i+2, len(enc)-1)] for i in range(0, len(enc), 3)]return ''.join(msg)fp = open('FLAG.enc', 'r')FLAG = fp.read()fp.close()ENC = bin(bytes_to_long(FLAG))[2:]i = 1while True:ENC = decrypt(ENC)print(i)if ENC.startswith('1000001'):print(long_to_bytes(int(ENC, 2)))breaki += 1
実行すると次のような結果となります。
19回繰り返したところでフラグを得ることができました。$ python2 bbb.py12345678910111213141516171819ASIS{50_S1mPl3_CryptO__4__warmup____}
フラグは、
ASIS{50_S1mPl3_CryptO__4__warmup____}です。