Rail fence transposition

Railfenceとは柵のことです。柵のように文字を並べて順番を変えることからそう呼ばれている、典型的な「紙とペンでやる並べ替え型暗号」になります。

 

これはABCDEFGH…という文字列であれば

A _ _ _ E _ _ _ I…

_ B _ D _ F _ H…

_ _ C _ _ _ G…

とジグザグに並べて、それを左上から横向きに

AEI… BDFH… CG…

と並べ替える方法になります。例えばRAILFENCEであれば

R _ _ _ F _ _ _ E

_ A _ L _ E _ C

_ _ I _ _ _ N

と並べて

RFEALECIN

が暗号となります。

バリエーションとして、

・左上ではなく途中から始める

* _ _ _ L _ _ _ C

_ R _ I _ F _ N _E

_ _ A _ _ _ E

LCRIFNEAE

・4段にする

R _ _ _ _ _ N

_ A _ _ E _ C

_ _ I _ F _ _ E

_ _ _ L

RNAECIFEL

またはそれらを組み合わせる事があり、この行の数(Rail数)およびどれだけずらしたところから始めるか(Offset)の2つをパラメータとして定義される一連の並べ替えをRail fenceと呼びます。

 

文字の種類に依存しない並べ替えですので、記号でも日本語でも同様に使用することができます。

遊びとしては面白いですが、文字頻度等を変えないことから、解読難度としてはあまり高くありません。特に、Rail fenceであると知れてしまえば、パラメータの組み合わせに対するbruteforceも容易です。けれどこの暗号単独ではなく、他の暗号と組み合わせることで解読難度をとても効果的に上げることができます。

 

日本語でそのまま使う場合には、例えば

“文字の種類に依存しない並べ替えですので、記号でも日本語でも同様に使用することができます。”

をRailfenceしても

“文類しべす記日も使こき字種に存な並替での、号も本で同に用るとでま。の依いえでで語様すがす”

となり、なにかあまり暗号化された気がしません。

せめてひらがなにしてから

“もゅいなべすきもごうしるで。じしるにぞしいらかでの、ごでにんでどよによすこがきすのいんなえでうほもううとま”

とするなどのほうがいいかと思います。 (思ったよりも謎の呪文っぽくなったな・・・。)

Cloud9のPythonのversion

Pythonのコーディングや実行はCloud9で行っているのですが、bashからPythonを実行する時と .pyファイルをRunした時とでPythonのバージョンが異なっていて面倒です。

terminalのbashモード(という表現でいいのだろうか?)で

>> python

を実行すると

Python 3.5.1 |Anaconda 4.0.0 (64-bit)| (default, Dec 7 2015, 11:16:01)

一方で、 .py のファイルを作成し、そのファイルを Run している中で

import sys
print(sys.version)

とすると

3.4.3 (default, Nov 17 2016, 01:08:31)

という結果が返ってきてしまいます。

どちらも3.x系なのでそこはまあいいのですが、libraryのインストール先が

lib/python3.4
lib/python3.5

に分かれていて。具体的にはsklearnのパッケージを使ってみたいのですが、それがpython3.5のフォルダに入っているため、bashからは実行できるけれど .pyファイルのRunではインポートエラー

ImportError: No module named 'sklearn'

が出てきて使えないという状態になっています。

bashからは使えるので、プログラムを作成した上でbashから

>> python hogehoge.py

とすることで使えていますが、若干面倒くさいです。

Project settingからPYTHONPATHにpython3.5のフォルダを加えてみたりしていますがうまくいかない感じです。python3.4のフォルダにもsklearnをインストールしようかと思いましたが、そもそも全てanaconda任せで構成した環境のためどうしていいかよくわからず。そもそもPythonの実行がなぜマルチバージョンな状態になっているのかと言うのがそもそもの問題な気もするわけで・・。

Mixed alphabet

通常のアルファベットの並び ABCDEF… ではなく、その順番を変えて使用することで各種暗号の強度を一段回上げることができます。例えば
CIPHERABDFGJKLMNOQSTUVWXYZ
という並びのテーブルを使えば、ROT13もC->L, I>-M, P->N という変換に変わります。
Vigenere, Playfair等も異なる並び順を使うことでさらに破りにくくすることができます。本当にバラバラの並び順を使用した場合、十分に長い英語の文章とかならともかく、パズルのレベルではテーブルを知らずに解くのは基本的に無理だと思います。

Mixed alphabetについては全体をランダムに並べ替えることもありますが、上の例のようにキーワードを最初に並べ、残りの文字を後に続ける生成方法も使われます。
これについてコードを準備しました。

def mixed_alphabet(keyword, combined=False):
    kw_alphabet_added = keyword.upper() + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    if combined:
        kw_alphabet_added = kw_alphabet_added.replace("J","I")

    already_appeared=[]
    result =""
    for s in kw_alphabet_added:
        if not s in already_appeared:
            result+=s
            already_appeared.append(s)
    return result

Polybiusのように方陣で使う際にはIとJを同一視して25文字で使用する事が多いため、2つ目の引数をそのオプションに使用しています。

 

Rail fence

RailfenceもColumnarも、暗号化の手順は何がしたいか分かるのですが、復号化はそれを逆からたどるだけなのでどうも分かりにくい上に処理しにくいなあと思います。

Railfence transpositionのプログラムです。斜めに書いていくというのをプログラムでどう表現すればいいかなと思いましたが、よく考えると横向きには単調に進行していき高さが周期的に変わっていくだけなので、元の文字列のリストに高さを付与した2次元配列をつくって高さごとに読み直す、というコードにしました。

Encode : railfence_e

def railfence_e(text, rails, offset=0):
    place=[["",0] for j in range(len(text) + offset)] 
    line_cycle = list(range(rails)) + list(range(rails-1)[:0:-1])
    for i in range(len(text)):
        place[i + offset] = [text[i], line_cycle[(i + offset) %(rails*2 -2)]]
    
    result =""
    for i in range(rails):
        for s in place:
            if s[1] == i:
                result+=s[0]
    return result

Decodeでは先にEncodeと同様の2次元配列を作成して、高さごとに文字を割り当てた後単調に横向きに読むようにしました。

Decode : railfence_d

def railfence_d(text, rails, offset=0):
    place=[["",0] for j in range(len(text) + offset)]
    line_cycle = list(range(rails)) + list(range(rails-1)[:0:-1])
    for i in range(len(text)):
        place[i + offset] = ["", line_cycle[(i + offset) %(rails*2 -2)]]

    t = 0
    for i in range(rails):
        for j in range(len(text)):
            if place[j + offset][1] == i:
                place[j + offset][0]=text[t]
                t+=1

    result = ""
    for s in place:
        result += s[0]
    return result

WordPressにコードの記載-続

https://classicalciphers.wordpress.com/2018/08/16/wordpress%E3%81%AB%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E8%A8%98%E8%BC%89/

で書いた、Wordpress標準のコード記載方法ですが、

  1.  code lang=”python” のブロックを複数一つの記事に書くと、2つ目以降のブロックが正しく表示されないです。テンプレートとの相性とかそういうのもあるのかもしれないのですが・・。 languageを指定しないで codeだけであれば(syntax highlightの機能が使えないものの)複数でも想定通りに使えるので、それで使います。
  2. ちゃんと読んでいなかったのですが、
  3. https://en.support.wordpress.com/code/posting-source-code/

    にはConfiguration Parametersという項があり、

    • autolinks (true/false) — Makes all URLs in your posted code clickable. Defaults to true.
    • collapse (true/false) — If true, the code box will be collapsed when the page loads, requiring the visitor to click to expand it. Good for large code posts. Defaults to false.
    • firstline (number) — Use this to change what number the line numbering starts at. It defaults to 1.
    • gutter (true/false) — If false, the line numbering on the left side will be hidden. Defaults to true.
    • highlight (comma-seperated list of numbers) — You can list the line numbers you want to be highlighted. For example “4,7,19”.
    • htmlscript (true/false) — If true, any HTML/XML in your code will be highlighted. This is useful when you are mixing code into HTML, such as PHP inside of HTML. Defaults to false and will only work with certain code languages.
    • light (true/false) — If true, the gutter (line numbering) and margin (see below) will be hidden. This is helpful when posting only one or two lines of code. Defaults to false.
    • padlinenumbers (true/false/integer) — Allows you to control the line number padding. truewill result in automatic padding, false will result in no padding, and entering a number will force a specific amount of padding.
    • title (string) — Set a label for your code block. Can be useful when combined with the collapse parameter.

    という風に、特定の行をハイライトしたりcode blockにラベルをつけたりといったことができるようです。また必要があれば試してみたいです。

Columnar transposition

Columnar transposition cipher.

Pencil cipherとしては平面的な配列に文字を埋めて操作するのですが、2次元配列をうまく扱えないという私のプログラムスキル上の問題で、1次元シーケンスを使ってindexの商を列、余りを行と見立て、数論的に2次元的なものを考えてコーディングしました。自分としてはわかりやすいのですが、多分意図が分かりにくいコードだなと思いつつ・・。

columnar_eがencode、columnar_dがdecodeの変換です。引数の1つ目(c)が平文もしくは暗号化テキスト、2つ目(col)にカラムのオーダーをリストで渡す想定です。カラムのオーダーはキーワードを使って定義されることも多いですが、そこはキーワードをオーダーのリストに変換する別の関数を作成しました。キーワードでもオーダーのリストでも、適切に判断して動作してくれるようにするともっと便利なんだろうけれど、今後の課題ということで。。

def columnar_e(c,col):
    p=[0]*len(c)
    left_col_cnt =len(c) % len(col)
    row_cnt1 = int(len(c)/len(col))+1
    row_cnt2 = int(len(c)/len(col))
    
    i=0
    for j in range(len(col)):
        ind=col.index(j+1)
        if ind<left_col_cnt:
            row_cnt=row_cnt1
        else:
            row_cnt=row_cnt2
        for k in range(row_cnt):
            p[i]=c[k*len(col)+ind]
            i+=1
            
    return p
def columnar_d(c,col):
    p=[0]*len(c)
    left_col_cnt =len(c) % len(col)
    row_cnt1 = int(len(c)/len(col))+1
    row_cnt2 = int(len(c)/len(col))

    i=0
    for j in range(len(col)):
        ind=col.index(j+1)
        if ind<left_col_cnt:
            row_cnt=row_cnt1
        else:
            row_cnt=row_cnt2
        for k in range(row_cnt):
            p[k*len(col)+ind]=c[i]
            i+=1
        
    return p

対称性を持った暗号

暗号変換方法の対称性という概念があります。何かというと、暗号化の変換と復号化の変換が全く同じ計算で行われるということです。

最も有名なものはROT 13です。暗号化によってAはNに、BはOに行きますが、逆にNはAに、OはBに変換されます。ですのでROT+13されて変換された文章を再度ROT+13して暗号化すると、元の文章に戻ってくることになります。ROT2なんかだとAはCに行きますがCはEに行ってしまうため、このようなことは起こりません。

また、Atbashも暗号化によってAはZに、BはYに行きますが、逆にZはAに、YはBに行くため、ROT13と同様に2回暗号化すると元の文書に返ってきます。つまりこれも対称性のある暗号です。

一般に、a→bならb→aを満たしているような単一換字変換の暗号であれば上記のような対称性を持ちます。

そして、単一換字暗号以外でも対称性を持ったものはあります。例えばBeaufortというVigenere暗号に似たkeyed cipherがあります。Vigenereが平文にkeyを足すような変換をするのに対して、Beaufortはkeyを中心として対象の位置のアルファベットに変換するような暗号方式になります。その為、Vigenere暗号とほぼ同様の解読難度と使いやすさを持ちながら、たとえば

CIPHERをTESTをkeyにしてBeaufortで暗号化すると RWDMPN

RWDMPNを再度TESTをkeyにしてBeaufortで暗号化すると CIPHER

となり、対称性を持っていることをみることができます。

また、Playfair暗号も、二文字を一単位としてPolybius方陣上の座標 (a,b) (c,d)を(a,d)(c,b)に変換する(列座標を取り替える)変換なので2回暗号化を繰り返すと元の文章に戻ってくる変換となっています。残念ながら平文の文字が同じ行や同じ列に並んでいる場合の処理が対称的でないので完全に対象な暗号変換とはなっていないのですが、仮にそういった場合の変換ルールを「方陣上の点対称な位置の文字に変換する」とかの対称性が保たれるルールに変えれば、今とほぼ同様の解読難度を持ちながら対称性のある暗号を作ることができます。

さらに、詳細なロジックはここでは書きませんが、有名なEnigma暗号も対称性のある暗号です。ローターやプラグの設定等多くのパラメータがありますが、暗号文に対してそれらの設定を同じにしてもう一度暗号機を回すと平文が出てくるという仕組みになっています。このことは当時実際に暗号機を製造し、運用していく上では色々とメリットがあったようです。

趣味でデコードを楽しむ立場としては対称性というのは少々面白い性質という程度のものでしかなく特にメリットは感じませんが、それは決して暗号が弱いということを意味するものでもありません。また、上では換字タイプの暗号を中心に書きましたが、文字の転置系の暗号など他にも対称性のある暗号はあり、分類の方法として個人的に割と気にいっているものの一つです。

 

Vigenere

こちら

https://classicalciphers.wordpress.com/2018/08/16/rot-2/

で作ったROTの関数を使って、Vigenereに発展させます。ROTの時と同様にまず一文字のVigenere関数を作成します。

def vig_a(c,k,type):
    t=list_A.find(k)
    if t<0:
        t=list_a.find(k)
    if t<0:
        t=list_0.find(k)
    if t<0:
        t=0
    if type=="d":
        t=-t
    return rot_a(c,t)

引数のtypeをdにしたときはDecode時の計算、その他のときはEncode時の計算としています。

これを使って、Encode時の関数は

def vig_e(c,k):
    l_c=len(c)
    l_k=len(k)
    p=""
    for i in range(l_c):
        s=k[i % l_k]
        p+=vig_a(c[i],s,"e")
    return p

Decode時の関数は

def vig_d(c,k):
    l_c=len(c)
    l_k=len(k)
    p=""
    for i in range(l_c):
        s=k[i % l_k]
        p+=vig_a(c[i],s,"d")
    return p

あとでvig_aにkeyed alphabetやbeaufortも対応させれば、keyed Vigenere とBeaufortも同様のコードでかけるはず。そして同様のコードでいいということはもう少し抽象化して効率的なコードに直せるはず、とは考えていますが、また後日。

WordPressにコードの記載

WordPressでコードを記載する方法を検索すると

・Plugin を利用する

・GitHubのGistを利用して、Gistの内容を表示するjavascriptを埋め込む

という2つがたくさん見つかりましたがfree planだとどちらも利用できなさそうです。

初心に帰ってWordpressのヘルプを読んでみると”Posting source code”というページが有りました。

https://en.support.wordpress.com/code/posting-source-code/

While WordPress.com doesn’t allow you to use potentially dangerous code on your blog, there is a way to post source code for viewing.

(WordPress.comではBlog内で危険なコードが使われないよう制限をかけています。投稿内でソースコードを表示させたい場合はこちらの方法をご使用ください。)

・・ということで、ちゃんと公式の方法があるようです。なぜ先ずこの情報が検索に引っかかってくれなかったのか不明ですが。

やり方は

just wrap your code in these tags:

[code language="css"]
your code here
[/code]

The language (or lang) parameter controls how the code is syntax highlighted.

(コードをこちらのタグで囲んでください。language(もしくはlang)のパラメータでsyntaxのハイライトがコントロールされます。)

ということで、pythonの場合には

[code language="python"]
[/code]

でコードを囲めばOKのようです。<>ではなくて[]でタグを書きます。
このような感じに表示されます。

def rot(c,k):
   l=len(c)
   p=""
   for i in range(l):
      p+=rot_a(c[i],k)
   return p

 

ROT

ROTをPythonで。

list_A="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
list_a=list_A.lower()
list_0="0123456789"

def rot_a(c,k):
    if list_A.find(c) >=0:
        list= list_A
    elif list_a.find(c) >=0:
        list= list_a
    elif list_0.find(c) >=0:
        list= list_0
    else:
        return c 

    l = len(list)
    position = list.find(c)
    p= (position + k) % l
    return list[p]

def rot(c,k):
    l=len(c)
    p=""
    for i in range(l):
        p+=rot_a(c[i],k)
    return p

ASCIIコードに変換してMod計算するような方法も考えましたが、後々keyed ROTに拡張することを考えて文字列A-Zの文字列自体を持つことにしました。Ingressでの使用のため、数字についてもROTに対応します。

rot_aが一文字だけのROT、メインのROTではrot_aを全文字に適用する作りです。このrot_aはVigenereでも使います。