Skip to content

Instantly share code, notes, and snippets.

@AMD-NICK
Created March 11, 2019 18:07
Show Gist options
  • Save AMD-NICK/ea1a8cf55ec2202683db2062d966ece5 to your computer and use it in GitHub Desktop.
Save AMD-NICK/ea1a8cf55ec2202683db2062d966ece5 to your computer and use it in GitHub Desktop.
Попытка перенести github.com/user-none/lua-hashings в Garry's Mod. Начал с sha1, т.к. нужен был sha1.hmac, но нашел его здесь: https://qweqwe.ovh/gmod-sha1-hmac и забил

Проблема

PRINT(sha1("123keker"):digest())

выбивает ошибку, что uintn.u32 возвращает таблицу вместо числа (надо просто __tonumber добавить)

Но я начал копать в uintn.32 и заметил, что оно неправильно делает сдвиг битов: должно так, а делает так

Решение

Надо пофиксить этот сдвиг и все должно работать, НО я нашел готовое решение здесь

Сделано

  • заменил все бинарные и простые (а-я //) операторы с lua 5.3 на gluaшную
  • убрал пару лишних кусков и require
  • сделал, чтобы при ране этих файлов сразу создавались нужные функции (снизу каждого файла) и не надо было отдельно куда-то инклюдить
-- Copyright (c) 2016 John Schember <john@nachtimwald.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining
-- a copy of this software and associated documentation files (the "Software"),
-- to deal in the Software without restriction, including without limitation
-- the rights to use, copy, modify, merge, publish, distribute, sublicense,
-- and/or sell copies of the Software, and to permit persons to whom the
-- Software is furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-- DEALINGS IN THE SOFTWARE.
local M = {}
local M_mt = { __metatable = {}, __index = M }
function M:new(hm, key, data)
local th
local tk = {}
local ipad = {}
if self ~= M then
return nil, "First argument must be self"
end
local o = setmetatable({}, M_mt)
o._hm = hm
-- Compute the key.
if #key > hm.block_size then
th = hm(key)
key = th:digest()
end
for i=1,#key do
tk[#tk+1] = string.byte(key, i)
end
for i=#key+1,hm.block_size do
tk[#tk+1] = 0
end
-- Generate the inner and outer padding.
o._opad = {}
for i=1,#tk do
ipad[i] = string.char(bit.bxor(tk[i], 0x36))
o._opad[i] = string.char(bit.bxor(tk[i], 0x5C))
end
ipad = table.concat(ipad)
o._opad = table.concat(o._opad)
-- Start the hash witht the inner padding
o._hash = o._hm(ipad)
if data ~= nil then
o._hash:update(data)
end
return o
end
setmetatable(M, { __call = M.new })
function M:copy()
local o = setmetatable({}, M_mt)
o._hm = self._hm
o._hash = self._hash:copy()
o._opad = self._opad
return o
end
function M:update(data)
self._hash:update(data)
end
function M:digest()
local final
local digest
local th
final = self:copy()
digest = final._hash:digest()
th = final._hm(final._opad)
th:update(digest)
return th:digest()
end
function M:hexdigest()
local h
local out = {}
h = self:digest()
for i=1,#h do
out[i] = string.format("%02X", string.byte(h, i))
end
return table.concat(out)
end
hmac = M
-- Copyright (c) 2016 John Schember <john@nachtimwald.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining
-- a copy of this software and associated documentation files (the "Software"),
-- to deal in the Software without restriction, including without limitation
-- the rights to use, copy, modify, merge, publish, distribute, sublicense,
-- and/or sell copies of the Software, and to permit persons to whom the
-- Software is furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-- DEALINGS IN THE SOFTWARE.
local M = {}
local M_mt = { __metatable = {}, __index = M }
M.digest_size = 20
M.block_size = 64
local u32 = uintn.u32
local function rotate_left(x, n)
return bit.bor(bit.lshift(x,n), bit.rshift(x, 32-n))
end
function M:new(data)
if self ~= M then
return nil, "First argument must be self"
end
local o = setmetatable({}, M_mt)
o._H0 = u32(0x67452301)
o._H1 = u32(0xEFCDAB89)
o._H2 = u32(0x98BADCFE)
o._H3 = u32(0x10325476)
o._H4 = u32(0xC3D2E1F0)
o._len = 0
o._data = ""
if data ~= nil then
o:update(data)
end
return o
end
setmetatable(M, { __call = M.new })
function M:copy()
local o = M:new()
o._H0 = self._H0:copy()
o._H1 = self._H1:copy()
o._H2 = self._H2:copy()
o._H3 = self._H3:copy()
o._H4 = self._H4:copy()
o._data = self._data
o._len = self._len
return o
end
function M:update(data)
local K0 = u32(0x5A827999)
local K1 = u32(0x6ED9EBA1)
local K2 = u32(0x8F1BBCDC)
local K3 = u32(0xCA62C1D6)
local W
local temp
local A
local B
local C
local D
local E
if data == nil then
data = ""
end
data = tostring(data)
self._len = self._len + #data
self._data = self._data .. data
while #self._data >= 64 do
W = {}
for i=1,64,4 do
local j = #W+1
W[j] = bit.lshift(u32(string.byte(self._data, i)), 24)
W[j] = bit.bor(W[j], bit.lshift(u32(string.byte(self._data, i+1)), 16))
W[j] = bit.bor(W[j], bit.lshift(u32(string.byte(self._data, i+2)), 8))
W[j] = bit.bor(W[j], u32(string.byte(self._data, i+3)))
end
for i=17,80 do
-- W[i] = rotate_left(W[i-3] ~ W[i-8] ~ W[i-14] ~ W[i-16], 1) -------------------------------------------------------
W[i] = rotate_left(bit.bxor(W[i-3], W[i-8], W[i-14], W[i-16]), 1)
end
A = self._H0
B = self._H1
C = self._H2
D = self._H3
E = self._H4
for i=1,20 do
temp = rotate_left(A, 5) + bit.bor(bit.band(B,C), bit.band(bit.bnot(B), D)) + E + W[i] + K0
E = D
D = C
C = rotate_left(B, 30)
B = A
A = temp
end
for i=21,40 do
temp = rotate_left(A, 5) + bit.bxor(B, C, D) + E + W[i] + K1
E = D
D = C
C = rotate_left(B, 30)
B = A
A = temp
end
for i=41,60 do
-- temp = rotate_left(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + K2
temp = rotate_left(A, 5) + bit.bor(bit.band(B,C), bit.band(B,D), bit.band(C,D)) + E + W[i] + K2
E = D
D = C
C = rotate_left(B, 30)
B = A
A = temp
end
for i=61,80 do
-- temp = rotate_left(A, 5) + (B ~ C ~ D) + E + W[i] + K3
temp = rotate_left(A, 5) + bit.bxor(B, C, D) + E + W[i] + K3
E = D
D = C
C = rotate_left(B, 30)
B = A
A = temp
end
self._H0 = self._H0 + A
self._H1 = self._H1 + B
self._H2 = self._H2 + C
self._H3 = self._H3 + D
self._H4 = self._H4 + E
self._data = self._data:sub(65, #self._data)
end
end
function M:digest()
local final
local data
local len = 0
local padlen = 0
final = self:copy()
padlen = final._len % 64
if padlen < 56 then
padlen = 56 - padlen
else
padlen = 120 - padlen
end
len = final._len * 8
data = string.char(bit.lshift(1,7)) ..
string.rep(string.char(0), padlen-1) ..
string.char(bit.band(bit.rshift(len,56), 0xFF)) ..
string.char(bit.band(bit.rshift(len,48), 0xFF)) ..
string.char(bit.band(bit.rshift(len,40), 0xFF)) ..
string.char(bit.band(bit.rshift(len,32), 0xFF)) ..
string.char(bit.band(bit.rshift(len,24), 0xFF)) ..
string.char(bit.band(bit.rshift(len,16), 0xFF)) ..
string.char(bit.band(bit.rshift(len,8) , 0xFF)) ..
string.char(bit.band(len,0xFF))
final:update(data)
return final._H0:asbytestring() ..
final._H1:asbytestring() ..
final._H2:asbytestring() ..
final._H3:asbytestring() ..
final._H4:asbytestring()
end
function M:hexdigest()
local h
local out = {}
h = self:digest()
for i=1,#h do
out[i] = string.format("%02X", string.byte(h, i))
end
return table.concat(out)
end
sha1 = M
-- Copyright (c) 2016 John Schember <john@nachtimwald.com>
--
-- Permission is hereby granted, free of charge, to any person obtaining
-- a copy of this software and associated documentation files (the "Software"),
-- to deal in the Software without restriction, including without limitation
-- the rights to use, copy, modify, merge, publish, distribute, sublicense,
-- and/or sell copies of the Software, and to permit persons to whom the
-- Software is furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-- DEALINGS IN THE SOFTWARE.
--- Fixed width unsigned integers backed by Lua's number type.
--
-- Maximum size is limited by the underlying number type size.
-- The detault size Lua uses is a 64 bit signed integer. Due to
-- overflow being used to handle wrapping nothing bigger than a
-- 32 bit unsigned integer can be supported/represented with this
-- backing type. In order to use larger than 32 bit unsigned integers
-- the BigNum backed uintb type needs to be used.
--
-- The size limitations Lua's number type imposes is why there is not
-- a public new function and instead a uintn must be created using
-- one of the fixed size functions, u32, u16, and u8.
--
-- Also, while Lua's number type is a 64 bit signed type it is possible
-- to compile Lua with a smaller number size. If a smaller size is used
-- this could make u32 and friends stop functioning properly. However,
-- changing the number size is a conscious choice made at compile time.
-- As such, it is known to the programmer limitations that changing
-- the number size imposes.
local M = {}
local M_mt = {}
-- Private
--- Get the input in a workable form.
--
-- The order of input will not necessarily reflect the output. A swapped flag
-- will be returned to indicate that a, b are being returned b, a. The input
-- input is normalized into uint, number as the return values.
--
-- The unit returned is a new object and intended to be returned by the caller.
--
-- @param a Input.
-- @param b Input.
--
-- @return unit, number, swapped.
local function get_inputs(a, b)
local swapped = false
if not M.isuint(a) then
a, b = b, a
swapped = true
end
if M.isuint(b) then
b = b._val
else
b = tonumber(b)
end
return a:copy(), b, swapped
end
local function reduce_range(o)
if o._val == o._max then
o._val = 0
elseif o._val < 0 or o._val > o._max then
o._val = o._val % o._max
end
end
-- M_mt
M_mt.__index = M
M_mt.__add =
function(a, b)
local s
a, b, s = get_inputs(a, b)
if s then
a._val = b + a._val
else
a._val = a._val + b
end
reduce_range(a)
return a
end
M_mt.__sub =
function(a, b)
local s
a, b, s = get_inputs(a, b)
if s then
a._val = b - a._val
else
a._val = a._val - b
end
reduce_range(a)
return a
end
M_mt.__mul =
function(a, b)
a, b = get_inputs(a, b)
a._val = a._val * b
reduce_range(a)
return a
end
M_mt.__div =
function(a, b)
return math.floor(a / b)
end
M_mt.__mod =
function(a, b)
local s
a, b, s = get_inputs(a, b)
if s then
a._val = b % a._val
else
a._val = a._val % b
end
reduce_range(a)
return a
end
M_mt.__pow =
function(a, b)
local s
a, b, s = get_inputs(a, b)
if s then
a._val = b ^ a._val
else
a._val = a._val ^ b
end
reduce_range(a)
return a
end
M_mt.__unm =
function(a)
a = a:copy()
a._val = -a._val
reduce_range(a)
return a
end
M_mt.__idiv =
function(a, b)
local s
a, b, s = get_inputs(a, b)
if s and b == 0 then
a._val = 0
return a
end
-- if b == 0 then divide by 0 exception, let it happen.
if s then
a._val = math.floor(b / a._val)
else
a._val = math.floor(a._val / b)
end
reduce_range(a)
return a
end
M_mt.__band =
function(a, b)
a, b = get_inputs(a, b)
a._val = bit.band(a._val,b)
reduce_range(a)
return a
end
M_mt.__bor =
function(a, b)
a, b = get_inputs(a, b)
a._val = bit.bor(a._val,b)
reduce_range(a)
return a
end
M_mt.__bxor =
function(a, b)
a, b = get_inputs(a, b)
a._val = bit.bxor(a._val,b)
reduce_range(a)
return a
end
M_mt.__bnot =
function(a)
a = a:copy()
a._val = bit.bnot(a._val)
reduce_range(a)
return a
end
M_mt.__shl =
function(a, b)
local s
a, b, s = get_inputs(a, b)
if s then
a._val = bit.lshift(b, a._val)
else
a._val = bit.lshift(a._val, b)
end
reduce_range(a)
return a
end
M_mt.__shr =
function(a, b)
local s
a, b, s = get_inputs(a, b)
if s then
a._val = bit.rshift(b, a._val)
else
a._val = bit.rshift(a._val, b)
end
reduce_range(a)
return a
end
M_mt.__concat =
function(a, b)
if M.isuint(a) and M.isuint(b) then
return a._val..b._val
elseif M.isuint(a) and not M.isuint(b) then
return a._val..b
end
return a..b._val
end
M_mt.__len =
function(a)
return a._bits
end
M_mt.__eq =
function(a, b)
a, b = get_inputs(a, b)
return a._val == b
end
M_mt.__lt =
function(a, b)
local s
a, b, s = get_inputs(a, b)
if s then
return a._val > b
end
return a._val < b
end
M_mt.__le =
function(a, b)
if a < b or a == b then
return true
end
return false
end
M_mt.__tostring =
function(a)
return tostring(a._val)
end
-- Private
local function new(bits, n)
local o = setmetatable({}, M_mt)
o._bits = bits
o._max = bit.lshift(1,o._bits)
if n == nil then
n = 0
end
if M.isuint(n) then
o._val = n._val
else
o._val = tonumber(n)
end
PRINT(o)
reduce_range(o)
PRINT(o)
return o
end
-- Static
function M.isuint(t)
if type(t) == "table" and getmetatable(t) == M_mt then
return true
end
return false
end
function M.u8(v)
return new(8, v)
end
function M.u16(v)
return new(16, v)
end
function M.u32(v)
return new(32, v)
end
-- M
function M:copy()
return new(self._bits, self._val)
end
function M:set(n)
if M.isuint(n) then
self._val = n._val
else
self._val = tonumber(n)
end
reduce_range(self)
end
function M:swape()
local v
local n = 0
local t
v = self:asbytearray()
for i=1, math.floor(#v / 2) do
t = v[i]
v[i] = v[#v-i+1]
v[#v-i+1] = t
end
t = {}
for i=#v,1,-1 do
t[#t+1] = v[i]
end
for i=1,#t do
n = bit.bor(n, bit.lshift(t[i], i*8-8))
end
return new(self._bits, n)
end
function M:asnumber()
return self._val
end
function M:ashex(width)
local f = "%"
if width ~= nil then
f = f .. "0" .. tostring(width)
end
f = f .. "X"
return f:format(self._val)
end
function M:asbytearray()
local t = {}
for i=self._bits-8,0,-8 do
t[#t+1] = bit.band(bit.rshift(self._val, i),0xFF)
end
return t
end
function M:asbytestring()
local b
b = self:asbytearray()
for i=1,#b do
b[i] = string.char(b[i])
end
return table.concat(b)
end
uintn = M
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment