RavyPop

=͟͟͞͞(๑=͟͟͞͞(๑•̀=͟͟͞͞(๑•̀д•́=͟͟͞͞(๑•̀д•́๑)=͟͟͞͞

rubyでopenSSLを使う in Mac OS X

一眠りしてから書きました。実行した環境は以下の通りです。

 

  • 環境:Mac OS X 10.9 Marverics
  • ruby: 2.0.0p247 (2013-06-27 revision 41674) [universal.x86_64-darwin13]

 

とりあえず暗号文を表示するためのメソッドを用意します。暗号文をprintするとちゃんと見えないので。

 

def bin_dump(str, num)
  num.times do |i|
    str[i].bytes { |b| print b.to_s(16) }
  end
  puts ""
end

 

"/dev/random"を使って暗号化鍵を生成する

暗号鍵を生成するクラスを作ってみました。こんな感じです。

require 'openssl'

def bin_dump(str, num)
  num.times do |i|
    str[i].bytes { |b| print b.to_s(16) }
  end
  puts ""
end

class Create_key

  def initialize(alg)
    @cip = OpenSSL::Cipher.new(alg)
    OpenSSL::Random.load_random_file("/dev/random")
  end

  #乱数シード変更
  def ch_seed
    OpenSSL::Random.load_random_file("/dev/random")
  end

  #イニシャライズベクタ生成
  def iv_gen
    return @cip.random_iv
  end

  #鍵生成
  def key_gen
    return @cip.random_key
  end

  #鍵長を返す
  def key_len
    return @cip.key_len
  end
end


#このプログラムが単体で実行される場合のみ以下を実行
if __FILE__ == $0
  ck = Create_key.new("aes-256-cbc")
  key = ck.key_gen
  len = ck.key_len
  print "len = ", len, "\n"
  bin_dump(key, len)
end

実行結果

bash-3.2$ ruby create_key.rb
len = 32
cf3dced495f690584a388d2556f87bf10612ab9ffa891cc4dde407175ebb2ad




スペシャルファイル"/dev/random"を乱数シードとして使っています。処理が返ってこない場合はかわりに"/dev/urandom"を使いましょう。少なくともubuntuでは処理が返ってこなくなりました。"if __FILE__ == $0"はコメントにあるようにこのプログラムが単体で実行された場合にのみ、実行されます。だからほかのプログラムからこのクラスを使ったりした場合は無視されるんですよ。便利だね〜。


"/dev/random"とはなにかやなんで処理が返ってこなくなるかはLet's google!

 

文字列の暗号化と復号を行う

 

require 'openssl'
require './create_key'

def bin_dump(str, num)
  num.times do |i|
    str[i].bytes { |b| print b.to_s(16) }
  end
  puts ""
end

class Crypto

  def initialize(key = nil, iv = nil, alg = "aes-128-cbc")
    @cip = OpenSSL::Cipher.new(alg)
    @key = key
    @iv = iv
  end

  def encrypt(s)
    if @key != nil && @iv != nil
      @cip.encrypt              #暗号化モード
      @cip.key = @key           #鍵セット
      @cip.iv = @iv             #イニシャライズベクタセット
      @cip.padding = 1          #パディング有効
      enc_data = ""
      enc_data << @cip.update(s)
      enc_data << @cip.final
      return enc_data
    else
      return nil
    end
  end

  def decrypt(s)
    if @key != nil && @iv != nil
      @cip.decrypt              #復号モード
      @cip.key = @key           #鍵セット
      @cip.iv = @iv             #イニシャライズベクタセット
      @cip.padding = 1          #パディング有効
      dec_data = ""
      dec_data << @cip.update(s)
      dec_data << @cip.final
      return dec_data
    else
      return nil
    end
  end

end



#このプログラムが単体で実行される場合のみ以下を実行
if __FILE__ == $0
  plaintext = ARGV[0]
  ck = Create_key.new("aes-128-cbc")
  key = ck.key_gen
  iv = ck.iv_gen
  c = Crypto.new(key, iv, "aes-128-cbc")
  ciphertext = c.encrypt(plaintext)
  if ciphertext != nil
    print "[ciphertext] : "
    bin_dump(ciphertext, 16)
    b = c.decrypt(ciphertext)
    p b
  else
    print "error\n"
  end
end

実行結果

bash-3.2$ ruby crypto.rb megane
[ciphertext] : 9c2bf5bfe43e984852eaec4b111c7229
"megane"



さっきの鍵生成プログラムをrequireして、暗号鍵と初期化ベクタを生成します。それでもって暗号化したり、復号したりします。実際使う場合は作った鍵をファイルに保存して厳重に管理しましょう。

深く考えずに作ったので色々至らない点もあるかもしれないっす。そしてここまで作って、ClassじゃなくてModuleにした方が良かったのではと思いました。 まぁあとは後々修正していきましょう!