Pythonでヴィジュネル暗号


はじめに

ヴィジュネル暗号に関するPythonスクリプトを探しても、非効率的なものしか見つけられなかったため、自分が効率の良いと思うコードを書いた。

基本方針

ヴィジュネル暗号は、ヴィジュネル方陣を参照して暗号化と復号を行う。
ただし、ヴィジュネル方陣はkey毎に参照先をずらしているだけなため、方陣を作成する必要はない。この方陣を作成しているものしか見つからなかったため、今回の投稿に至る。

コード抜粋

def vigenere_encrypt(plaintext, key):
    """Vigenere Cipher Encrypt
    key are only UPPERCASE ALPHABET[A-Z]."""
    count = 0
    ciphertext = ''
    key = key.upper()
    for s in plaintext:
        if s.isupper():
            ciphertext += chr(((ord(s) + ord(key[count % len(key)])) % 26) + ord('A'))
        elif s.islower():
            ciphertext += chr(((ord(s) + ord(key[count % len(key)]) - (ord('a') - ord('A'))) % 26) + ord('a'))
        else:
            ciphertext += s
        count += 1
    return ciphertext

def vigenere_decrypt(ciphertext, key):
    """Vigenere Cipher Decrypt
    key are only UPPERCASE ALPHABET[A-Z]."""
    count = 0
    plaintext = ''
    key = key.upper()
    for s in ciphertext:
        if s.isupper():
            plaintext += chr(((ord(s) - ord(key[count % len(key)])) % 26) + ord('A'))
        elif s.islower():
            plaintext += chr(((ord(s) - ord(key[count % len(key)]) - (ord('a') - ord('A'))) % 26) + ord('a'))
        else:
            plaintext += s
        count += 1
    return plaintext

コード解説

ヴィジュネル方陣について

以下にヴィジュネル方陣を示す。

出典:
Vigenère cipher - Wikipedia

ヴィジュネル方陣は、縦軸をKey, Aを0, Zを25とすると、
Keyの値を平文字(横軸)に自身を足し、26の法を取ったものが暗号化後の文字になるようになっている。
A...ZA...ZA...Zと続く文字列の中で、Keyの値を足したものだと考えたほうがわかりやすい方もいるかもしれない。

手作業でのヴィジュネル暗号の暗号化方法

例として、暗号鍵を「QIITA」、平文を「VIGENERE」とした場合、
ヴィジュネル方陣の縦軸のQ, 横軸のVの交差点を確認し、Lを得る。
次に、縦軸のI, 横軸のIの交差点を確認し、Q
同様に繰り返していく。(暗号鍵の最後の文字まで達したら、暗号鍵の最初の文字に戻る。)
結果として、暗号文LQOXNUZMを得る。

コード上での暗号化方法

例として、以下の1行のコードを解説していく。
ord()文字をUnicode値に変換する。chr()はその逆。
暗号鍵の最後まで達したら、暗号鍵の最初の文字に戻る部分は、key[count % len(key)]である。
ord('A')は26の法の数値をUnicode値に変換するためのものである。

ciphertext += chr(((ord(s) + ord(key[count % len(key)])) % 26) + ord('A'))

ただし、以下の性質を利用している。

>>> ord('A')
65
>>> (65*2)%26
0

上記の性質を利用しない場合、以下の記述になる。

ciphertext += chr((((ord(s) - ord('A')) + (ord(key[count % len(key)]) - ord('A'))) % 26) + ord('A'))

参考文献

Vigenère cipher - Wikipedia

ソースコード

GitHub: vigenere.py