Rubyで共通鍵暗号(openssl)を使う

Ruby で共通鍵暗号を使用する場合、openssl ライブラリを使用するのが簡単らしい。

require 'openssl'
 
def encrypt(cipher, msg, pass)
  salt = OpenSSL::Random.random_bytes(8)
  enc  = OpenSSL::Cipher::Cipher.new(cipher)
  enc.encrypt
  enc.pkcs5_keyivgen(pass, salt)
  return enc.update(msg) + enc.final, salt
end
 
def decrypt(cipher, crypt_msg, pass, salt)
  dec = OpenSSL::Cipher::Cipher.new(cipher)
  dec.decrypt
  dec.pkcs5_keyivgen(pass, salt)
  dec.update(crypt_msg) + dec.final
end

使用例:

cipher = 'aes-256-cbc'   #鍵長256ビットのAES
 
msg  = "秘密のメッセージ"
pass = "PASSWORD"
 
crypt, salt = encrypt(cipher, msg, pass)
p crypt.unpack("H*").join
p salt.unpack("H*").join
 
msg2 = decrypt(cipher, crypt, pass, salt)
p msg2

PHP + mcrypt の場合と違って、鍵や初期化ベクトルを直接設定する必要はない(不可能というわけでは無い)。代わりに pkcs5_keyivgen メソッドを使って、パスワードとソルトから鍵と初期化ベクトルを生成する。

パスワードとソルトが揃っていないと復号できないので、ソルトは暗号文とともに転送・保存する必要がある。それ故にソルトは、毎回異なる安全な乱数でなければならない。しかし、ここが重要なところだが、秘密にしておく必要はない。初期化ベクトルと違って、本当に秘密にしておく必要は無い。なぜならソルトだけでは鍵も初期化ベクトルも作り出せないし、ソルトを改竄しても平文を意図的に改竄することはできないからだ。

とても優れた仕組みだと思う。ただしその仕組みは、結局のところ pkcs5_keyivgen というただ一つのメソッドに立脚しているので、次はこのメソッドの詳細について調べてみたい。

参考:

ウノウラボ Unoh Labs: rubyで手軽に暗号化文字列やハッシュ値を生成
参考にはなった…が、ソルトについて触れていないとか、パスワードのことをソルト(solt)と呼んでいるとか、hashの戻り値が文字列になっていないとか、突っ込みどころがいろいろある…。あと、2007年の記事なので仕方ないかもだが、Ruby 1.9 では動かない。
class OpenSSL::Cipher::Cipher
Ruby 1.9.1 リファレンスマニュアル OpenSSL::Cipher::Cipher クラス

One Response

  1. [...] へびにっき 樹上で暮らすヘビのように生きたい « Rubyで共通鍵暗号(openssl)を使う [...]

Leave a Reply