暗号ツール Webアプリケーション  その2

前書き

 この記事は,SLP KBIT Advent Calendar 2019 の20日目の記事です。

adventar.org

この記事は、「暗号ツール Webアプリケーション  その2」です。その1を見ていない人は、先にその1を閲覧してもらえるとありがたいです。

目次

Webアプリケーション

 続いて、Webアプリケーションの作り方について簡単に説明します。
まず、初めに文字を表示させてみましょう。 今回は、やっほーと表示させましょう。 文字を表示させるには、以下のようなプログラムになります。

require 'sinatra'
require 'sinatra/reloader'
enable :sessions

class App < Sinatra::Base
    get '/' do
        'やっほー'
    end
end
App.run!

require 'sinatra'は、sinatraというフレームワークの組み込むための宣言です。
require 'sinatra/reloader'は、ソースコードが変更された時、サーバに適応してくれる便利な機能と思っておいてください。 get '/' do~end は、'/'にgetメソッドでアクセスされたら、do~endの内容が実行されます。

Ruby {ファイル名}.rbで実行し、ブラウザからhttp://localhost:4567でアクセスします。 以下のように表示されると思います。 f:id:Drink_15:20191219122346p:plain

 次に、erbファイルを利用して文字を表示させたいと思います。 プログラムは、以下のようなものになります。

rbファイル

class App < Sinatra::Base
    get '/' do
      @title = 'やっほー'
      @subtitle = 'ここは、富士参か?'
      erb :{erbのファイル名}
    end
end
App.run!

erbファイル

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title><%= @title %></title>
    </head>
    <body>
        <form action="/" method="post">
            <h4><%= @title %></h4>
            <p><%= @subtitle %></p>
        </form>
        <br>
    </body>
</html>

@titleと@subtitleに文字列を代入し、erbファイルで表示しています。 ブラウザには、以下のように表示されると思います。 f:id:Drink_15:20191219124028p:plain

 次にテキストとボタンを付け加えていきましょう。 <input type=" " name=" " value=" ">のコードを付け加えます。typeのところをtextにすればテキスト、submitにすればボタンが生成されます。nameは変数、valueは属性を設定しています。今回は暗号ボタンと復号ボタンを付け加えましょう。また、暗号を生成するWebアプリケーションと分かりやすいようにtitleとsubtitleも’暗号ツール!’と’使ってね!’に変えたいと思います。 付け加えたプログラムが以下のものになります。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title><%= @title %></title>
    </head>
    <body>
        <form action="/" method="post">
            <h4><%= @title %></h4>
            <p><%= @subtitle %></p>
            <input type="text" name="sts1">
            <input type="submit"  value="暗号">
            <br>
            <input type="text" name="sts2">
            <input type="submit"  value="復号">
            <br>
        </form>
        <br>
    </body>
</html>

以下のように表示されると思います。 f:id:Drink_15:20191219130358p:plain

 作業もいよいよ終盤です。 ここから、一気に完成させようと思います。現段階では、同じフォームの中にボタンが2つあります。1つのフォームに1つのボタンしか設定できないため、フォームをもう1つ作成し、送信先を区別します。区別するため<form action="/" method="post">の"/"を"/cip"と"/dec"に変えます。続いて送信したデータを受け取る部分でrbファイルに作成します。その時、post "/cip" do ~ endpost "/dec" do ~ endのコードを付け加えます。<form action="/" method="post">では、ユーザーがボタンを押したとき'/'に対してpostを送信し、それをサーバが受け取ります。'/'に対してpostが送られた時にdo~endの内容が実行されます。この部分でテキストの文字列を暗号化、復号を行います。なので、この中にその1で考えた暗号化と復号のプログラムを挿入します。その際、@before1と@before2にtextの文字列、@result1に暗号化した文字列、@result2に復号した文字列を代入し表示します。 プログラムは、以下のようになります。

rbファイル

require 'sinatra'
require 'sinatra/reloader'

enable :sessions

class App < Sinatra::Base
    get '/' do
        @title = '暗号復号ツール!'
        @subtitle = '使ってね!'
        erb :{erbのファイル名}
    end
    post '/cip' do
        @title = '暗号復号ツール!'
        @subtitle = '使ってね!'
        @before1 = params[:sts1].to_s
        keyword = params[:sts1].to_s
        code = [] 
        j = 1
        keyword.chars.each do |char|
            if (65 <= char.ord && char.ord <= 90) then
                num1 = char.ord 
                num2 = 77 - num1
                num5 = 2 * num2 + 1 + num1
            end  
            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
            elsif(48 <= char.ord && char.ord <= 58)then
                num1 = char.ord - 48
                num2 = (num1 + j) % 10
                num5 = num2 + 48
                if(j >= 3)then
                    j = 1
                        
                else
                    j = j + 1
                end
            end    
            code << num5.chr
        end
        @result1 = code.join("")
        erb :index
    end    
    post '/dec' do
        @title = '暗号復号ツール!'
        @subtitle = '使ってね!'
        @before2 = params[:sts2].to_s
        keyword = params[:sts2].to_s
        code = [] 
        j = 1
        keyword.chars.each do |char|
            if (65 <= char.ord && char.ord <= 90) then
                num1 = char.ord
                num2 = 77 - num1
                num5 = 2 * num2 + 1 + num1
            end  
            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
                
            elsif(48 <= char.ord && char.ord <= 58)
                num1 = char.ord - 48
                num2 = (num1 - j) % 10
                num5 = num2 + 48
                if(j >= 3)then
                    j = 1
                    
                else
                    j = j + 1
                end 
            end
            code << num5.chr
        end
        @result2 = code.join("")
        erb :index
    end
end
App.run!

erbファイル

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title><%= @title %></title>
    </head>
    <body>
        <form action="/cip" method="post">
            <h4><%= @title %></h4>
            <p><%= @subtitle %></p>
            <input type="text" name="sts1">
            <input type="submit"  value="暗号">
            <br>
            <span><%= @before1 %></span>
            <br>
            <span><%= @result1 %></span>
        </form>
        <br>
        <form action="/dec" method="post">
          <input type="text" name="sts2">
          <input type="submit"  value="復号">
          <br>
          <span><%= @before2 %></span>
          <br>
          <span><%= @result2 %></span>
        </form>
    </body>
</html>

以下のように表示されます。 f:id:Drink_15:20191219135732p:plain f:id:Drink_15:20191219135748p:plain このように暗号化前の文字列と暗号化後の文字列を表示させます。

終り

 以上で紹介が全て終りました。やってみた感想として、意外と簡単にWebアプリケーションが作れるんだと思いました。まぁ、大きなWebアプリケーションを作成していないからかもしれませんが。世間では、Rubyはオワコンという声もありますが、使っていて非常に書きやすく楽しかったので、気に入りました。使用頻度は、下がっていく一方と予想されますが、私はもう少し使ってみようと思います。今後、もう少し大きなWebアプリケーションを作成できれば、いいなぁーと思います。

暗号ツール Webアプリケーション  その1

前書き

 この記事は,SLP KBIT Advent Calendar 2019 の20日目の記事です。

adventar.org

 皆さんは、暗号にどれほど興味がありますか。普段、私が使っている連絡ツールにも暗号は使われています。
今回は、難しい暗号には挑戦しませんが、簡単な暗号方程式を考え、暗号を生成するWebアプリケーションを作成しました。
その方法を紹介したいと思います。

目次

開発環境

  • Windows10
  • ruby 2.6.5

インストール

gem install sinatra

暗号方程式

 今回、3つの暗号方程式を紹介します。
1つ目は大文字のアルファベット、2つ目は小文字のアルファベット、3つ目は数字を暗号化する方程式です。 これから紹介する暗号方程式は、ASCIIコードという文字データを用いて考えました。また、10進数の値で考えているため、10進数のデータで説明します。

 1つ目は、下の図のように「M」と「N」を境に鏡状に文字を反転させる方程式です。 f:id:Drink_15:20191213204008p:plain
 例えば、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文字分ずらす操作を繰り返す方程式です。 f:id:Drink_15:20191218201712p:plain

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に続きます。