mirror of
https://git.phreedom.club/localhost_frssoft/fediauth.git
synced 2024-11-26 01:41:32 +00:00
working otp code generation
This commit is contained in:
parent
64eb6077b3
commit
831ba7772e
20
.github/workflows/test.yml
vendored
Normal file
20
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
name: test
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
ENGINE_VERSION: [5.3.0, 5.4.0, 5.5.0, 5.6.1, latest]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
submodules: recursive
|
||||||
|
- name: test
|
||||||
|
run: docker-compose up --exit-code-from test
|
15
docker-compose.yml
Normal file
15
docker-compose.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
version: "3.6"
|
||||||
|
|
||||||
|
services:
|
||||||
|
test:
|
||||||
|
build: ./test
|
||||||
|
user: root
|
||||||
|
volumes:
|
||||||
|
- "./:/root/.minetest/worlds/world/worldmods/otp/"
|
||||||
|
- "./test/minetest.conf:/minetest.conf"
|
||||||
|
- "world:/root/.minetest/worlds/world"
|
||||||
|
ports:
|
||||||
|
- "30000:30000/udp"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
world: {}
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
-- https://stackoverflow.com/a/25594410
|
-- https://stackoverflow.com/a/25594410
|
||||||
function otp.bitXOR(a,b)--Bitwise xor
|
local function bitxor(a,b)
|
||||||
local p,c=1,0
|
local p,c=1,0
|
||||||
while a>0 and b>0 do
|
while a>0 and b>0 do
|
||||||
local ra,rb=a%2,b%2
|
local ra,rb=a%2,b%2
|
||||||
|
@ -16,6 +16,16 @@ function otp.bitXOR(a,b)--Bitwise xor
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function bitor(a,b)
|
||||||
|
local p,c=1,0
|
||||||
|
while a+b>0 do
|
||||||
|
local ra,rb=a%2,b%2
|
||||||
|
if ra+rb>0 then c=c+p end
|
||||||
|
a,b,p=(a-ra)/2,(b-rb)/2,p*2
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
-- https://stackoverflow.com/a/32387452
|
-- https://stackoverflow.com/a/32387452
|
||||||
local function bitand(a, b)
|
local function bitand(a, b)
|
||||||
local result = 0
|
local result = 0
|
||||||
|
@ -36,15 +46,20 @@ local function rshift(x, by)
|
||||||
return math.floor(x / 2 ^ by)
|
return math.floor(x / 2 ^ by)
|
||||||
end
|
end
|
||||||
|
|
||||||
function otp.write_uint64(v)
|
local function lshift(x, by)
|
||||||
local b1 = bitand(v, 0xFF)
|
return x * 2 ^ by
|
||||||
local b2 = bitand( rshift(v, 8), 0xFF )
|
end
|
||||||
local b3 = bitand( rshift(v, 16), 0xFF )
|
|
||||||
local b4 = bitand( rshift(v, 24), 0xFF )
|
-- big-endian uint64 of a number
|
||||||
local b5 = bitand( rshift(v, 32), 0xFF )
|
function otp.write_uint64_be(v)
|
||||||
local b6 = bitand( rshift(v, 40), 0xFF )
|
local b1 = bitand( rshift(v, 56), 0xFF )
|
||||||
local b7 = bitand( rshift(v, 48), 0xFF )
|
local b2 = bitand( rshift(v, 48), 0xFF )
|
||||||
local b8 = bitand( rshift(v, 56), 0xFF )
|
local b3 = bitand( rshift(v, 40), 0xFF )
|
||||||
|
local b4 = bitand( rshift(v, 32), 0xFF )
|
||||||
|
local b5 = bitand( rshift(v, 24), 0xFF )
|
||||||
|
local b6 = bitand( rshift(v, 16), 0xFF )
|
||||||
|
local b7 = bitand( rshift(v, 8), 0xFF )
|
||||||
|
local b8 = bitand( rshift(v, 0), 0xFF )
|
||||||
return string.char(b1, b2, b3, b4, b5, b6, b7, b8)
|
return string.char(b1, b2, b3, b4, b5, b6, b7, b8)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -61,29 +76,49 @@ end
|
||||||
function otp.hmac(key, message)
|
function otp.hmac(key, message)
|
||||||
local i_key_pad = ""
|
local i_key_pad = ""
|
||||||
for i=1,64 do
|
for i=1,64 do
|
||||||
i_key_pad = i_key_pad .. string.char(otp.bitXOR(string.byte(key, i) or 0x00, string.byte(i_pad, i)))
|
i_key_pad = i_key_pad .. string.char(bitxor(string.byte(key, i) or 0x00, string.byte(i_pad, i)))
|
||||||
end
|
end
|
||||||
|
assert(#i_key_pad == 64)
|
||||||
|
|
||||||
local o_key_pad = ""
|
local o_key_pad = ""
|
||||||
for i=1,64 do
|
for i=1,64 do
|
||||||
o_key_pad = o_key_pad .. string.char(otp.bitXOR(string.byte(key, i) or 0x00, string.byte(o_pad, i)))
|
o_key_pad = o_key_pad .. string.char(bitxor(string.byte(key, i) or 0x00, string.byte(o_pad, i)))
|
||||||
end
|
end
|
||||||
|
assert(#o_key_pad == 64)
|
||||||
|
|
||||||
-- concat message
|
-- concat message
|
||||||
local first_msg = i_key_pad
|
local first_msg = i_key_pad
|
||||||
for i=1,#message do
|
for i=1,#message do
|
||||||
first_msg = first_msg .. string.byte(message, i)
|
first_msg = first_msg .. string.char(string.byte(message, i))
|
||||||
end
|
end
|
||||||
|
assert(#first_msg == 64+8)
|
||||||
|
|
||||||
-- hash first message
|
-- hash first message
|
||||||
local hash_sum_1 = minetest.sha1(first_msg, true)
|
local hash_sum_1 = minetest.sha1(first_msg, true)
|
||||||
|
assert(#hash_sum_1 == 20)
|
||||||
|
|
||||||
-- concat first message to secons
|
-- concat first message to secons
|
||||||
local second_msg = o_key_pad
|
local second_msg = o_key_pad
|
||||||
for i=1,#hash_sum_1 do
|
for i=1,#hash_sum_1 do
|
||||||
second_msg = second_msg .. string.byte(hash_sum_1, i)
|
second_msg = second_msg .. string.char(string.byte(hash_sum_1, i))
|
||||||
|
end
|
||||||
|
assert(#second_msg == 64+20)
|
||||||
|
|
||||||
|
local hmac = minetest.sha1(second_msg, true)
|
||||||
|
assert(#hmac == 20)
|
||||||
|
|
||||||
|
return hmac
|
||||||
end
|
end
|
||||||
|
|
||||||
-- hash final message
|
function otp.generate_code(key, message)
|
||||||
return minetest.sha1(second_msg, true)
|
local hmac = otp.hmac(key, message)
|
||||||
|
|
||||||
|
-- https://www.rfc-editor.org/rfc/rfc4226#section-5.4
|
||||||
|
local offset = bitand(string.byte(hmac, #hmac), 0xF)
|
||||||
|
local value = 0
|
||||||
|
value = bitor(value, string.byte(hmac, offset+4))
|
||||||
|
value = bitor(value, lshift(string.byte(hmac, offset+3), 8))
|
||||||
|
value = bitor(value, lshift(string.byte(hmac, offset+2), 16))
|
||||||
|
value = bitor(value, lshift(bitand(string.byte(hmac, offset+1), 0x7F), 24))
|
||||||
|
return value % 10^6
|
||||||
end
|
end
|
43
functions.spec.lua
Normal file
43
functions.spec.lua
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
|
||||||
|
mtt.register("otp.hmac", function(callback)
|
||||||
|
local secret_b32 = "N6JGKMEKU2E6HQMLLNMJKBRRGVQ2ZKV7"
|
||||||
|
local secret = otp.basexx.from_base32(secret_b32)
|
||||||
|
local unix_time = 1640995200
|
||||||
|
|
||||||
|
local expected_hmac = otp.basexx.from_base64("m04YheEb7i+ThPMUJEfVXVybZFo=")
|
||||||
|
assert(#expected_hmac == 20)
|
||||||
|
|
||||||
|
local tx = 30
|
||||||
|
local ct = math.floor(unix_time / tx)
|
||||||
|
local counter = otp.write_uint64_be(ct)
|
||||||
|
|
||||||
|
assert( #secret == 20 )
|
||||||
|
assert( otp.basexx.to_base64(secret) == "b5JlMIqmiePBi1tYlQYxNWGsqr8=" )
|
||||||
|
assert( #counter == 8 )
|
||||||
|
assert( otp.basexx.to_base64(counter) == "AAAAAANCp0A=" )
|
||||||
|
|
||||||
|
local hmac = otp.hmac(secret, counter)
|
||||||
|
assert(#hmac == 20)
|
||||||
|
|
||||||
|
for i=1,20 do
|
||||||
|
assert( string.byte(expected_hmac,i) == string.byte(hmac, i) )
|
||||||
|
end
|
||||||
|
|
||||||
|
callback()
|
||||||
|
end)
|
||||||
|
|
||||||
|
mtt.register("otp.generate_code", function(callback)
|
||||||
|
local expected_code = 699847
|
||||||
|
local secret_b32 = "N6JGKMEKU2E6HQMLLNMJKBRRGVQ2ZKV7"
|
||||||
|
local secret = otp.basexx.from_base32(secret_b32)
|
||||||
|
local unix_time = 1640995200
|
||||||
|
|
||||||
|
local tx = 30
|
||||||
|
local ct = math.floor(unix_time / tx)
|
||||||
|
local counter = otp.write_uint64_be(ct)
|
||||||
|
|
||||||
|
local code = otp.generate_code(secret, counter)
|
||||||
|
assert(code == expected_code)
|
||||||
|
callback()
|
||||||
|
end)
|
5
init.lua
5
init.lua
|
@ -9,4 +9,7 @@ otp = {
|
||||||
}
|
}
|
||||||
|
|
||||||
dofile(MP.."/functions.lua")
|
dofile(MP.."/functions.lua")
|
||||||
dofile(MP.."/test.lua")
|
|
||||||
|
if minetest.get_modpath("mtt") and mtt.enabled then
|
||||||
|
dofile(MP.."/functions.spec.lua")
|
||||||
|
end
|
24
test.lua
24
test.lua
|
@ -1,24 +0,0 @@
|
||||||
local secret_b32 = "N6JGKMEKU2E6HQMLLNMJKBRRGVQ2ZKV7"
|
|
||||||
local expected_code = 699847
|
|
||||||
|
|
||||||
minetest.register_chatcommand("otp_test", {
|
|
||||||
description = "",
|
|
||||||
params = "[]",
|
|
||||||
func = function(name, param)
|
|
||||||
local secret = otp.basexx.from_base32(secret_b32)
|
|
||||||
local unix_time = 1640995200
|
|
||||||
local tx = 30
|
|
||||||
local ct = math.floor(unix_time / tx)
|
|
||||||
|
|
||||||
local hmac = otp.hmac(secret, otp.write_uint64(ct))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print(dump({
|
|
||||||
expected_code = expected_code,
|
|
||||||
unix_time = unix_time,
|
|
||||||
ct = ct,
|
|
||||||
hmac = otp.basexx.to_base64(hmac)
|
|
||||||
}))
|
|
||||||
end
|
|
||||||
})
|
|
11
test/Dockerfile
Normal file
11
test/Dockerfile
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
ARG ENGINE_VERSION=5.6.1
|
||||||
|
FROM registry.gitlab.com/minetest/minetest/server:${ENGINE_VERSION}
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
RUN apk add git &&\
|
||||||
|
mkdir -p /root/.minetest/worlds/world/worldmods/ &&\
|
||||||
|
cd /root/.minetest/worlds/world/worldmods/ &&\
|
||||||
|
git clone https://github.com/BuckarooBanzay/mtt
|
||||||
|
|
||||||
|
ENTRYPOINT minetestserver --config /minetest.conf
|
3
test/minetest.conf
Normal file
3
test/minetest.conf
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
default_game = minetest_game
|
||||||
|
mg_name = v7
|
||||||
|
mtt_enable = true
|
Loading…
Reference in a new issue