views:

136

answers:

3

Two quick questions about ruby's string#crypt(salt) method.

  1. In the documentation it claims the salt should be two characters? I thought a salt could be anything I wanted, no? I am using a random value that is larger than two characters and it seems to work fine. Is this an error in the documentation or in my understanding of how this works?

  2. Currently it generates a string that is ~15 chars. I'd like to generate something longer, at least 32 chars. Is there a way to do this with built in ruby functionality? If not, what is a recommended gem/plugin to use to simply generate a (longer) hash given a string val?

Thank you,

Tom

+2  A: 

String#crypt ignores any extra characters, so only the first two are used.

"foobar".crypt("abc") # => abVbJXzHUY99s
"foobar".crypt("abd") # => abVbJXzHUY99s

Instead, you can use SHA1 to give you a 40 character encryption and allow any length of salt.

require 'digest/sha1'
Digest::SHA1.hexdigest("foobar" + "abc") # => 17dd6cae99582672c4b2ccc78fe4ad0888559ce7
Digest::SHA1.hexdigest("foobar" + "abd") # => 8aba27fd409286946504ac78098c41549d182316

UPDATE: as Gaius pointed out, SHA1 is not best for production. Instead use SHA256 or SHA512. See his response for details.

ryanb
Thank you again good sir. :)
cakeforcerberus
You've got the right idea, ryanb, but SHA1 is outdated. Just do gsub('1', '2') on your code and it's great!
James A. Rosen
(Well, at least for the next couple of years)
James A. Rosen
+2  A: 

According to "Cryptographic Right Answers (which I advise reading and listening to unless you really know what you're doing . . . and almost nobody does), SHA1 is too broken for production code. Use SHA256:

require 'digest/sha2'
Digest::SHA2.hexdigest("foobar" + "abc") # => "32ef4da9bcfbbe1..." (64 chars)
Digest::SHA2.hexdigest("foobar" + "abd") # => "f5e363e77f14e07..." (64 chars)

Or SHA512:

require 'digest/sha2'
digest = Digest::SHA2.new(512)
digest << 'foobar'
digest << 'abc'
digest.to_s                              # => ""415d4ca2647d17..." (128 chars)

digest.reset
digest << 'foobar'
digest << 'abd'
digest.to_s                              # => ""93fbbe3b6a7aac..." (128 chars)
James A. Rosen
Neat. I'll check it out, thanks. +1
cakeforcerberus
+2  A: 

I'd use bcrypt-ruby. Bcrypt is a more secure hashing algorithm, as it's designed to be computationally expensive and thus slow, whereas Sha variants are much faster. This makes brute-forcing even more difficult.

ehsanul
That's interesting, I'll look into it. Thanks :) +1
cakeforcerberus
Also a great point. It's important to consider side-channel attacks and timing attacks!
James A. Rosen