シーザー暗号についてわかりやすく解説!

caesar-cipher

シーザー暗号は、最も単純な暗号のひとつです。そのため、情報系の学生の多くは学部生のうちに授業等で耳にするでしょう。この記事では、具体的なアルゴリズムや実装方法についてもわかりやすく解説していきます。

シーザー暗号とは

シーザー暗号は単純なアルゴリズムに基づいた古典暗号のひとつです。カサエル式暗号、シフト暗号とも呼ばれます(カサエルは英語読みでシーザーになります)。

シーザー暗号は、一言で言うと「文字をいくつか次の文字にずらす」ことで暗号化を行います。例えば、Aというアルファベットを二つ次にずらすとCになります。小文字の場合も同様です。

caesar-shift-1

また、Zを二つ次にずらす場合は、Bになります(Zの次には再びABC…と続くものと考えているためです)。

caesar-shift-1

以降では、この”ずらす”を”シフトする”と言うことにします。また、「二つずらす」は「2シフトする」と言うことにします。

このようなシフトを、共通のシフト数(鍵)を使用して全ての文字に行うことで暗号化を行います。一文字目をシフト数5でシフトしたなら、二文字目以降も同様に5シフトする必要があります。

シーザー暗号の特殊系であるROT13についての記事も書いているので、よければご覧ください。

暗号化の手順

平文(暗号化される前の文字列)の全てのアルファベットをnシフトすることで暗号化します。ここで、nは暗号化を行う人が自分で決める数値です。3や13が利用されることが多いです。ここで決めたnは、複合をする際にも同じ値を利用します。

具体例を考えてみます。”The quick brown fox jumped over the lazy dogs”という平文をシフト数3で暗号化してみましょう。”T”は(→”U”->”V”→”W”なので)”W”になり、”h”は”k”になります。他の文字も同様にずらしていくと最終的には”Wkh txlfn eurzq ira mxpshg ryhu wkh odcb grjv“になります。

caesar-encode

複合の手順

複合は、暗号化された文と鍵を用いて暗号化される前の平文を獲得することを指します。シーザー暗号の場合は鍵がシフト数になります。

シーザー暗号の複合は、暗号化時にシフトした分だけ反対にシフトすることで行います。2シフトで暗号化したなら-2シフトすれば良いわけです。

Wkh txlfn eurzq ira mxpshg ryhu wkh odcb grjv“という暗号文があった場合に、鍵(シフト数)が3だとわかっていれば文字を逆方向に3シフト(-3シフト)することで元の文である”The quick brown fox jumped over the lazy dogs”が得られます。

caesar-decode

問題点

拡張することは可能ですが、基本的にはアルファベット部分しか暗号化できません。また、暗号としての強度は非常に低く、シフト数としてあり得る数を全部試してみると平文が簡単にわかってしまいます。

Pythonを用いた実装例

Pythonを使用して、シーザー暗号を実装する際の例を以下に示します。バージョンは3.xであることを想定しています。

def is_upper(c):
    return ord('A') <= ord(c) and ord(c) <= ord('Z')


def is_lower(c):
    return ord('a') <= ord(c) and ord(c) <= ord('z')


def shift(c, k):
    if is_upper(c):
        return chr((ord(c) - ord('A') + k) % 26 + ord('A'))
    elif is_lower(c):
        return chr((ord(c) - ord('a') + k) % 26 + ord('a'))
    else:
        return c


def caesar(s, k, decode=False):
    if decode:
        k = -k
    return "".join([shift(c, k) for c in s])


key = 3
text = "The quick brown fox jumped over the lazy dogs"
print(text)
enc = caesar(text, key)
print(enc)
print(caesar(enc, key, decode=True))

is_upper関数は与えられた文字がアルファベットの大文字であるかどうかを判定します。それに対して、is_lower関数は文字が小文字であるかどうかを判定します。

コンピューター上では文字コードという数字と文字の対応表を用いて文字を管理しています。Pythonの組み込み関数であるordは文字を与えると文字コード上での数値を返してくれます。反対に、chrは文字コード上での数値を与えると対応する文字を返します。

一般にアルファベットの小文字”a”から”z”は文字コード上の数値として連続しており、”A”から”Z”も同様に連続しています。そのため、数値としての大小関係を用いて小文字であるか大文字であるかを判定しています。ちなみに、Pythonにはstr.isupperstr.islowerといった同等のことをする関数もあるのでそちらを利用することもできます。

shift関数は、指定した数だけ文字をシフトする関数です。入力文字を文字コード上の数値に一度変換し、シフト数を加算した後文字に戻すという処理を行なっています。”z”→”a”のように循環をさせるために26で割った余りを計算しています。割る数字が26なのは、”a”から”z”までが26文字だからです。アルファベットの小文字でも大文字でもない文字(スペースなど)はそのまま返されます。

caesarは、実際にシーザー暗号の暗号化・複合をするときに呼ぶ関数です。デフォルトでは暗号化を行い、引数としてdecode=Trueが渡される場合は複合を行います。複合時にはシフト数をマイナスにしています。処理内容は、上記のshift関数を入力される全ての文字に対して適応して返すだけです。