見出し画像

#45 Caesar Cipher

 来週資格の試験があります。コツコツ勉強してきましたが、いつだって試験は不安です。あと一週間集中していきます。

 それはさておき、CTFをやっていると必ず暗号の問題がでてきます。なんとなく苦手意識があったので、基礎から固めていこうと思っています。とりあえず、有名なシーザー暗号から。

目標

シーザー暗号を理解する。

シーザー暗号で暗号化・復号を行うプログラムを書いてみます。

作業

シーザー暗号について

 シーザー暗号とは、かの有名な古代ローマのジュリアス・シーザーが使ったと言われる暗号です。仕組みは非常に単純で、平文を1文字ずつ、アルファベットの辞書順にずらすことで暗号化します。例えば、「ABC」の各文字を3文字ずつずらすと、「DEF」になりますね。同様に、「Caesar」は、「Fdhvdu」のような文字列になり、一見なにやらわかりません。復号するときは、同じ数だけ逆方向にずらせばよいので、単純です。
 このとき、ずらした幅である「3」は暗号鍵と呼べるでしょう。この鍵さえ共有していれば、秘密のメッセージをやりとりできます。逆にいえば、鍵が漏れてしまうと、メッセージも簡単に復号できてしまいます。


プログラムの作成


 仕組みがわかったところで、プログラムを組んでみましょう。Pythonです。

class Caesar():
    #文字の一覧。この中に含まれる文字のみ扱える
    ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 -_=+[]{};:'\"\\|,.<>/?!@#$%^&*()"

    def __init__(self, key):
        # 暗号鍵を設定する
        self.key = key

    # 暗号化する
    def encrypt(self, message, key=None):
        result = self.translate(message, key, decrypt=False)

        return result

    # 復号する
    def decrypt(self, message, key=None):
        result = self.translate(message, key, decrypt=True)

        return result

    # シーザー暗号で文字列を変換する
    def translate(self, message, key=None, decrypt=False):
        if key == None:
            key = self.key
        result = ""
        for char in message:
            original = self.ALPHABET.find(char)
            # 文字が一覧にないときはスキップ
            if original < 0:
                print("[!] Cannot process '" + char + "'. Skip.")
                continue
            # 変換後の文字の位置
            mod = (key % len(self.ALPHABET))
            if decrypt:
                index = original - mod
                if index < 0:
                    index += len(self.ALPHABET)
            else:
                index = original + mod
                if index > len(self.ALPHABET):
                    index -= len(self.ALPHABET)
            result += self.ALPHABET[index]
        return result

試してみます。

if __name__ == "__main__":

    caesar = Caesar(3)

    message = "test"
    encrypted = caesar.encrypt(message)
    print("暗号文: " + encrypted)

    decrypted = caesar.decrypt(encrypted)
    print("復号: " + decrypted)
$ python3 caesar.py 
暗号文: whvw
復号: test

ちゃんと暗号化・復号できました。!

弱点

 ご覧のように、シーザー暗号は単純な仕組みなので、簡単に破れてしまいます。まず、暗号鍵の種類が少ないのは問題です。今回作成したプログラムでは、アルファベットの大文字・小文字と数字、記号を扱っていて全部で93あります。93文字ずらしたらもとの文字に戻ってきてしまうので、使える暗号鍵は、93パターンということになります。全暗号鍵を試すのは容易いことです。

先程のプログラムの"Caesar"クラスにメソッドを追加します。

    # 全パターン試す
    def bruteforce(self, message):
        result = []
        for i in range(len(self.ALPHABET)):
            decrypted = self.decrypt(message, key=i)
            result.append((i, decrypted))

        return result

このメソッドで、暗号文「1[].D].D._ ,_<Y」を解読してみると…

if __name__ == "__main__":

    caesar = Caesar(0)

    encrypted = "1[].D].D._ ,_<Y"

    result = caesar.bruteforce(encrypted)
    for i in result:
        print(str(i[0]) + ": " + i[1])
$ python3 caesar.py
0: 1[].D].D._ ,_<Y
1: 0+[,C[,C,-9|-.X
2: z=+|B+|B| 8\ ,W
3: y_=\A=\A\97"9|V
...
31: Wklv=lv=vhfuhw$
32: Vjku_ku_ugetgv#
33: Uijt-jt-tfdsfu@
34: This is secret!
35: Sghr9hr9rdbqds?
36: Rfgq8gq8qcapcr/
...

暗号鍵34のときに、それっぽい文章ができています!このように、総当りで復号できてしまうとなると、大事な情報は扱いたくありませんね…


まとめ

 シーザー暗号のプログラムを作ってみました。現代ではあまり使われていない古典暗号のひとつですが、暗号の入口としては面白いものかなと思います。現代のインターネットを支える、公開鍵暗号のような複雑な技術にも踏み込んでいけるよう、少しずつ勉強していきます。

EOF


この記事が気に入ったらサポートをしてみませんか?