Quick *nix shadow passwords with Ruby
by Kenneth Kalmer on May 1, 2009
Just thought I’d share this one to boost the available online information. Using String#crypt and man crypt you’ll come up with something similar to the gist below (extract from a project I’m busy working on).
module Linux class User class << self # Generate an MD5 salt string def salt seeds = ('a'..'z').to_a seeds.concat( ('A'..'Z').to_a ) seeds.concat( (0..9).to_a ) seeds.concat ['/', '.'] seeds.compact! salt_string = '$1$' 8.times { salt_string << seeds[ rand(seeds.size) ].to_s } salt_string end # Crypt a password suitable for use in shadow files def crypt( string ) string.crypt( self.salt ) end end end end
And the spec
require File.dirname(__FILE__) + '/../spec_helper' describe Linux::User do describe "generating shadow passwords" do it "should generate a salt for crypt" do salt = Linux::User.salt salt.length.should be(11) salt.should match(/^\$1\$[a-zA-Z0-9\.\/]{8}$/) end it "should generate a shadow password" do pass = Linux::User.crypt( 'secret' ) pass.should match(/^\$1\$[a-zA-Z0-9\.\/]{8}\$[a-zA-Z0-9\.\/]{22}$/) pass.length.should be(34) end end end
HTH
3 comments
from the doc:
“Applies a one-way cryptographic hash to str by invoking the standard library function crypt. The argument is the salt string, which should be two characters long, each character drawn from [a-zA-Z0-9./].”
so only the first 2 chars will be used
>> “secret”.crypt “ab”
=> “abNANd1rDfiNc”
>> “secret”.crypt “abcd”
=> “abNANd1rDfiNc”
>> “secret”.crypt “abcdefgh”
=> “abNANd1rDfiNc”
by Brian Demant on May 1, 2009 at 3:32 pm. #
@Brian yes, and no. Ruby uses the underlying linux crypt function (see man crypt). By default it uses a DES encryption scheme which does exactly what you said, but with glibc2 on the host things change. From the man page: If salt is a character string starting with the characters “$id$” followed by a string terminated by “$”: $id$salt$encrypted then instead of using the DES machine, id identifies the encryption method used and this then determines how the rest of the password string is interpreted.
=> “abNANd1rDfiNc”
irb(main):002:0> “secret”.crypt(“abasasa”)
=> “abNANd1rDfiNc”
irb(main):003:0> “secret”.crypt(“$1$abasasa”)
=> “$1$abasasa$2RZY2vd6E2ZEPSDa0eLec0″
irb(main):004:0> “secret”.crypt(“$1$abasa”)
=> “$1$abasa$ikoKICgwOFdcWgmDl9Asy1″
You can clearly see how the behavior of the crypt method changes in the latter calls. The Ruby rdoc’s are confusing in this regard.
by Kenneth Kalmer on May 1, 2009 at 3:40 pm. #
Thanks for this and the comment explaining the way crypt works with different formats of salts. That’s trick!
Here’s my version: http://d.strelau.net/post/220354423/shadow-passwords-in-ruby
by Dean Strelau on October 23, 2009 at 12:49 am. #