Skip to content

Instantly share code, notes, and snippets.

@e0da
Created March 6, 2012 23:35
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save e0da/1989787 to your computer and use it in GitHub Desktop.
Save e0da/1989787 to your computer and use it in GitHub Desktop.
Hashing and checking SSHA passwords in Ruby
#!/usr/bin/env ruby
require 'base64'
require 'digest'
# get 16 random hex bytes
#
def new_salt
16.times.inject('') {|t| t << rand(16).to_s(16)}
end
# hash the password using the given salt. If no salt is supplied, use a new
# one.
#
def hash_password(password, salt=new_salt)
"{SSHA}" + Base64.encode64("#{Digest::SHA1.digest("#{password}#{salt}")}#{salt}").chomp
end
# Check the supplied password against the given hash and return true if they
# match, else false.
#
def check_password(password, ssha)
decoded = Base64.decode64(ssha.gsub(/^{SSHA}/, ''))
hash = decoded[0,20] # isolate the hash
salt = decoded[20,-1] # isolate the salt
hash_password(password, salt) == ssha
end
# a single argument just requests the hash for the supplied password. two
# arguments check the first (a password) against the second (an SSHA hash of a
# password)
#
ARGV[0] = ARGV[0].gsub /^"(.*)"$/, '$1'
if ARGV[1]
puts check_password ARGV[0], ARGV[1]
else
puts hash_password ARGV[0]
end
@ioquatix
Copy link

ioquatix commented Nov 11, 2016

Awesome, thanks so much for this example! I made some small changes to use SecureRandom:

require 'securerandom'
require 'digest/sha1'
require 'base64'

# Generate 16 hex characters of random
def generate_salt
	SecureRandom.hex(16)
end

# Hash the password using the given salt. If no salt is supplied, use a new
# one.
def encode_password(plaintext, salt=generate_salt)
	raise ArgumentError.new("Password must not be nil") if plaintext.nil?
	raise ArgumentError.new("Password must be at least 4 characters") if plaintext.size < 4
	
	ssha = Digest::SHA1.digest(plaintext+salt) + salt

	return "{SSHA}" + Base64.strict_encode64(ssha).chomp
end

# Check the supplied password against the given hash and return true if they
# match, else false.
def check_password(password, ssha)
	decoded = Base64.decode64(ssha.gsub(/^{SSHA}/, ''))
	hash = decoded[0,20] # isolate the hash
	salt = decoded[20,-1] # isolate the salt
	
	return encode_password(password, salt) == ssha
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment