Created
April 18, 2011 14:08
-
-
Save tstevens/925415 to your computer and use it in GitHub Desktop.
Implementation of SHA-1 Hash in pure ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#http://stackoverflow.com/questions/5940316/left-rotate-through-carry-in-ruby | |
class Integer | |
def lotate(n=1) | |
self << n | self >> (32 - n) | |
end | |
end | |
# FIPS 180-2 -- relevant section #'s below | |
# Pulls parts from Wiki pseudocode and http://ruby.janlelis.de/17-sha-256 | |
class SHA1 | |
def self.digest(input) | |
# 5.3.1 - Initial hash value | |
z = 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 | |
# 5.1.1 | |
length = input.length*8 | |
input << 0x80 | |
input << 0 while input.size%64 != 56 | |
input += [length].pack('Q').reverse | |
#6.1.2 | |
input.unpack('C*').each_slice(64){|chunk| | |
#6.1.2 - 1. Prepare the message schedule | |
w = [] | |
chunk.each_slice(4){|a,b,c,d| w << (((a<<8|b)<<8|c)<<8|d) } | |
#Expand from sixteen to eighty -- 6.1.2 - 1. Prepare the message schedule | |
(16..79).map{|i| | |
w[i] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]).lotate & 0xffffffff | |
} | |
#6.1.2 - 2. Initialize the five working variables. | |
a,b,c,d,e = z | |
(0..79).each{|i| # 6.1.2 - 3. & 4.1.1 - SHA-1 Functions | |
case i | |
when 0..19 | |
f = ((b & c) | (~b & d)) | |
k = 0x5A827999 | |
when 20..39 | |
f = (b ^ c ^ d) | |
k = 0x6ED9EBA1 | |
when 40..59 | |
f = ((b & c) | (b & d) | (c & d)) | |
k = 0x8F1BBCDC | |
when 60..79 | |
f = (b ^ c ^ d) | |
k = 0xCA62C1D6 | |
end | |
temp = (a.lotate(5) & 0xffffffff) + f + e + k + w[i] & 0xffffffff | |
e = d | |
d = c | |
c = b.lotate(30) & 0xffffffff | |
b = a | |
a = temp | |
} | |
# 6.1.2 - 4. Compute the ith intermediate hash value | |
z[0] = z[0] + a & 0xffffffff | |
z[1] = z[1] + b & 0xffffffff | |
z[2] = z[2] + c & 0xffffffff | |
z[3] = z[3] + d & 0xffffffff | |
z[4] = z[4] + e & 0xffffffff | |
} | |
# Produce the final hash value (big-endian) | |
return '%.8x'*5 % z | |
end | |
end | |
if $0 == __FILE__ | |
input = gets(nil) || '' | |
if RUBY_VERSION >= '1.9' | |
input = input.force_encoding('US-ASCII') | |
end | |
puts SHA1.digest(input) | |
end |
Hey, can you please explain this expression?
'%.8x'*5 % z
Thanks!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Over a year behind but I finally fixed this up. Both the NoMethodError and padding issues have been resolved with this update!