# How to manage passwords

**URL:** <https://www.ruby-forum.com/t/how-to-manage-passwords/149070>\
**Category:** Ruby\
**Created:** [September 20, 2008, 12:00am UTC](https://www.ruby-forum.com/t/how-to-manage-passwords/149070 "2008-09-20T00:00:50Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Junkone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e274bd/32.png) [@Junkone](https://www.ruby-forum.com/u/Junkone)\
**Post date:** [September 20, 2008, 12:00am UTC](https://www.ruby-forum.com/t/how-to-manage-passwords/149070/1 "2008-09-20T00:00:50Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Junkone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e274bd/32.png) [@Junkone](https://www.ruby-forum.com/u/Junkone)\
**Post date:** [September 20, 2008, 12:48am UTC](https://www.ruby-forum.com/t/how-to-manage-passwords/149070/2 "2008-09-20T00:48:19Z")

</div>

You may be looking for this:  
[http://www.ruby-doc.org/core/classes/Base64.html#M004726](http://www.ruby-doc.org/core/classes/Base64.html#M004726)

---

<div class="post-metadata">

**Author:** ![Junkone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e274bd/32.png) [@Junkone](https://www.ruby-forum.com/u/Junkone)\
**Post date:** [September 20, 2008, 6:01pm UTC](https://www.ruby-forum.com/t/how-to-manage-passwords/149070/3 "2008-09-20T18:01:09Z")

</div>

On 19 set, 18:55, Junkone [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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

---

<div class="post-metadata">

**Author:** ![Junkone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e274bd/32.png) [@Junkone](https://www.ruby-forum.com/u/Junkone)\
**Post date:** [September 21, 2008, 10:56am UTC](https://www.ruby-forum.com/t/how-to-manage-passwords/149070/4 "2008-09-21T10:56:48Z")

</div>

On Sun, Sep 21, 2008 at 12:52:05AM +0900, removed\_email\_address@domain.invalid 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.

---

<div class="post-metadata">

**Author:** ![Junkone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e274bd/32.png) [@Junkone](https://www.ruby-forum.com/u/Junkone)\
**Post date:** [September 22, 2008, 6:08am UTC](https://www.ruby-forum.com/t/how-to-manage-passwords/149070/5 "2008-09-22T06:08:51Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Junkone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e274bd/32.png) [@Junkone](https://www.ruby-forum.com/u/Junkone)\
**Post date:** [September 22, 2008, 5:39pm UTC](https://www.ruby-forum.com/t/how-to-manage-passwords/149070/6 "2008-09-22T17:39:22Z")

</div>

On Sep 22, 12:00 am, Justin C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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.

---

<div class="post-metadata">

**Author:** ![Junkone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e274bd/32.png) [@Junkone](https://www.ruby-forum.com/u/Junkone)\
**Post date:** [September 22, 2008, 8:23pm UTC](https://www.ruby-forum.com/t/how-to-manage-passwords/149070/7 "2008-09-22T20:23:58Z")

</div>

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.

😕

---

<div class="post-metadata">

**Author:** ![Junkone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/e274bd/32.png) [@Junkone](https://www.ruby-forum.com/u/Junkone)\
**Post date:** [October 19, 2008, 9:34pm UTC](https://www.ruby-forum.com/t/how-to-manage-passwords/149070/8 "2008-10-19T21:34:47Z")

</div>

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/](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
