Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
8
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

Railsの可逆暗号化 初心者→中級者へのSTEP11/25

Railsの可逆暗号化

はじめに
今回はセキュアなテーマです。ハッシュ化と可逆暗号化などがありますが、今回は可逆暗号化です。ハッシュ化はRailsチュートリアルで少し出てきたので割愛します。

可逆暗号とハッシュ化

確かRailsチュートリアルでも出てきたと思います。パスワードをセキュアなものにしてましたね。また、ハッシュ化は暗号化ではない、との記事があったのですが、読めば納得。暗号化とは当事者間だけでわかるように情報を秘匿することで、ハッシュ化は誰も元に戻せず元の情報がわからなくなることです。しっかり、違いを認識しましょう。

[セキュリティ] ハッシュ化と暗号化は違いますよ!!

可逆暗号
復号可能なデータの変換のこと。個人情報など、DBに保存するときは見られたくないが、復号が必要なものに用いる。

ハッシュ化
復号不可能なデータの変換のこと。パスワードなど、誰にも見られてはならないものに使う。認証時はどうするかというと、送られてきたデータを同じくハッシュ化して、DBにあるハッシュ化されたパスワードと比較する。(同じ値をハッシュ化したら、同じ値が得られる。しかし、ハッシュ化した値から元の値を復号するのは不可能。)

今回は可逆暗号化について説明します。

Railsで可逆暗号

実際にRailsコンソールでやってみましょう。

irb(main):006:0> message = 'Hello!'                      
=> "Hello!"
irb(main):007:0> secret = SecureRandom::hex(128)                                                 
=> "0ed29b6ac428d1f8c4826ad0c586f1dfb79902d5d6b3a9e1a8db923d2bbbcd2a123475758196dc6424f1c2bcf9475912b27902d809cc9ac5b89e5ec7f5942d8979f813ba8a12e3e19303e9a4c918985c93e2eb381b0f0be91d1e8c5aa099d76e55e3c6901b625eaedcd9f2e6da1b4a0cade784f1fb8f2b385b100743f5d7a829"
irb(main):008:0> encryptor = ::ActiveSupport::MessageEncryptor.new(secret, cipher: 'aes-256-cbc')
=> #<ActiveSupport::MessageEncryptor:0x007fc2031f2f30 @secret="0ed29b6ac428d1f8c4826ad0c586f1dfb79902d5d6b3a9e1a8db923d2bbbcd2a123475758196dc6424f1c2bcf9475912b27902d809cc9ac5b89e5ec7f5942d8979f813ba8a12e3e19303e9a4c918985c93e2eb381b0f0be91d1e8c5aa099d76e55e3c6901b625eaedcd9f2e6da1b4a0cade784f1fb8f2b385b100743f5d7a829", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x007fc2031f2b20 @secret="0ed29b6ac428d1f8c4826ad0c586f1dfb79902d5d6b3a9e1a8db923d2bbbcd2a123475758196dc6424f1c2bcf9475912b27902d809cc9ac5b89e5ec7f5942d8979f813ba8a12e3e19303e9a4c918985c93e2eb381b0f0be91d1e8c5aa099d76e55e3c6901b625eaedcd9f2e6da1b4a0cade784f1fb8f2b385b100743f5d7a829", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer>, @serializer=Marshal>
irb(main):009:0> encrypt_message = encryptor.encrypt_and_sign(message)                           
=> "L3FIRGdPam0vTW1ZZWxWaVRFdXRMRUN4QVphWEN3M2hxaHhYUFFMMmZkVT0tLXQvaXFVekQ5MGgxOEc1b2txaGM4MWc9PQ==--81e36973a11ee8148384d55be4f901a0c2ce7b43"
irb(main):010:0> encryptor.decrypt_and_verify(encrypt_message)                                   
=> "Hello!"
irb(main):011:0> 

流れは上記の通りです。解説してきます。

まず暗号化したい情報はmessageHello!です。

secret = SecureRandom::hex(128) 

上記の箇所では乱数を生成しています。

encryptor = ::ActiveSupport::MessageEncryptor.new(secret, cipher: 'aes-256-cbc')`

chipherとは暗号の意味で、ここではaes-256-cbcを採用しています。(暗号化のアルゴリズム等は話がそれるので割愛。)鍵として先ほどの乱数を用います。
ちなみに右辺の::ActiveSupportの部分、これはトップレベルでのActiveSupportを呼び出しています。詳しくは参考記事見てください。ちょっとした小技らしいです。

encrypt_message = encryptor.encrypt_and_sign(message)

先ほどのオブジェクトにmessageを渡して暗号化します。

encryptor.decrypt_and_verify(encrypt_message)

これで復号。

試してみたこと

AESは共通鍵暗号方式って書いてあったからsecretさえ覚えておけば誰でも復号可能。逆に、secretを忘れちゃうと、戻せない。てな訳でsecretを一回上書きして違う値を入れて見た。

irb(main):018:0> secret = SecureRandom::hex(128)    
=> "dbdc9c44db27e70fdcb7a15ac4e794111e20b38b9569abe08f79c336d241871d20f4d327a0a413ac50f80953df11a5f67b3e2137bfc4386744611f35e3f14d56dc388aa4afef5113f4c5177eb546f7b106a6920db6d85318d5d02602c82b61d2d5735dcfd1306c0aa3b0e98f1ebf2dcd8f07744db86f35e86ebe4f99c541e48c"
irb(main):019:0> encryptor = ::ActiveSupport::MessageEncryptor.new(secret, cipher: 'aes-256-cbc')
=> #<ActiveSupport::MessageEncryptor:0x007fc2050925f8 @secret="dbdc9c44db27e70fdcb7a15ac4e794111e20b38b9569abe08f79c336d241871d20f4d327a0a413ac50f80953df11a5f67b3e2137bfc4386744611f35e3f14d56dc388aa4afef5113f4c5177eb546f7b106a6920db6d85318d5d02602c82b61d2d5735dcfd1306c0aa3b0e98f1ebf2dcd8f07744db86f35e86ebe4f99c541e48c", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x007fc205092468 @secret="dbdc9c44db27e70fdcb7a15ac4e794111e20b38b9569abe08f79c336d241871d20f4d327a0a413ac50f80953df11a5f67b3e2137bfc4386744611f35e3f14d56dc388aa4afef5113f4c5177eb546f7b106a6920db6d85318d5d02602c82b61d2d5735dcfd1306c0aa3b0e98f1ebf2dcd8f07744db86f35e86ebe4f99c541e48c", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer>, @serializer=Marshal>
irb(main):020:0> encrypt_message = encryptor.encrypt_and_sign(message)
=> "VmVRRklGT3Z3cW9iclFGV2tZeGYvalU0VUJ6SkhpMUxBN3pjSlF0VTExZz0tLU92TzhVcDc5Yk1UWVJLb1hOZktZQ3c9PQ==--d2900b7e0754a3a6b3d7b95039f7ef47d6d274bc"
irb(main):021:0> encryptor.decrypt_and_verify(encrypt_message)
=> "Hello!"

先ほど同様、暗号化した。ここから鍵を忘れてみる。

irb(main):022:0> secret = "0ed29b6ac428d1f8c4826ad0c586f1dfb79902d5d6b3a9e1a8db923d2bbbcd2a123475758196dc6424f1c2bcf9475912b27902d809cc9ac5b89e5ec7f5942d8979f813ba8a12e3e19303e9a4c918985c93e2eb381b0f0be91d1e8c5aa099d76e55e3c6901b625eaedcd9f2e6da1b4a0cade784f1fb8f2b385b100743f5d7a829"
=> "0ed29b6ac428d1f8c4826ad0c586f1dfb79902d5d6b3a9e1a8db923d2bbbcd2a123475758196dc6424f1c2bcf9475912b27902d809cc9ac5b89e5ec7f5942d8979f813ba8a12e3e19303e9a4c918985c93e2eb381b0f0be91d1e8c5aa099d76e55e3c6901b625eaedcd9f2e6da1b4a0cade784f1fb8f2b385b100743f5d7a829"
irb(main):023:0> encryptor = ::ActiveSupport::MessageEncryptor.new(secret, cipher: 'aes-256-cbc')
=> #<ActiveSupport::MessageEncryptor:0x007fc2017c08d8 @secret="0ed29b6ac428d1f8c4826ad0c586f1dfb79902d5d6b3a9e1a8db923d2bbbcd2a123475758196dc6424f1c2bcf9475912b27902d809cc9ac5b89e5ec7f5942d8979f813ba8a12e3e19303e9a4c918985c93e2eb381b0f0be91d1e8c5aa099d76e55e3c6901b625eaedcd9f2e6da1b4a0cade784f1fb8f2b385b100743f5d7a829", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x007fc2017c0720 @secret="0ed29b6ac428d1f8c4826ad0c586f1dfb79902d5d6b3a9e1a8db923d2bbbcd2a123475758196dc6424f1c2bcf9475912b27902d809cc9ac5b89e5ec7f5942d8979f813ba8a12e3e19303e9a4c918985c93e2eb381b0f0be91d1e8c5aa099d76e55e3c6901b625eaedcd9f2e6da1b4a0cade784f1fb8f2b385b100743f5d7a829", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer>, @serializer=Marshal>
irb(main):024:0> encryptor.decrypt_and_verify(encrypt_message)                                                                                                                                                                                
ActiveSupport::MessageVerifier::InvalidSignature: ActiveSupport::MessageVerifier::InvalidSignature
    from (irb):24

案の定復号できない。
じゃあ鍵を思い出して見る。

irb(main):027:0> secret = "dbdc9c44db27e70fdcb7a15ac4e794111e20b38b9569abe08f79c336d241871d20f4d327a0a413ac50f80953df11a5f67b3e2137bfc4386744611f35e3f14d56dc388aa4afef5113f4c5177eb546f7b106a6920db6d85318d5d02602c82b61d2d5735dcfd1306c0aa3b0e98f1ebf2dcd8f07744db86f35e86ebe4f99c541e48c"
irb(main):028:0> encryptor = ::ActiveSupport::MessageEncryptor.new(secret, cipher: 'aes-256-cbc')                                                                                                                                             
=> #<ActiveSupport::MessageEncryptor:0x007fc202534d20 @secret="dbdc9c44db27e70fdcb7a15ac4e794111e20b38b9569abe08f79c336d241871d20f4d327a0a413ac50f80953df11a5f67b3e2137bfc4386744611f35e3f14d56dc388aa4afef5113f4c5177eb546f7b106a6920db6d85318d5d02602c82b61d2d5735dcfd1306c0aa3b0e98f1ebf2dcd8f07744db86f35e86ebe4f99c541e48c", @sign_secret=nil, @cipher="aes-256-cbc", @aead_mode=false, @digest="SHA1", @verifier=#<ActiveSupport::MessageVerifier:0x007fc202534a50 @secret="dbdc9c44db27e70fdcb7a15ac4e794111e20b38b9569abe08f79c336d241871d20f4d327a0a413ac50f80953df11a5f67b3e2137bfc4386744611f35e3f14d56dc388aa4afef5113f4c5177eb546f7b106a6920db6d85318d5d02602c82b61d2d5735dcfd1306c0aa3b0e98f1ebf2dcd8f07744db86f35e86ebe4f99c541e48c", @digest="SHA1", @serializer=ActiveSupport::MessageEncryptor::NullSerializer>, @serializer=Marshal>
irb(main):029:0> encryptor.decrypt_and_verify(encrypt_message)                                                                                                                                                                                
=> "Hello!"

(鍵はさっきのコピペ)これで復号できました。

参考にしたの

Railsで簡単可逆暗号(ActiveSupport::MessageEncryptor)
https://qiita.com/kengos@github/items/e8ea8f71c47852fde48b

[小ネタ] トップレベルの定数(クラス/モジュール)の取得
https://doruby.jp/users/everyday_is_everyday/entries/1

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
8
Help us understand the problem. What are the problem?