暗号ツール Webアプリケーション その1
前書き
この記事は,SLP KBIT Advent Calendar 2019 の20日目の記事です。
皆さんは、暗号にどれほど興味がありますか。普段、私が使っている連絡ツールにも暗号は使われています。
今回は、難しい暗号には挑戦しませんが、簡単な暗号方程式を考え、暗号を生成するWebアプリケーションを作成しました。
その方法を紹介したいと思います。
目次
開発環境
- Windows10
- ruby 2.6.5
インストール
gem install sinatra
暗号方程式
今回、3つの暗号方程式を紹介します。
1つ目は大文字のアルファベット、2つ目は小文字のアルファベット、3つ目は数字を暗号化する方程式です。
これから紹介する暗号方程式は、ASCIIコードという文字データを用いて考えました。また、10進数の値で考えているため、10進数のデータで説明します。
1つ目は、下の図のように「M」と「N」を境に鏡状に文字を反転させる方程式です。
例えば、Aという文字をASCIIコードで表すと65、Zは90になります。単純にAをZにしたいとき25を足せばよいです。しかし、MをNにしたいとき、25を足しても上手くいきません。そのため、25の数値を変化させる必要があります。
変化させるにあたって、25とはどんな数値か考えてみましょう。もちろん、AからZまでの差でもありますが、細かく分ければ、AからM MからN NからZの差を足したものだとも考えられます。MからNまでの差は1でNからZまでの差はAからMの差と同じです。AからMまでの差を2倍したものに1足した値が25です。つまり、文字を鏡状に反転させるには、特定の文字からMまでの差を2倍して1足した値をその文字に足せば、反転させることができます。
上に記述した方法では、NからZの文字をAからMに反転させることはできないと疑問に持つ人がいるかもしれません。試しにZで計算してみましょう。
ASCIIコードに直すと、Zは90でMは77です。
2*(77-90)+1=-25 90-25=65
上の式のように65という値になりました。ASCIIコードで65はAを表します。このように、NからZの値もAからMの値に
反転させることができます。
これをプログラムで表すと以下のようになります。
puts "パスワードを入力してください" keyword = gets.chomp puts "暗号化前: #{keyword}" code = [] keyword.chars.each do |char| if (65 <= char.ord && char.ord <= 90) then num1 = char.ord num2 = 77 - num1 num3 = 2 * num2 + 1 + num1 end code << num3.chr end puts "暗号化後: #{code.join("")}"
実行結果
パスワードを入力してください ABM 暗号化前: ABM 暗号化後: ZYN
2つ目は、下の図のように1文字目は1つずらし、2文字目は2つずらし、3文字目は3つずらし、再び4文字目は1つずらすような、1、2、3文字分ずらす操作を繰り返す方程式です。
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 | d | f | e | g | i | h | j | l | k | m | o | n | p | r | q | s | u | t | v | x | w | y | a | z | b |
上の表を見てもらえば分かるように、変換後bが2回出てきており、cが1度も出てきてません。
暗号だけの場合は、それでも別に構いませんが復号のことも考えるとあまりよくありません。bはaとzのどちらに復号すればよいか、分からなくなります。例外ですが、zは変換後cになるようにします。
aをASCIIコードで表すと97です。なので、96を引いて1 2 3…というように小さい数値で考えます。この時に、3で割りあまりの数で何文字ずらすか判断します。あまりが0の場合は99、1の場合は97、2の場合は98を足せばよいと分かります。しかし、xはaに変換に限っては大きな値から小さい値に変換する必要があり、普通に足すだけではできません。xは3で割り切れるので、あまりが0の場合は除法の計算を用いて考えます。3で割りきれる場合、97を引いて3を足します。その後、26で割りあまりを見ます。そのあまりと97を足すと3ずらすことができます。
3をずらしたい数に変更すれば、その分ずらすことできます。また、26で割る理由はアルファベットが26個のためです。数字に適応させる時など、必要に応じてこの値を変える必要があります。
cとxの2つ場合を考えてみましょう。ASCIIコードでcは99、xは120です。
cの場合
99-97=2 (2+3)/26=0…5 97+5=102
xの場合
120-97=23 (23+3)/26=1…0 97+0=97
上の計算式よりcがf、xがaになったことが分かります。
プログラムで表すと以下のようになります。
keyword.chars.each do |char| num1 = char.ord - 96 if (num1 == 26) then num3 = 99 elsif (num1 % 3 == 0) then num1 = num1 - 1 num2 = (num1 + 3) % 26 num3 = num2 + 97 elsif (num1 % 3 == 1) then num3 = num1 + 97 else num3 = num1 + 98 end code << num3.chr end
実行結果
パスワードを入力してください abcdefghijklmnopqrstuvwxyz 暗号化前: abcdefghijklmnopqrstuvwxyz 暗号化後: bdfegihjlkmonprqsutvxwyazc
私は、先ほど考えた反転の方程式と組み合わせてより複雑にしました。
そのプログラムを載せておきます。
keyword.chars.each do |char| if (97 <= char.ord && char.ord <= 122) then num1 = char.ord num2 = 109 - num1 num3 = 2 * num2 + 1 + num1 num4 = num3 - 96 if (num4 == 26) then num5 = 99 elsif (num4 % 3 == 0) then num4 = num4 - 1 num6 = (num4 + 3) % 26 num5 = num6 + 97 elsif (num4 % 3 == 1) then num5 = num4 + 97 else num5 = num4 + 98 end end code << num5.chr end
実行結果
パスワードを入力してください abc 暗号化前: abc 暗号化後: cza
3つ目は、入力した順に文字を1つ2つ3つずらす操作を繰り返す方程式です。
例えば、 0000 と入力すると 1231 というように変換されます。
3つ目の方程式はjという変数を用いて考えます。入力した数をjだけずらします。初めは、jに1を代入し入力されるたびにjの値を増加させます。jが3以上になれば再びjに1を代入します。
プログラムで表すと以下のようになります。
keyword.chars.each do |char| if(48 <= char.ord && char.ord <= 58)then num1 = char.ord - 48 num2 = (num1 + j) % 10 num3 = num2 + 48 if(j >= 3)then j = 1 else j = j + 1 end end code << num3.chr end
実行結果
パスワードを入力してください 000000 暗号化前: 000000 暗号化後: 123123
復号方程式
復号の方法ですが、暗号の方法とあまり変わりません。
1つ目の復号方程式ですが、暗号方程式と同じです。要するに、もう一度反転作業を行えばよいだけです。
順番を少し変えて3つ目の復号方程式について説明します。これもほとんど暗号方程式と同じです。暗号化する際、jを足して文字をずらしました。なので、復号する際はjを引いて文字ずらします。
プログラムで表すと以下のようになります。
j=1 keyword.chars.each do |char| if(48 <= char.ord && char.ord <= 58)then num1 = char.ord - 48 num2 = (num1 - j) % 10 num3 = num2 + 48 if(j >= 3)then j = 1 else j = j + 1 end end code << num3.chr end
実行結果
パスワードを入力してください 123123 復号前: 123123 復号後: 000000
最後に2つ目の復号方程式は、どれだけ数を足せば3で割り切れるかでずらす値を判断します。
暗号化の際、文字を1つずらしたものは、3で割ってあまりが2になるものに変換されます。なので、1を足せば3で割り切れる値になります。よって、1を足して3で割り切れる値は1つ文字をずらして復号します。
文字を2つずらしたものは、3で割って余りが1になるものに変換されます。なので、2を足せば3で割り切れる値になります。よって、2を足して3で割りきれる値は2つずらして復号します。残った値は、3つずらし復号します。
暗号化の際、例外を1つ作りました。最初に例外の復号を行うことを忘れないようにしましょう。
プログラムで表すと以下のようになります。
keyword.chars.each do |char| if (97 <= char.ord && char.ord<=122)then num = char.ord if(num == 97)then num3 =120 elsif((num+1)%3==0)then num1 = num - 97 num2 = (num1 - 1) % 26 num3 = num2 + 97 elsif((num+2)%3==0)then num1 = num - 97 num2 = (num1 - 2) % 26 num3 = num2 + 97 else num1 = num - 97 num2 = (num1 - 3) % 26 num3 = num2 + 97 end end code << num3.chr end
実行結果
パスワードを入力してください bdfegihjlkmonprqsutvxwyazc 復号前: bdfegihjlkmonprqsutvxwyazc 復号後: abcdefghijklmnopqrstuvwxyz
私は、少し複雑な暗号にしたのでその復号のプログラムも載せておきます。
keyword.chars.each do |char| if (97 <= char.ord && char.ord<=122)then num = char.ord if(num == 97)then num3 =120 elsif((num+1)%3==0)then num1 = num - 97 num2 = (num1 - 1) % 26 num3 = num2 + 97 elsif((num+2)%3==0)then num1 = num - 97 num2 = (num1 - 2) % 26 num3 = num2 + 97 else num1 = num - 97 num2 = (num1 - 3) % 26 num3 = num2 + 97 end num4 = 109 - num3 num5 = 2 * num4 + 1 + num3 end code << num5.chr end
実行結果
パスワードを入力してください cza 復号前: cza 復号後: abc
追記
内容が思っていたよりも多くなったので、その2に続きます。