openssl で暗号化すると便利なんだけど
暗号化をおこなったデータをそのままプログラムを経由して読みたいよね。やっぱり。
openssl で暗号化 → ruby で復号化
openssl enc -e -aes-256-cbc -salt -in test.json -out enc.json -pass password:my_pass
これで暗号化したファイルを、rubyでデコードしてみる
passphrase = "my_pass" data = open("enc.json", "r").read data = data.force_encoding("ASCII-8BIT") salt = data[8,8] data = data[16, data.size] cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC") cipher.decrypt cipher.pkcs5_keyivgen(passphrase, salt, 1 ) data = cipher.update(data) + cipher.final open("out.json", "w"){|f| f.write data }
ruby で暗号化 → openssl で復号化
ruby で暗号化したものを openssl で復号化する。
passphrase = "秘密秘密" data = open("plain.json", "r").read cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC") salt = OpenSSL::Random.random_bytes(8) cipher.encrypt cipher.pkcs5_keyivgen(passphrase, salt, 1 ) data = cipher.update(data) + cipher.final ## salted data = "Salted__" + salt + data open("enc.json", "w"){|f| f.write data }
openssl で復号化
openssl enc -d -aes-256-cbc -salt -in enc.json -out plain.json -pass password:秘密秘密
base64 や、pbkdf2 を用いる場合
上記の記述はずいぶんと古い記述なので、新しく調べ直した。
OpenSSLでbase64 ファイルで、salt を使う場合
## 暗号化 openssl enc -e -pbkdf2 -aes256 -salt -base64 -in my.txt -out my.enc -pass password:my_passphrase ## 復号化 openssl enc -e -pbkdf2 -aes256 -salt -base64 -in my.enc -out out.txt -pass password:my_passphrase
PBKDF2 を用いて、salt を iter 回数分だけ繰り返している。iter回数はデフォルトで10000 である。iter回数は明示したほうが総当たり強度がある。
## 暗号化 iter 明示 openssl enc -e -pbkdf2 -iter 110801-aes256 -salt -base64 -in my.txt -out my.enc -pass password:my_passphrase ## 復号化 iter 明示 openssl enc -e -pbkdf2 -iter 110801 -aes256 -salt -base64 -in my.enc -out out.txt -pass password:my_passphrase
コレと同等の処理をruby で行いたい。
復号化
data = Base64.decode64 File.read(encrypted_file, mode: 'rb') raise 'no salt' unless data.start_with?("Salted__") # ソルトの取り出し salt = data[8, 8] # ヘッダー後続8バイト encrypted_data = data[16..-1] # 残り全部が暗号化文 cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC") cipher.decrypt key_iv = OpenSSL::PKCS5.pbkdf2_hmac(passphrase, salt, iter, cipher.key_len + cipher.iv_len, 'sha256') cipher.key = key_iv[0, cipher.key_len] cipher.iv = key_iv[cipher.key_len, cipher.iv_len] # 復号化 decrypted_data = cipher.update(encrypted_data) + cipher.final File.open(output_file, 'wb') {|f|f.write(decrypted_data)} ## 実行例 ## openssl enc -e -pbkdf2 -iter 110801 -aes256 -salt -base64 -in my.enc -out out.txt -pass password:my_passphrase 相当 passphrase = "my-long-pass-phrase" iterations = 110801 decrypt_file('my.enc, 'my.out', password, iterations)
暗号化
def encrypt_file(input_file, encrypted_file, passphrase, iter) data = File.open(input_file, "r").read cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC") cipher.encrypt salt = OpenSSL::Random.random_bytes(8 ) key_iv = OpenSSL::PKCS5.pbkdf2_hmac(passphrase, salt, iter, cipher.key_len + cipher.iv_len, 'sha256') cipher.key = key_iv[0, cipher.key_len] cipher.iv = key_iv[cipher.key_len, cipher.iv_len] encrypted_data = "Salted__" + salt + cipher.update(data) + cipher.final File.open(encrypted_file, 'wb') { |f| f.write Base64.encode64(encrypted_data)} end # 実行例 # openssl相当 ## openssl enc -e -pbkdf2 -iter 110801 -aes256 -salt -base64 \ # -in my.enc -out out.txt -pass password:my_passphrase passphrase = "my-long-pass-phrase" iterations = 110801 encrypt_file(input_file, encrypted_file, password, iterations) puts "File encrypted to #{encrypted_file}"
これらをまとめて実行しつつ、openssl コマンドでも扱えるか試してみる。
def main require 'openssl' require 'base64' require 'pry' # 入力ファイル名と出力ファイル名 input_file = 'my.txt' encrypted_file = 'my.enc' decrypted_file = 'my.out' password = 'your_password_here' # パスワードをここに設定 iterations = 110801 # 暗号化 encrypt_file(input_file, encrypted_file, password, iterations) puts "File encrypted to #{encrypted_file}" # 復号化 decrypt_file(encrypted_file, decrypted_file, password, iterations) puts "File decrypted to #{decrypted_file}" raise "failed ruby encrypt / decrypt " unless open(input_file).read == open(decrypted_file).read ## 互換性チェック openssl_out = 'my.openssl.enc' # ruby encrypt_file -> openssl decrypt result = `openssl enc -d -aes-256-cbc -base64 -pbkdf2 -iter #{iterations} -salt -in #{encrypted_file} -k #{password}` raise "failed compatible check: ruby encrypt -> openssl decrypt failed." unless open(input_file).read == result # openssl encrypt -> ruby decrypt_file() `openssl enc -e -aes-256-cbc -base64 -pbkdf2 -iter #{iterations} -salt -in #{input_file} -out #{openssl_out} -k #{password}` decrypt_file(openssl_out, decrypted_file, password, iterations) raise "openssl encrypt -> ruby decrypt failed. " unless open(decrypted_file).read == open(input_file).read end main
コレで、問題なく、Openssl と同様の処理が行えることがわかった。
2024-09-28
ruby ソースコードで openssl コマンドと同等の処理を行ってみた。
細かいところが割とめんどくさい。pkcs5_keyivgen だとうまくいかない。いろいろと新しくなってるんですね。