module OnceOnly::Sha1
Public Class Methods
sha1(string)
click to toggle source
Calculates SHA-1 message digest of string. Returns binary digest. For hexadecimal digest, use +*sha1(string).unpack(‘H*’)+.
# File lib/once-only/sha1.rb, line 15 def Sha1::sha1(string) # functions and constants mask = (1 << 32) - 1 s = proc{|n, x| ((x << n) & mask) | (x >> (32 - n))} f = [ proc {|b, c, d| (b & c) | (b.^(mask) & d)}, proc {|b, c, d| b ^ c ^ d}, proc {|b, c, d| (b & c) | (b & d) | (c & d)}, proc {|b, c, d| b ^ c ^ d}, ].freeze k = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6].freeze # initial hash h = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0] io = StringIO.new(string) block = "" term = false # appended "\x80" in second-last block? last = false # last block? until last # Read next block of 16 words (64 bytes, 512 bits). io.read(64, block) or ( # Work around a bug in Rubinius 1.2.4. At eof, # MRI and JRuby already replace block with "". block.replace("") ) # Unpack block into 32-bit words "N". case len = block.length when 64 # Unpack 16 words. w = block.unpack("N16") when 56..63 # Second-last block: append padding, unpack 16 words. block.concat("\x80"); term = true block.concat("\0" * (63 - len)) w = block.unpack("N16") when 0..55 # Last block: append padding, unpack 14 words. block.concat(term ? "\0" : "\x80") block.concat("\0" * (55 - len)) w = block.unpack("N14") # Append bit length, 2 words. bit_len = string.length << 3 w.push(bit_len >> 32, bit_len & mask) last = true else fail "impossible" end # Process block. (16..79).each {|t| w[t] = s[1, w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]]} a, b, c, d, e = h[0..4] t = 0 (0..3).each {|i| 20.times { temp = (s[5, a] + f[i][b, c, d] + e + w[t] + k[i]) & mask e = d; d = c; c = s[30, b]; b = a; a = temp t += 1}} h[0] = (h[0] + a) & mask h[1] = (h[1] + b) & mask h[2] = (h[2] + c) & mask h[3] = (h[3] + d) & mask h[4] = (h[4] + e) & mask end # h.join('').hex.to_s # p h p sprintf("%08X","10") -> 0000000A h.map { |n| sprintf("%08x",n) }.join('') end