見出し画像

Pythonでビジュネル暗号

どうも、今回はPythonでビジュネル暗号化するツールを書いてみた話です。

お断り

自分は素人もいいところのプログラミング初心者です。企業やグループでの開発経験もないです。そのためおかしな処理、非効率な処理、おかしな命名規則をしているかもしれませんがご了承ください。またかなり細かく説明するの結構長いです。


ビジュネル暗号とは

右図(ヴィジュネル方陣)を使って暗号化を行う。以下、平文を小文字、暗号文を大文字で表す。例として鍵を arm、平文を code とすると、ヴィジュネル方陣で、aとcの交わりはCであり、rとoはF、mとdはPというように暗号文 C, F, P が得られる。平文が鍵よりも長い場合、鍵を繰り返して用い、最後の平文eはaとの交わりでEとなる。すると、平文「code」は暗号文「CFPE」となる。ここで平文が暗号文と同一の文字になる箇所があるが、解読者にそれは分からない。大事なのは(例では3である)鍵の周期を解読者は知らないということだ。また、この鍵は文字数の制約がないので、鍵の個数は無数である。実際に利用するという観点からみれば、覚えやすいほうがよい(紙に書くとそれが漏れる場合があるので)が、逆に敵に推測されやすいという危険もある。ここでの鍵は、単に例として arm つまり「」または「武器」という覚えやすい単語にした。

ヴィジュネル暗号
ヴィジュネル暗号

表の行と列から暗号鍵と平文の交点にあたる文字を暗号文として使用します。ヴィジュネル暗号は同じ文字を暗号化した際に、同じ文字になることが少ないので解読が容易でない。例えば、平文「SOS」を鍵「ARM」で暗号化すると、「SFE」となります。最初のSと最後のSが暗号化されるとSとEになっています。これによって単一換字式暗号の弱点を克服しているようです。
ただ、頻度分析だかすると解読できるそうですが…

今回はこれの暗号化ツールをPythonで書いていこうと思います。

GitHub

流れ

  1. 鍵と平文を受け取る

  2. 方陣(csv)を参照しながら暗号化

  3. 暗号文を出力

今回はcsvに先ほどのヴィジュネル方陣を保存します。

csvファイル

,で区切られたファイルです。エクセルなどで表示すると表みたいに閲覧できます。今回はpandsというライブラリ?を利用して参照します。

一応全文

ここから細かく解説しますが、行番号より処理の流れ通りに説明します。

import pandas as pd

def encryption(key,plaintext):
    df = pd.read_csv('Vigenere_square.csv', index_col=0)
    row_label = str(key)
    column_label = str(plaintext)
    jene = df.loc[row_label, column_label]
    return jene

def main():
    print("鍵を入力してください。")
    input_key = list(input().upper())
    print("平文を入力してください。")
    input_plaintext = list(input().upper())

    key_len = len(input_key)
    plaintext_len = len(input_plaintext)

    n = 0
    result_list = []
    for i in range(plaintext_len):
        arg_key = input_key[n]
        arg_plaintext = input_plaintext[i]
        result_list.append(encryption(arg_key, arg_plaintext))
        n += 1
        if n == key_len:
            n = 0
    result_str = ''.join(result_list)
    print(result_str)

if __name__ == "__main__":
        main()
,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
A,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
B,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A
C,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B
D,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C
E,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D
F,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E
G,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F
H,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G
I,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H
J,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I
K,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J
L,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K
M,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L
N,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M
O,O,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N
P,P,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O
Q,Q,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P
R,R,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q
S,S,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R
T,T,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S
U,U,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T
V,V,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U
W,W,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V
X,X,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W
Y,Y,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X
Z,Z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y

import pands as pd

pandsを導入してpdと書くだけで使用できるように。

if name == "main":

Pythonにmain関数を導入するとこんな感じになるそう。おまじない。

if __name__ == "__main__":
        main()

def main():

main関数。主に値の入出力をしています。

print()

ユーザへの指示です。

input_key = list(input().upper())

input_keyという変数にリスト化と大文字に変換した入力を代入します。

まず暗号化の際に一文字ずつ処理したいので添え字で指定できるリストに、csvが大文字なのでそれに合わせて大文字に変換しておきます。

 平文の入力処理も同様です。

これが1行で簡単にかけてしまうPythonすごいですね。

key_len = len(input_key)

リストの長さを取得しています。

鍵の長さは周期の設定に、平文の長さは全体の繰り返し回数の設定に使用します。

n =  0

暗号化する関数に渡す鍵の添え字になります。

result_list = []

結果用のリスト。

for i in range(plaintext_len):

平文をすべて暗号化するため、平文の長さ分繰り返します。

arg_key = input_key[n]

さきほどの添え字を指定して、暗号化関数に渡す引数を設定。

arg_plaintext = input_plaintext[i]

こちらは平文の引数。for分のiを利用します。

result_list.append(encryption(arg_key, arg_plaintext))

暗号化関数(encryption関数)に先ほどの鍵と平文の引数を与えて、返り値を直に結果用のリストに追加していきます。

def encryption(key,plaintext):

暗号化関数。

鍵と平文を一文字ずつ受け取って、csvファイルを参照しながら暗号化した値を返します。

ちなみにpandasの使い方はよくわからなかったので、色んなサイトを見様見真似でやっているのでちょっと怪しい説明かもしれません。

df = pd.read_csv('Vigenere_square.csv', index_col=0)

df にcsvの内容を代入。index=0はたしかindex(縦のタイトル?)に一番左の列を利用する場合の呪文だったきがする。

row_label = str(key)
column_label = str(plaintext)

行列を指定する変数。縦を指定するのにrow_labelを鍵に、横を指定するのにcolumn_labelに平文を代入。

jene = df.loc[row_label, column_label]

jene変数にlocと先ほどの変数で行列を指定して、暗号化済みの文字を代入。

return jene

返します。これ別にreturnでdf.locを直接返してもいいですね。

def main():

main関数に戻ってきました。

n += 1

nインクリメントしておきます。

if n == key_len:

これは鍵の添え字をリセットしてます。もしARMを鍵にした場合、平文の4文字目になった際に、存在しないリストを参照してしまうので、鍵の長さを超えた際に0にリセットします。

result_str = ''.join(result_list)

結果用のリストをstr型に連結しています。たしか’’に空白を置けば、文字間に空白が挿入されるはずです。

print(result_str)

結果表示。

まとめ

またPythonで書いちゃいました。ブロックがインデントだったりして、あんまり好きじゃないんですけど、処理を書きやすいのでつい使っちゃいます。


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