知ることは、たのしい。

入門レベルの情報系学生が勉強する。同じ分野に初めて興味を持った人への参考になればいいなあ

シーザー暗号を解きながらpythonの勉強

CTFに限ったことではないのですが、同じことをするのに何度も検索したり頭をつかうのは資源の無駄なので
我らがコンピュータに仕事してもらいたいと思います。

シーザー暗号

シーザー暗号は端的にいうと平文を何文字かずらす暗号です。
復号するにはずらされた文字数分戻してあげればよいです。

解き方

sedコマンドを使うことで簡単に求まります。 試しに"Hello world" を3文字手前にずらした"Ebiil Tloia"を復号してみると、

$ echo "Ebiil Tloia" | sed -e 'y/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/defghijklmnopqrstuvwxyzabcDEFGHIJKLMNOPQRSTUVWXYZABC/'
Hello World

コマンドについては以前紹介しているので割愛。
このアルファベットを入力するのが手間なのでプログラム書きました。

pythonで解く

調べつつ学んだこともまとめていきたいと思います。
やっぱりリファレンスは優秀。組み込み関数便利。

rot_n.py

# $ python rot_n.py s rot
import sys

def rot_n(c, n):
    if 'a' <= c and c <= 'z':
        return chr((ord(c) - ord('a') + int(n)) % 26 + ord('a'))
    
    if 'A' <= c and c <= 'Z':
        return chr((ord(c) - ord('A') + int(n)) % 26 + ord('A'))
    
    return c

def rot(s, n):
    c = (rot_n(c, n) for c in s)
    print ''.join(c)

if __name__ == '__main__':
    param = sys.argv
    s = param[1]
    rot = param[2]
    rot(s, rot)

実行結果

$ python rot_n.py  'Ebiil, Tloia' 3
Hello, World

解説

import sys : コマンドライン引数を取得する(sys.argv)のに必要
ord(c) : 文字cの文字コードを返す
chr(n) : 文字コードnに対応する文字を返す
if文を大文字と小文字で分けているのは文字コードが連続していないためです。
(rot_n(c, n) for c in s) : ジェネレータ式(不勉強なためまだ理解してないです) リストを作らない分メモリに優しいらしい
''.join(c) : これはリストなどを''ではさまれた文字でつなげます。今回は''なのでリストcのすべての要素を連結させます。

勉強すればするほど洗練されたコードが書けそうな予感。pythonいいね

追記

def rot(s, n)はイマイチ理解していない方法を使わなくても一文字ずつ復号して連結していけば良いのでこんな感じに出来ます。

def rot(s, n):
    plain = ''
    for c in s:
        plain += _rot(c, n)
    print plain