わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

Pythonを用いた単一換字暗号の解読

 科目名が情報セキュリティだったころから,単一換字暗号を授業で解説したあとに,「暗号解読」のレポート課題を出題してきました.
 初期のうちは,学内演習室環境のLinuxで端末を起動し,いくつかのコマンド(sed,echo,cat)を組み合わせれば,効率良く解読できることを紹介してきましたが,Linux環境がなくなったため,別の方法を使用します.
 この解読のためだけに,BYOD PCにLinuxをインストールするのは,推奨できません.Windows Subsystem for Linux (WSL)も,新規インストールには通信とセットアップで時間がかかります.
 近年では「オンライン実行環境」が充実し,ブラウザ上でプログラムを書いて実行することが,簡単にできるようになっています.この記事では,無料かつユーザ登録なしで利用できる,paiza.IOを用いた解読の試みを紹介します.(Google Colabでも実行可能です.作成したプログラムは保存されます.実行にはGoogleアカウントが必要です.)
 『暗号技術入門 第3版 秘密の国のアリス』に合わせて,アルファベット26文字の単一換字暗号を対象とします.小文字(aからzまで)を平文で用いるアルファベット,大文字(AからZまで)を暗号文で用いるアルファベットとします.空白や記号類は出現しないのが慣例です(それらが含まれると解読がより容易になるという事情もあります).暗号文も,この本の記載を使わせてもらいました.
 それでは,動かしてみましょう.https://paiza.io/ja/にアクセスして,「コード作成を試してみる(無料)」のボタンを押します.左上の「PHP」を「Python3」に変更してから,以下の内容を貼り付けて,「実行」のボタンを押してみてください.

s = """\
MEYLGVIWAMEYOPINYZGWYEGMZRUUYPZAIXILGVSIZZMPGKKDWOMEPGROEIWGPCEIPAMDKKEYCIUYMGIF
"""
t = s.translate(str.maketrans('YMEPODWING', 'ethrginaco'))
print(t)

 下部に「theLoVanAthegraceZonehotZRUUerZAaXaLoVSaZZtroKKingthroRghanorCharAtiKKheCaUetoaF」と表示されれば,まずは成功です.
 プログラムを簡単に説明します.「s = """\」と「"""」の間に,解読したい文字列を記述します.複数行になってもかまいません.
 その次の行では,sの文字列を変換します.「'YMEPODWING', 'ethrginaco'」について,文字列の中に'Y'の文字があれば'e'の文字に置き換えます.'M'の文字は't'に,'E'は'h'に,...,'G'は'o'に,置き換えます.複数回,同じ文字が出現すれば,それぞれを置き換えます(だから「単一」「換字」暗号です).すべての置き換えが終わった状態の文字列が,変数tに代入されます.print(t)で,その内容を出力します.
 今回の暗号文をすべて解読するには,tへの代入の行を,以下のコードに変更します.

t = s.translate(str.maketrans('YMEPODWIGCSQRZUALXVNKHJFTB', 'ethrginaocwqusmdfyxpljkbvz'))

 実行結果は,自分で確かめてください.空白を入れて読めば,英文になります
 無事に解読ができたら,「str.maketrans('置換前の文字の並び', '置換後の文字の並び')」が,2行で構成する換字表と,同等の情報を持つことになります.ちなみに,strは変数名ではなく,文字列を扱うPythonの組み込みオブジェクトです.
 ところで,レポート課題で解読の最中というときには,大文字の部分は無視して,小文字にしてみた箇所のみを見て,妥当かどうか検討したいところです.
 大文字を単純に取り除くことも,Pythonで簡単に書けますが,取り除くというより,「未解読の文字がある」という情報に置き換えるべきでしょう.1文字の大文字なら1文字分,連続する大文字はその数だけ,伏せ字にします.
 そうすると,プログラムは以下のようになります.

s = """\
MEYLGVIWAMEYOPINYZGWYEGMZRUUYPZAIXILGVSIZZMPGKKDWOMEPGROEIWGPCEIPAMDKKEYCIUYMGIF
"""
t = s.translate(str.maketrans('YMEPODWING', 'ethrginaco'))
print(t)
import re
u = re.sub('[A-Z]', '.', t)
print(u)

 実行し,出力を見ると,先ほどの大文字小文字混じりと,空行のあとに,「the.o.an.thegrace.onehot....er..a.a.o..a..tro..ingthro.ghanor.har.ti..he.a.etoa.」と表示されます.
 追加したうち「u = re.sub('[A-Z]', '.', t)」は,tの文字列に出現する,文字'A'から文字'Z'までを,すべて'.'に置き換えよ,という指示になります.直前の「import re」は,正規表現モジュールを使用するために記述するコードで,一般にはプログラムの最初(今回の例だとsへの代入より前)に書くのですが,途中に書くのも差し支えなく,それ以降で有効となります.
 それでは,レポート課題に取り組んでください.
 s.translate(str.maketrans(..., ...))やre.subを含むコード例は,Pythonで文字列を置換(replace, translate, re.sub, re.subn) | note.nkmk.meを参考にしました.
 また本記事は,Rubyを用いた単一換字暗号の解読Pythonに置き換えたものとなっています.PythonよりもRubyのほうが好みという人は,活用してください.