many of my ruby apps have the password hard coded. i am looking for a
way so that i can control the password not to be stored as text file.
what are the ruby options that are available.
On 19 set, 18:55, Junkone [email protected] wrote:
many of my ruby apps have the password hard coded. i am looking for a
way so that i can control the password not to be stored as text file.
what are the ruby options that are available.
could use String#crypt
mypassword = “visible_to_everyone”
hash = mypassword.crypt(mypassword)
“some_other_password”.crypt(hash) == hash >> false
mypassword.crypt(hash) == hash) >> true
On Sun, Sep 21, 2008 at 12:52:05AM +0900, [email protected] wrote:
“some_other_password”.crypt(hash) == hash >> false
mypassword.crypt(hash) == hash) >> true
I don’t recommend relying on crypt if you want “real” security. The
cryptographic value of the algorithm used by crypt is pretty damned weak
by today’s standards.
Junkone wrote:
many of my ruby apps have the password hard coded. i am looking for a
way so that i can control the password not to be stored as text file.
what are the ruby options that are available.
Do you need to know what the stored password is, or do you just need to
validate passwords?
If the latter, you can use the MD5, SHA1, or SHA2 libraries that come
with Ruby:
require ‘digest/sha1’
#Could load the hash from a file instead
hash = Digest::SHA1.new.update(“mypassword”)
print "Enter password: "
input_password = gets.strip
if hash == Digest::SHA1.new.update(input_password)
puts “Access granted.”
else
puts “Access denied.”
end
-Justin
On Sep 22, 12:00 am, Justin C. [email protected] wrote:
else
puts “Access denied.”
end-Justin
i just store passwords in text files. i am looking for a secure way of
keeping these passwords and using it thro ruby as my progs need the
pass.
for eg. i send auto IM using bot and need my IM pass to be kept
secure.
Hmm, that’d be quite the trick. Not even the professional-grade IM
clients (Trillian and Pidgin) have figured out how to do that yet.
It’s a month ago but maybe it helps anyway.
On 22.09.2008, at 16:58, Junkone wrote:
i just store passwords in text files. i am looking for a secure way
of
keeping these passwords and using it thro ruby as my progs need the
pass.
for eg. i send auto IM using bot and need my IM pass to be kept
secure.
I don’t know for sure if the following can help:
http://pog.rubyforge.org/doc/
Otherwise I had a similar problem in a daemon.
I solved it like that:
M::main_loop() # entry point
M::passwd_eventloop() # daemon mode, use an UNIX domain socket
M::set_password_interactive() # interactive mode (CLI without socket)
M::PasswordStorage saves the username password tuple in the memory by
encrypting the tuple. It has all methods you need to get and set
passwords.
It uses OpenSSL::Cipher::Cipher.new(“AES-256-CBC”) and a generated
random
key with key length 52 to save the tuple in memory.
If you just need an interactive way to set your passsword then just
use the
*_interactive() methods from M, without the client and without
M::passwd_eventloop().
Disclaimer:
I am not a crypto expert and maybe there are a few timing issues in the
following code!
#server:
require ‘rubygems’
require ‘termios’
require ‘openssl’
module M
class ShutdownException < StandardError; end
@@pw_storage = nil # safe password storage if anyone can read your
memory
If you change the next line, don’t forget to change it in
client.rb, too!
PASS_UNIX_SOCK="/tmp/my.sock"
class PasswordStorage
def initialize
@secret = {}
@shared_key = {}
end
# PasswordStorage::get_password returns the cleartext password
for a user.
def get_password(username=nil)
decode(@secret[username], username) if username
end
def set_password_interactive(username="")
# get password from prompt at the start
print "provide password for #{username}: "
begin
M::echo(false)
passwd = STDIN.gets.strip
ensure
M::echo(true)
end
if passwd.empty?
STDERR.puts("An empty password is not allowed.")
exit
end
@secret[username] = encode(passwd,username)
passwd=""
puts ""
end
def set_password(user=nil, passwd=nil)
if user.nil? or passwd.nil? or user.empty? or passwd.empty?
return false
else
@secret[user] = encode(passwd,user)
end
end
# private Methods of PasswordStorage
private
def encode(s,username)
cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
@iv = @iv || cipher.random_iv
cipher.iv = @iv
# for each user we want to have a long random key to encrypt the
# user/passwd storage
@shared_key[username] = @shared_key[username] ||
OpenSSL::Random::random_bytes(52)
cipher.encrypt
@shared_key[username] << “\0” until
@shared_key[username].length == 52
cipher.key = @shared_key[username]
return (cipher.update(s) << cipher.final)
end
def decode(key,username)
cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
cipher.iv = @iv
cipher.decrypt
cipher.key = @shared_key[username]
return (cipher.update( key ) << cipher.final)
end
end # PasswordStorage
module_function
getter/setter
def getpass(username=nil)
@@pw_storage.get_password(username)
end
def setpass_interactive(username=nil)
@@pw_storage = @@pw_storage || M::PasswordStorage.new
@@pw_storage.set_password_interactive(username)
end
def setpass(username=nil, password=nil)
@@pw_storage = @@pw_storage || M::PasswordStorage.new
@@pw_storage.set_password(username,password) unless username.nil?
or password.nil?
end
def clean_unixsocket
File.delete(PASS_UNIX_SOCK) if File.exists? PASS_UNIX_SOCK
end
It reads the passwd from a unix domain socket.
def passwd_eventloop
clean_unixsocket
res = ""
server = UNIXServer.new(PASS_UNIX_SOCK)
begin
sock = server.accept_nonblock
res = sock.readpartial(4096).split(" ")
sock.close
rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO,
Errno::EINTR, EOFError
IO.select([server])
retry
end
clean_unixsocket
# res: [user passwd]
if @@pw_storage.nil?
b = []
b << setpass(res.shift,res.shift)
return b.all?
end
return false
end
M::main_loop
The daemon mode has two states, user/password set and not set.
def main_loop
begin
Signal.trap(“INT”) {raise ShutdownException }
Signal.trap(“TERM”) {raise ShutdownException }
# Comment out, if you want to use interactive mode
passwd_eventloop
# Uncomment, if you want to use it without reading from socket.
#set_password_interactive
loop do
#do your stuff...
end # loop
rescue ShutdownException
clean_unixsocket
end
end
end # module M
interactive mode
#M::setpass_interactive(“user”)
#puts M::getpass(“user”)[
daemon mode
M::main_loop()
end server
client
#!/usr/bin/env ruby -wKU
require ‘socket’
require ‘rubygems’
require ‘termios’
PASS_UNIX_SOCK="/tmp/my.sock"
unless File.exists? PASS_UNIX_SOCK
puts “server is not running”
exit
end
enable/disable echo on prompt
def echo(on=true, masked=false)
term = Termios::getattr( $stdin )
if on
term.c_lflag |= ( Termios::ECHO | Termios::ICANON )
else # off
term.c_lflag &= ~Termios::ECHO
term.c_lflag &= ~Termios::ICANON if masked
end
Termios::setattr( $stdin, Termios::TCSANOW, term )
end
print “user:”
user = Kernel.gets.strip
puts “”
print "#{user}'s password: "
echo(false)
passwd = Kernel.gets.chomp
UNIXSocket.open PASS_UNIX_SOCK do |socket|
socket.write_nonblock("#{user} #{passwd}")
end
echo(true)
puts “”
puts “Thank you for providing the necessary information”
end client
regards, Sandor
Szücs