ヴィジュネル暗号を実装してみる

情報セキュリティ

こんにちは。引き続き今回も暗号についての内容です。今回はヴィジュネル暗号について取り上げます。

ヴィジュネル暗号とは

ヴィジュネル暗号は15~16世紀に考えられた換字式の暗号です。

ヴィジュネル方陣という変換表を使って暗号化します。ヴィジュネル方陣とは次の表です。

 |abcdefghijklmnopqrstuvwxyz
-+--------------------------
A|abcdefghijklmnopqrstuvwxyz
B|bcdefghijklmnopqrstuvwxyza
C|cdefghijklmnopqrstuvwxyzab
D|defghijklmnopqrstuvwxyzabc
E|efghijklmnopqrstuvwxyzabcd
F|fghijklmnopqrstuvwxyzabcde
G|ghijklmnopqrstuvwxyzabcdef
H|hijklmnopqrstuvwxyzabcdefg
I|ijklmnopqrstuvwxyzabcdefgh
J|jklmnopqrstuvwxyzabcdefghi
K|klmnopqrstuvwxyzabcdefghij
L|lmnopqrstuvwxyzabcdefghijk
M|mnopqrstuvwxyzabcdefghijkl
N|nopqrstuvwxyzabcdefghijklm
O|opqrstuvwxyzabcdefghijklmn
P|pqrstuvwxyzabcdefghijklmno
Q|qrstuvwxyzabcdefghijklmnop
R|rstuvwxyzabcdefghijklmnopq
S|stuvwxyzabcdefghijklmnopqr
T|tuvwxyzabcdefghijklmnopqrs
U|uvwxyzabcdefghijklmnopqrst
V|vwxyzabcdefghijklmnopqrstu
W|wxyzabcdefghijklmnopqrstuv
X|xyzabcdefghijklmnopqrstuvw
Y|yzabcdefghijklmnopqrstuvwx
Z|zabcdefghijklmnopqrstuvwxy

この表の最上段の文字が平文の文字、左側の文字が鍵の文字になります。例えば、平文の文字が’t’で鍵の文字が’D’として暗号化すると、’w’になります。

上に載せたヴィジュネル方陣を作るPythonのプログラムは次になります。

print( ' |abcdefghijklmnopqrstuvwxyz')
print( '-+--------------------------')
for i in range(26):
    l = chr( i +ord('A') ) + '|'
    for j in range(26):
        l += chr( ( i + j ) % 26 +ord('a') )
    print(l)

A,aを0、B,bを1、…、Z,zを25として、平文と鍵を足した値を26(アルファベットの文字数)で割った余りが暗号化した文字の値になります。ここで求めた値に’a’の文字コード(ord('a’))を足して、chrを用いて文字に変換しています。

具体例を使って変換してみます。

平文:thebestwaytopredictthefutureistocreateit
鍵 :DRUCKERDRUCKERDRUCKERDRUCKERDRUCKERDRUCK
暗号:wyydowkzrsvytihucedxyhwovevvljnqmvvdkykd

1文字目は、平文のtを鍵Dで暗号化してwに
2文字目は、平文のhを鍵Rで暗号化してyに
3文字目は、平文のeを鍵Uで暗号化してyに
……………………………………………………………
と暗号化していきます。鍵の文字が不足している場合には、平文の最後の文字が変換されるまで繰り返します。

暗号化するプログラム

毎度のPythonで実装してみます。文字→数値の変換をcode、数値→文字の変換をcharと関数にしてあります。

def code( letter, base ):
    return ord(letter) - ord(base)

def char( code ):
    return chr( code % 26 + ord('a') )

def encrypt( plain, key ):
    index = 0
    result = ''
    while index < len(plain):
        index2 = index % len(key)
        plain_code = code( plain[index], 'a' )
        key_code = code( key[index2], 'A' )
        result += char( plain_code + key_code )
        index += 1
    return result
 
def decrypt( cipher, key ):
    index = 0
    result = ''
    while index < len(cipher):
        index2 = index % len(key)
        cipher_code = code( cipher[index], 'a')
        key_code = code( key[index2], 'A' )
        result += char( cipher_code - key_code )
        index += 1
    return result


if __name__ == '__main__':
    plain_text = 'thebestwaytopredictthefutureistocreateit'
    key = 'DRUCKER'
    cipher_text = encrypt( plain_text, key )
    decode_text = decrypt( cipher_text, key )
    print( cipher_text )
    print( decode_text )

実行結果です。

wyydowkzrsvytihucedxyhwovevvljnqmvvdkykd
thebestwaytopredictthefutureistocreateit

同じプログラムがシーザー暗号にもなる

キーを1文字だけにするとシーザー暗号になります。比較できるよう、以前にシーザー暗号により暗号化した文と同じ文で暗号化してみます。

プログラムの31・32行目を

    plain_text = 'thepenismightierthanthesword'
    key = 'D'

にすると、

wkhshqlvpljkwlhuwkdqwkhvzrug
thepenismightierthanthesword

と表示されます。これはシーザー暗号そのものになります。参考として、シーザー暗号のページへのリンクを貼っておきます。

ヴィジュネル暗号の弱点

鍵が何らかの意味がある言葉になっていることがヴィジュネルの特徴です。そこで、例えばtheのような頻出の単語に着目して、平文のtheと暗号とを付け合わせて鍵を推測していくことを試みます。上の暗号で仮に先頭にtheだとした場合、

平文 :the****
暗号文:wyydow**

鍵  :DRU****

というようになります。DRUで始まる単語を鍵としてあてはめてうまく復号できれば、鍵を見つけられるということのようです。よく考えるよ・・・すごい。

The best way to predict the future is to create it.

鍵が言葉の主だとほとんど意味がないですね。

今回はこれでおしまい。それではまた。

Posted by 春日井 優