# # # # # # # # #
# /41/pws_2.rb
#
# by Jan Lelis
# e-mail: mail@janlelis.de
# type/version: ruby
# snippet url: http://rbJL.net/41/pws_2.rb
# original post: http://rbJL.net/41-tutorial-build-your-own-password-safe-with-ruby
# license: CC-BY (DE)
#
# (c) 2010 Jan Lelis.
require 'openssl'
require 'fileutils'
class PasswordSafe
VERSION = '0.0.2'.freeze
def initialize( filename = File.expand_path('~/.pws') )
@pwfile = filename
@pwdata = "example data"
@pwhash = Encryptor.hash 'password'
access_safe
read_safe
end
private
# Tries to load and decrypt the password safe from the pwfile
def read_safe
pwdata_encrypted = File.read @pwfile
@pwdata = Encryptor.decrypt pwdata_encrypted, @pwhash
end
# Tries to encrypt and save the password safe into the pwfile
def write_safe
pwdata_encrypted = Encryptor.encrypt @pwdata, @pwhash
File.open( @pwfile, 'w' ){ |f| f.write pwdata_encrypted }
end
# Checks if the file is accessible or create a new one
def access_safe
if !File.file? @pwfile
puts "No password safe detected, creating one at #@pwfile"
FileUtils.touch @pwfile
write_safe
end
end
class << Encryptor = Module.new
CIPHER = 'AES256'
def decrypt( data, pwhash )
crypt :decrypt, data, pwhash
end
def encrypt( data, pwhash )
crypt :encrypt, data, pwhash
end
def hash( plaintext )
OpenSSL::Digest::SHA512.new( plaintext ).digest
end
private
# Encrypts or decrypts the data with the password hash as key
# NOTE: encryption exceptions do not get caught!
def crypt( decrypt_or_encrypt, data, pwhash )
c = OpenSSL::Cipher.new CIPHER
c.send decrypt_or_encrypt.to_sym
c.key = pwhash
c.update( data ) << c.final
end
end
end
if __FILE__ == $0 # test whether it works :)
pws = PasswordSafe.new 'p2test'
print 'Enter data to encrypt: '
pws.instance_variable_set :@pwdata, gets.chop
pws.send :write_safe
puts "In safe: " +
(File.read pws.instance_variable_get :@pwfile).inspect
pws = PasswordSafe.new 'p2test'
pws.send :read_safe
puts "Read from safe: " + pws.instance_variable_get(:@pwdata)
end
# J-_-L