Pythonとシーザー暗号

シーザー暗号とは

シーザー暗号とは最も単純な暗号化技術でカエサル(英語名でシーザー)がよく用いていた暗号としてこの名がつきました。また、別名としてシフト暗号と呼ばれ名前の通り文字を同じ数だけずらしたものです。
例えば「ABC」とい文字列があるとすればそれらを左に3つずらすと「XYZ」になりますね。これがシーザー暗号です。今回はこの暗号化技術をプログラミングで実装してみたいと思います。もしこれができれば友達にシーザー暗号を送りつけることができますね。

基本的にどんなプログラミング言語でも実装可能ですが今回はPythonで挑戦していきます。

Pythonでシーザー暗号を記述

def encrypt(str, num):
    ciphertext = ""

    for cha in list(str):
        if 'A' <= cha <= 'Z':
            ciphertext += chr((ord(cha) - ord('A') + num) % 26 + ord('A'))
        elif 'a' <= cha <= 'z':
            ciphertext += chr((ord(cha) - ord('a') + num) % 26 + ord('a'))
        else:
            ciphertext += cha

    return ciphertext

if __name__ == '__main__':
    plaintext = input("暗号化したい文章: ")
    num = input("シフト数 : ")
    ciphertext = encrypt(plaintext, int(num))

    print("暗号文 : " + ciphertext)

上のようなプログラムを作ってみました。
上から順番に見ていきます。

def encrypt(str, key):
    ciphertext = ""

とりあえず暗号化するための関数をencypt()と定義します。暗号化したい文字列をstr、シフトする数をnumとして引数を用意しました。
次に英語で暗号文を意味するciphertextを定義しました。しかしよく見たら定義したはいいものの中身がありませんね。実は今回のプログラムのフローチャート的に空にしておく必要があります。この後、一文字ずつ文字を置換していきこのciphertextに入れていきます。つまりこれは入れ子としての役割を担っています。

    for cha in list(str):
        if 'A' <= cha <= 'Z':
            ciphertext += chr((ord(cha) - ord('A') + num) % 26 + ord('A'))
        elif 'a' <= cha <= 'z':
            ciphertext += chr((ord(cha) - ord('a') + num) % 26 + ord('a'))
        else:
            ciphertext += cha

次に文字を一つずつ取り出し置換していくために繰り返し処理(for文)を用いました。list()関数を使って暗号化したい文章を一文字ずつリストに入れていきます。そのリストから一文字ずつ取り出して別のもじに置換していきます。

繰り返し処理の中身としては条件分岐(if文)を使って大文字か小文字かで分別し別々の処理を行なっています。なぜ条件分岐しなければいけないかという説明は後ほどしていきます。

ciphertext += chr((ord(cha) - ord('A') + num) % 26 + ord('A'))

このコードについてできるだけ簡単に説明していきます。このコードは主にchr()関数とord()関数がメインとなっています。この二つの関数は文字とアスキーコードを相互変換してくれます。アスキーコードとは文字の整理番号のようなものでこれを使うことで文字から数字に変換できます。

つまり ord(cha) は cha のアスキーコードを表しています。これにシフトさせたい文字数を足したり引いたりすればいいわけですね。

しかしそう簡単にはいきません。なぜなら「a」の一個前は「z」でなくてはいけません。よってこのような剰余を利用したアルゴリズムになるわけですね、。また、大文字と小文字で条件分岐する理由もこれでわかると思います。アスキーコード表を実際に見てもらえればわかると思いますがアルファベットの場合は大文字の次に小文字が来ています。なので条件分岐をしないと暗号化したときに勝手に大文字や小文字に変換されてしまいうまく実行できなくなってしまいます。

if __name__ == '__main__':
    plaintext = input("暗号化したい文章: ")
    num = input("シフト数 : ")
    ciphertext = encrypt(plaintext, int(num))

    print("暗号文 : " + ciphertext)

最後にこのコードについて説明していきます。
if __name__ == ‘__main__’: の以下の部分が実行する内容になります。

暗号化してみる

こんな感じでうまく暗号化に成功しました。