|
| 1 | +-- $Revision: 1.5 $ |
| 2 | +-- $Date: 2014-09-10 16:54:25 $ |
| 3 | + |
| 4 | +-- This module was originally taken from http://cube3d.de/uploads/Main/sha1.txt. |
| 5 | + |
| 6 | +------------------------------------------------------------------------------- |
| 7 | +-- SHA-1 secure hash computation, and HMAC-SHA1 signature computation, |
| 8 | +-- in pure Lua (tested on Lua 5.1) |
| 9 | +-- License: MIT |
| 10 | +-- |
| 11 | +-- Usage: |
| 12 | +-- local hashAsHex = sha1.hex(message) -- returns a hex string |
| 13 | +-- local hashAsData = sha1.bin(message) -- returns raw bytes |
| 14 | +-- |
| 15 | +-- local hmacAsHex = sha1.hmacHex(key, message) -- hex string |
| 16 | +-- local hmacAsData = sha1.hmacBin(key, message) -- raw bytes |
| 17 | +-- |
| 18 | +-- |
| 19 | +-- Pass sha1.hex() a string, and it returns a hash as a 40-character hex string. |
| 20 | +-- For example, the call |
| 21 | +-- |
| 22 | +-- local hash = sha1.hex("iNTERFACEWARE") |
| 23 | +-- |
| 24 | +-- puts the 40-character string |
| 25 | +-- |
| 26 | +-- "e76705ffb88a291a0d2f9710a5471936791b4819" |
| 27 | +-- |
| 28 | +-- into the variable 'hash' |
| 29 | +-- |
| 30 | +-- Pass sha1.hmacHex() a key and a message, and it returns the signature as a |
| 31 | +-- 40-byte hex string. |
| 32 | +-- |
| 33 | +-- |
| 34 | +-- The two "bin" versions do the same, but return the 20-byte string of raw |
| 35 | +-- data that the 40-byte hex strings represent. |
| 36 | +-- |
| 37 | +------------------------------------------------------------------------------- |
| 38 | +-- |
| 39 | +-- Description |
| 40 | +-- Due to the lack of bitwise operations in 5.1, this version uses numbers to |
| 41 | +-- represents the 32bit words that we combine with binary operations. The basic |
| 42 | +-- operations of byte based "xor", "or", "and" are all cached in a combination |
| 43 | +-- table (several 64k large tables are built on startup, which |
| 44 | +-- consumes some memory and time). The caching can be switched off through |
| 45 | +-- setting the local cfg_caching variable to false. |
| 46 | +-- For all binary operations, the 32 bit numbers are split into 8 bit values |
| 47 | +-- that are combined and then merged again. |
| 48 | +-- |
| 49 | +-- Algorithm: http://www.itl.nist.gov/fipspubs/fip180-1.htm |
| 50 | +-- |
| 51 | +------------------------------------------------------------------------------- |
| 52 | + |
| 53 | +local sha1 = (function() |
| 54 | +local sha1 = {} |
| 55 | + |
| 56 | +-- set this to false if you don't want to build several 64k sized tables when |
| 57 | +-- loading this file (takes a while but grants a boost of factor 13) |
| 58 | +local cfg_caching = false |
| 59 | +-- local storing of global functions (minor speedup) |
| 60 | +local floor,modf = math.floor,math.modf |
| 61 | +local char,format,rep = string.char,string.format,string.rep |
| 62 | + |
| 63 | +-- merge 4 bytes to an 32 bit word |
| 64 | +local function bytes_to_w32 (a,b,c,d) return a*0x1000000+b*0x10000+c*0x100+d end |
| 65 | +-- split a 32 bit word into four 8 bit numbers |
| 66 | +local function w32_to_bytes (i) |
| 67 | + return floor(i/0x1000000)%0x100,floor(i/0x10000)%0x100,floor(i/0x100)%0x100,i%0x100 |
| 68 | +end |
| 69 | + |
| 70 | +-- shift the bits of a 32 bit word. Don't use negative values for "bits" |
| 71 | +local function w32_rot (bits,a) |
| 72 | + local b2 = 2^(32-bits) |
| 73 | + local a,b = modf(a/b2) |
| 74 | + return a+b*b2*(2^(bits)) |
| 75 | +end |
| 76 | + |
| 77 | +-- caching function for functions that accept 2 arguments, both of values between |
| 78 | +-- 0 and 255. The function to be cached is passed, all values are calculated |
| 79 | +-- during loading and a function is returned that returns the cached values (only) |
| 80 | +local function cache2arg (fn) |
| 81 | + if not cfg_caching then return fn end |
| 82 | + local lut = {} |
| 83 | + for i=0,0xffff do |
| 84 | + local a,b = floor(i/0x100),i%0x100 |
| 85 | + lut[i] = fn(a,b) |
| 86 | + end |
| 87 | + return function (a,b) |
| 88 | + return lut[a*0x100+b] |
| 89 | + end |
| 90 | +end |
| 91 | + |
| 92 | +-- splits an 8-bit number into 8 bits, returning all 8 bits as booleans |
| 93 | +local function byte_to_bits (b) |
| 94 | + local b = function (n) |
| 95 | + local b = floor(b/n) |
| 96 | + return b%2==1 |
| 97 | + end |
| 98 | + return b(1),b(2),b(4),b(8),b(16),b(32),b(64),b(128) |
| 99 | +end |
| 100 | + |
| 101 | +-- builds an 8bit number from 8 booleans |
| 102 | +local function bits_to_byte (a,b,c,d,e,f,g,h) |
| 103 | + local function n(b,x) return b and x or 0 end |
| 104 | + return n(a,1)+n(b,2)+n(c,4)+n(d,8)+n(e,16)+n(f,32)+n(g,64)+n(h,128) |
| 105 | +end |
| 106 | + |
| 107 | +-- debug function for visualizing bits in a string |
| 108 | +local function bits_to_string (a,b,c,d,e,f,g,h) |
| 109 | + local function x(b) return b and "1" or "0" end |
| 110 | + return ("%s%s%s%s %s%s%s%s"):format(x(a),x(b),x(c),x(d),x(e),x(f),x(g),x(h)) |
| 111 | +end |
| 112 | + |
| 113 | +-- debug function for converting a 8-bit number as bit string |
| 114 | +local function byte_to_bit_string (b) |
| 115 | + return bits_to_string(byte_to_bits(b)) |
| 116 | +end |
| 117 | + |
| 118 | +-- debug function for converting a 32 bit number as bit string |
| 119 | +local function w32_to_bit_string(a) |
| 120 | + if type(a) == "string" then return a end |
| 121 | + local aa,ab,ac,ad = w32_to_bytes(a) |
| 122 | + local s = byte_to_bit_string |
| 123 | + return ("%s %s %s %s"):format(s(aa):reverse(),s(ab):reverse(),s(ac):reverse(),s(ad):reverse()):reverse() |
| 124 | +end |
| 125 | + |
| 126 | +-- bitwise "and" function for 2 8bit number |
| 127 | +local band = cache2arg (function(a,b) |
| 128 | + local A,B,C,D,E,F,G,H = byte_to_bits(b) |
| 129 | + local a,b,c,d,e,f,g,h = byte_to_bits(a) |
| 130 | + return bits_to_byte( |
| 131 | + A and a, B and b, C and c, D and d, |
| 132 | + E and e, F and f, G and g, H and h) |
| 133 | + end) |
| 134 | + |
| 135 | +-- bitwise "or" function for 2 8bit numbers |
| 136 | +local bor = cache2arg(function(a,b) |
| 137 | + local A,B,C,D,E,F,G,H = byte_to_bits(b) |
| 138 | + local a,b,c,d,e,f,g,h = byte_to_bits(a) |
| 139 | + return bits_to_byte( |
| 140 | + A or a, B or b, C or c, D or d, |
| 141 | + E or e, F or f, G or g, H or h) |
| 142 | + end) |
| 143 | + |
| 144 | +-- bitwise "xor" function for 2 8bit numbers |
| 145 | +local bxor = cache2arg(function(a,b) |
| 146 | + local A,B,C,D,E,F,G,H = byte_to_bits(b) |
| 147 | + local a,b,c,d,e,f,g,h = byte_to_bits(a) |
| 148 | + return bits_to_byte( |
| 149 | + A ~= a, B ~= b, C ~= c, D ~= d, |
| 150 | + E ~= e, F ~= f, G ~= g, H ~= h) |
| 151 | + end) |
| 152 | + |
| 153 | +-- bitwise complement for one 8bit number |
| 154 | +local function bnot (x) |
| 155 | + return 255-(x % 256) |
| 156 | +end |
| 157 | + |
| 158 | +-- creates a function to combine to 32bit numbers using an 8bit combination function |
| 159 | +local function w32_comb(fn) |
| 160 | + return function (a,b) |
| 161 | + local aa,ab,ac,ad = w32_to_bytes(a) |
| 162 | + local ba,bb,bc,bd = w32_to_bytes(b) |
| 163 | + return bytes_to_w32(fn(aa,ba),fn(ab,bb),fn(ac,bc),fn(ad,bd)) |
| 164 | + end |
| 165 | +end |
| 166 | + |
| 167 | +-- create functions for and, xor and or, all for 2 32bit numbers |
| 168 | +local w32_and = w32_comb(band) |
| 169 | +local w32_xor = w32_comb(bxor) |
| 170 | +local w32_or = w32_comb(bor) |
| 171 | + |
| 172 | +-- xor function that may receive a variable number of arguments |
| 173 | +local function w32_xor_n (a,...) |
| 174 | + local aa,ab,ac,ad = w32_to_bytes(a) |
| 175 | + for i=1,select('#',...) do |
| 176 | + local ba,bb,bc,bd = w32_to_bytes(select(i,...)) |
| 177 | + aa,ab,ac,ad = bxor(aa,ba),bxor(ab,bb),bxor(ac,bc),bxor(ad,bd) |
| 178 | + end |
| 179 | + return bytes_to_w32(aa,ab,ac,ad) |
| 180 | +end |
| 181 | + |
| 182 | +-- combining 3 32bit numbers through binary "or" operation |
| 183 | +local function w32_or3 (a,b,c) |
| 184 | + local aa,ab,ac,ad = w32_to_bytes(a) |
| 185 | + local ba,bb,bc,bd = w32_to_bytes(b) |
| 186 | + local ca,cb,cc,cd = w32_to_bytes(c) |
| 187 | + return bytes_to_w32( |
| 188 | + bor(aa,bor(ba,ca)), bor(ab,bor(bb,cb)), bor(ac,bor(bc,cc)), bor(ad,bor(bd,cd)) |
| 189 | + ) |
| 190 | +end |
| 191 | + |
| 192 | +-- binary complement for 32bit numbers |
| 193 | +local function w32_not (a) |
| 194 | + return 4294967295-(a % 4294967296) |
| 195 | +end |
| 196 | + |
| 197 | +-- adding 2 32bit numbers, cutting off the remainder on 33th bit |
| 198 | +local function w32_add (a,b) return (a+b) % 4294967296 end |
| 199 | + |
| 200 | +-- adding n 32bit numbers, cutting off the remainder (again) |
| 201 | +local function w32_add_n (a,...) |
| 202 | + for i=1,select('#',...) do |
| 203 | + a = (a+select(i,...)) % 4294967296 |
| 204 | + end |
| 205 | + return a |
| 206 | +end |
| 207 | +-- converting the number to a hexadecimal string |
| 208 | +local function w32_to_hexstring (w) return format("%08x",w) end |
| 209 | + |
| 210 | +-- calculating the SHA1 for some text |
| 211 | +function sha1.hex(msg) |
| 212 | + local H0,H1,H2,H3,H4 = 0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0 |
| 213 | + local msg_len_in_bits = #msg * 8 |
| 214 | + |
| 215 | + local first_append = char(0x80) -- append a '1' bit plus seven '0' bits |
| 216 | + |
| 217 | + local non_zero_message_bytes = #msg +1 +8 -- the +1 is the appended bit 1, the +8 are for the final appended length |
| 218 | + local current_mod = non_zero_message_bytes % 64 |
| 219 | + local second_append = current_mod>0 and rep(char(0), 64 - current_mod) or "" |
| 220 | + |
| 221 | + -- now to append the length as a 64-bit number. |
| 222 | + local B1, R1 = modf(msg_len_in_bits / 0x01000000) |
| 223 | + local B2, R2 = modf( 0x01000000 * R1 / 0x00010000) |
| 224 | + local B3, R3 = modf( 0x00010000 * R2 / 0x00000100) |
| 225 | + local B4 = 0x00000100 * R3 |
| 226 | + |
| 227 | + local L64 = char( 0) .. char( 0) .. char( 0) .. char( 0) -- high 32 bits |
| 228 | + .. char(B1) .. char(B2) .. char(B3) .. char(B4) -- low 32 bits |
| 229 | + |
| 230 | + msg = msg .. first_append .. second_append .. L64 |
| 231 | + |
| 232 | + assert(#msg % 64 == 0) |
| 233 | + |
| 234 | + local chunks = #msg / 64 |
| 235 | + |
| 236 | + local W = { } |
| 237 | + local start, A, B, C, D, E, f, K, TEMP |
| 238 | + local chunk = 0 |
| 239 | + |
| 240 | + while chunk < chunks do |
| 241 | + -- |
| 242 | + -- break chunk up into W[0] through W[15] |
| 243 | + -- |
| 244 | + start,chunk = chunk * 64 + 1,chunk + 1 |
| 245 | + |
| 246 | + for t = 0, 15 do |
| 247 | + W[t] = bytes_to_w32(msg:byte(start, start + 3)) |
| 248 | + start = start + 4 |
| 249 | + end |
| 250 | + |
| 251 | + -- |
| 252 | + -- build W[16] through W[79] |
| 253 | + -- |
| 254 | + for t = 16, 79 do |
| 255 | + -- For t = 16 to 79 let Wt = S1(Wt-3 XOR Wt-8 XOR Wt-14 XOR Wt-16). |
| 256 | + W[t] = w32_rot(1, w32_xor_n(W[t-3], W[t-8], W[t-14], W[t-16])) |
| 257 | + end |
| 258 | + |
| 259 | + A,B,C,D,E = H0,H1,H2,H3,H4 |
| 260 | + |
| 261 | + for t = 0, 79 do |
| 262 | + if t <= 19 then |
| 263 | + -- (B AND C) OR ((NOT B) AND D) |
| 264 | + f = w32_or(w32_and(B, C), w32_and(w32_not(B), D)) |
| 265 | + K = 0x5A827999 |
| 266 | + elseif t <= 39 then |
| 267 | + -- B XOR C XOR D |
| 268 | + f = w32_xor_n(B, C, D) |
| 269 | + K = 0x6ED9EBA1 |
| 270 | + elseif t <= 59 then |
| 271 | + -- (B AND C) OR (B AND D) OR (C AND D |
| 272 | + f = w32_or3(w32_and(B, C), w32_and(B, D), w32_and(C, D)) |
| 273 | + K = 0x8F1BBCDC |
| 274 | + else |
| 275 | + -- B XOR C XOR D |
| 276 | + f = w32_xor_n(B, C, D) |
| 277 | + K = 0xCA62C1D6 |
| 278 | + end |
| 279 | + |
| 280 | + -- TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt; |
| 281 | + A,B,C,D,E = w32_add_n(w32_rot(5, A), f, E, W[t], K), |
| 282 | + A, w32_rot(30, B), C, D |
| 283 | + end |
| 284 | + -- Let H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E. |
| 285 | + H0,H1,H2,H3,H4 = w32_add(H0, A),w32_add(H1, B),w32_add(H2, C),w32_add(H3, D),w32_add(H4, E) |
| 286 | + end |
| 287 | + local f = w32_to_hexstring |
| 288 | + return f(H0) .. f(H1) .. f(H2) .. f(H3) .. f(H4) |
| 289 | +end |
| 290 | + |
| 291 | +local function hex_to_binary(hex) |
| 292 | + return hex:gsub('..', function(hexval) |
| 293 | + return string.char(tonumber(hexval, 16)) |
| 294 | + end) |
| 295 | +end |
| 296 | + |
| 297 | +function sha1.bin(msg) |
| 298 | + return hex_to_binary(sha1.hex(msg)) |
| 299 | +end |
| 300 | + |
| 301 | +local xor_with_0x5c = {} |
| 302 | +local xor_with_0x36 = {} |
| 303 | +-- building the lookuptables ahead of time (instead of littering the source code |
| 304 | +-- with precalculated values) |
| 305 | +for i=0,0xff do |
| 306 | + xor_with_0x5c[char(i)] = char(bxor(i,0x5c)) |
| 307 | + xor_with_0x36[char(i)] = char(bxor(i,0x36)) |
| 308 | +end |
| 309 | + |
| 310 | +local blocksize = 64 -- 512 bits |
| 311 | + |
| 312 | +function sha1.hmacHex(key, text) |
| 313 | + assert(type(key) == 'string', "key passed to hmacHex should be a string") |
| 314 | + assert(type(text) == 'string', "text passed to hmacHex should be a string") |
| 315 | + |
| 316 | + if #key > blocksize then |
| 317 | + key = sha1.bin(key) |
| 318 | + end |
| 319 | + |
| 320 | + local key_xord_with_0x36 = key:gsub('.', xor_with_0x36) .. string.rep(string.char(0x36), blocksize - #key) |
| 321 | + local key_xord_with_0x5c = key:gsub('.', xor_with_0x5c) .. string.rep(string.char(0x5c), blocksize - #key) |
| 322 | + |
| 323 | + return sha1.hex(key_xord_with_0x5c .. sha1.bin(key_xord_with_0x36 .. text)) |
| 324 | +end |
| 325 | + |
| 326 | +function sha1.hmacBin(key, text) |
| 327 | + return hex_to_binary(sha1.hmacHex(key, text)) |
| 328 | +end |
| 329 | + |
| 330 | +return sha1 |
| 331 | +end)() |
| 332 | + |
0 commit comments