mirror of
https://github.com/kepler155c/opus
synced 2025-01-26 23:24:45 +00:00
security updates
This commit is contained in:
parent
69522e61d4
commit
e75a357209
@ -137,13 +137,17 @@ end
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
function page.ports.grid:update()
|
function page.ports.grid:update()
|
||||||
|
local transport = network:getTransport()
|
||||||
|
|
||||||
local function findConnection(port)
|
local function findConnection(port)
|
||||||
for _,socket in pairs(_G.transport.sockets) do
|
if transport then
|
||||||
|
for _,socket in pairs(transport.sockets) do
|
||||||
if socket.sport == port then
|
if socket.sport == port then
|
||||||
return socket
|
return socket
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local connections = { }
|
local connections = { }
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ if not device.wireless_modem then
|
|||||||
end
|
end
|
||||||
|
|
||||||
print('Net daemon starting')
|
print('Net daemon starting')
|
||||||
|
device.wireless_modem.closeAll()
|
||||||
|
|
||||||
for _,file in pairs(fs.list('sys/apps/network')) do
|
for _,file in pairs(fs.list('sys/apps/network')) do
|
||||||
local fn, msg = Util.run(_ENV, 'sys/apps/network/' .. file)
|
local fn, msg = Util.run(_ENV, 'sys/apps/network/' .. file)
|
||||||
|
39
sys/apps/network/keygen.lua
Normal file
39
sys/apps/network/keygen.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
local ECC = require('opus.crypto.ecc')
|
||||||
|
local Event = require('opus.event')
|
||||||
|
local Util = require('opus.util')
|
||||||
|
|
||||||
|
local network = _G.network
|
||||||
|
local os = _G.os
|
||||||
|
|
||||||
|
local keyPairs = { }
|
||||||
|
|
||||||
|
local function generateKeyPair()
|
||||||
|
local key = { }
|
||||||
|
for _ = 1, 32 do
|
||||||
|
table.insert(key, ("%02x"):format(math.random(0, 0xFF)))
|
||||||
|
end
|
||||||
|
local privateKey = Util.hexToByteArray(table.concat(key))
|
||||||
|
return privateKey, ECC.publicKey(privateKey)
|
||||||
|
end
|
||||||
|
|
||||||
|
getmetatable(network).__index.getKeyPair = function()
|
||||||
|
local keys = table.remove(keyPairs)
|
||||||
|
os.queueEvent('generate_keypair')
|
||||||
|
if not keys then
|
||||||
|
return generateKeyPair()
|
||||||
|
end
|
||||||
|
return table.unpack(keys)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Generate key pairs in the background as this is a time-consuming process
|
||||||
|
Event.on('generate_keypair', function()
|
||||||
|
while true do
|
||||||
|
os.sleep(5)
|
||||||
|
local timer = Util.timer()
|
||||||
|
table.insert(keyPairs, { generateKeyPair() })
|
||||||
|
_G._syslog('Generated keypair in ' .. timer())
|
||||||
|
if #keyPairs >= 3 then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
@ -6,7 +6,9 @@
|
|||||||
]]--
|
]]--
|
||||||
|
|
||||||
local Event = require('opus.event')
|
local Event = require('opus.event')
|
||||||
|
local SHA = require('opus.crypto.sha2')
|
||||||
|
|
||||||
|
local network = _G.network
|
||||||
local os = _G.os
|
local os = _G.os
|
||||||
|
|
||||||
local computerId = os.getComputerID()
|
local computerId = os.getComputerID()
|
||||||
@ -15,7 +17,10 @@ local transport = {
|
|||||||
sockets = { },
|
sockets = { },
|
||||||
UID = 0,
|
UID = 0,
|
||||||
}
|
}
|
||||||
_G.transport = transport
|
|
||||||
|
getmetatable(network).__index.getTransport = function()
|
||||||
|
return transport
|
||||||
|
end
|
||||||
|
|
||||||
function transport.open(socket)
|
function transport.open(socket)
|
||||||
transport.UID = transport.UID + 1
|
transport.UID = transport.UID + 1
|
||||||
@ -33,19 +38,11 @@ function transport.read(socket)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function transport.write(socket, data)
|
function transport.write(socket, data)
|
||||||
--_syslog('>> ' .. Util.tostring({ type = 'DATA', seq = socket.wseq }))
|
|
||||||
socket.transmit(socket.dport, socket.dhost, data)
|
socket.transmit(socket.dport, socket.dhost, data)
|
||||||
|
socket.wseq = SHA.digest(socket.wseq):toHex()
|
||||||
--local timerId = os.startTimer(3)
|
|
||||||
|
|
||||||
--transport.timers[timerId] = socket
|
|
||||||
--socket.timers[socket.wseq] = timerId
|
|
||||||
|
|
||||||
socket.wseq = socket.wseq + 1
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function transport.ping(socket)
|
function transport.ping(socket)
|
||||||
--_syslog('>> ' .. Util.tostring({ type = 'DATA', seq = socket.wseq }))
|
|
||||||
if os.clock() - socket.activityTimer > 10 then
|
if os.clock() - socket.activityTimer > 10 then
|
||||||
socket.activityTimer = os.clock()
|
socket.activityTimer = os.clock()
|
||||||
socket.transmit(socket.dport, socket.dhost, {
|
socket.transmit(socket.dport, socket.dhost, {
|
||||||
@ -53,7 +50,7 @@ function transport.ping(socket)
|
|||||||
seq = -1,
|
seq = -1,
|
||||||
})
|
})
|
||||||
|
|
||||||
local timerId = os.startTimer(5)
|
local timerId = os.startTimer(3)
|
||||||
transport.timers[timerId] = socket
|
transport.timers[timerId] = socket
|
||||||
socket.timers[-1] = timerId
|
socket.timers[-1] = timerId
|
||||||
end
|
end
|
||||||
@ -78,18 +75,19 @@ Event.on('modem_message', function(_, _, dport, dhost, msg, distance)
|
|||||||
local socket = transport.sockets[dport]
|
local socket = transport.sockets[dport]
|
||||||
if socket and socket.connected then
|
if socket and socket.connected then
|
||||||
|
|
||||||
--if msg.type then _syslog('<< ' .. Util.tostring(msg)) end
|
|
||||||
if socket.co and coroutine.status(socket.co) == 'dead' then
|
if socket.co and coroutine.status(socket.co) == 'dead' then
|
||||||
_G._syslog('socket coroutine dead')
|
_G._syslog('socket coroutine dead')
|
||||||
socket:close()
|
socket:close()
|
||||||
|
|
||||||
elseif msg.type == 'DISC' then
|
elseif msg.type == 'DISC' then
|
||||||
-- received disconnect from other end
|
-- received disconnect from other end
|
||||||
|
if msg.seq == socket.rseq then
|
||||||
if socket.connected then
|
if socket.connected then
|
||||||
os.queueEvent('transport_' .. socket.uid)
|
os.queueEvent('transport_' .. socket.uid)
|
||||||
end
|
end
|
||||||
socket.connected = false
|
socket.connected = false
|
||||||
socket:close()
|
socket:close()
|
||||||
|
end
|
||||||
|
|
||||||
elseif msg.type == 'ACK' then
|
elseif msg.type == 'ACK' then
|
||||||
local ackTimerId = socket.timers[msg.seq]
|
local ackTimerId = socket.timers[msg.seq]
|
||||||
@ -108,28 +106,19 @@ Event.on('modem_message', function(_, _, dport, dhost, msg, distance)
|
|||||||
})
|
})
|
||||||
|
|
||||||
elseif msg.type == 'DATA' and msg.data then
|
elseif msg.type == 'DATA' and msg.data then
|
||||||
socket.activityTimer = os.clock()
|
|
||||||
if msg.seq ~= socket.rseq then
|
if msg.seq ~= socket.rseq then
|
||||||
print('transport seq error - closing socket ' .. socket.sport)
|
print('transport seq error - closing socket ' .. socket.sport)
|
||||||
_syslog(msg.data)
|
_syslog(msg.data)
|
||||||
_syslog('current ' .. socket.rseq)
|
_syslog('expected ' .. socket.rseq)
|
||||||
_syslog('expected ' .. msg.seq)
|
_syslog('got ' .. msg.seq)
|
||||||
-- socket:close()
|
|
||||||
-- os.queueEvent('transport_' .. socket.uid)
|
|
||||||
else
|
else
|
||||||
socket.rseq = socket.rseq + 1
|
socket.activityTimer = os.clock()
|
||||||
|
socket.rseq = SHA.digest(socket.rseq):toHex()
|
||||||
table.insert(socket.messages, { msg.data, distance })
|
table.insert(socket.messages, { msg.data, distance })
|
||||||
|
|
||||||
-- use resume instead ??
|
|
||||||
if not socket.messages[2] then -- table size is 1
|
if not socket.messages[2] then -- table size is 1
|
||||||
os.queueEvent('transport_' .. socket.uid)
|
os.queueEvent('transport_' .. socket.uid)
|
||||||
end
|
end
|
||||||
|
|
||||||
--_syslog('>> ' .. Util.tostring({ type = 'ACK', seq = msg.seq }))
|
|
||||||
--socket.transmit(socket.dport, socket.dhost, {
|
|
||||||
-- type = 'ACK',
|
|
||||||
-- seq = msg.seq,
|
|
||||||
--})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -4,6 +4,8 @@ local Security = require('opus.security')
|
|||||||
local Socket = require('opus.socket')
|
local Socket = require('opus.socket')
|
||||||
local Util = require('opus.util')
|
local Util = require('opus.util')
|
||||||
|
|
||||||
|
local trustId = '01c3ba27fe01383a03a1785276d99df27c3edcef68fbf231ca'
|
||||||
|
|
||||||
local function trustConnection(socket)
|
local function trustConnection(socket)
|
||||||
local data = socket:read(2)
|
local data = socket:read(2)
|
||||||
if data then
|
if data then
|
||||||
@ -14,7 +16,7 @@ local function trustConnection(socket)
|
|||||||
data = Crypto.decrypt(data, password)
|
data = Crypto.decrypt(data, password)
|
||||||
if data and data.pk and data.dh == socket.dhost then
|
if data and data.pk and data.dh == socket.dhost then
|
||||||
local trustList = Util.readTable('usr/.known_hosts') or { }
|
local trustList = Util.readTable('usr/.known_hosts') or { }
|
||||||
trustList[data.dh] = Util.byteArrayToHex(data.pk)
|
trustList[data.dh] = data.pk
|
||||||
Util.writeTable('usr/.known_hosts', trustList)
|
Util.writeTable('usr/.known_hosts', trustList)
|
||||||
|
|
||||||
socket:write({ success = true, msg = 'Trust accepted' })
|
socket:write({ success = true, msg = 'Trust accepted' })
|
||||||
@ -29,7 +31,7 @@ Event.addRoutine(function()
|
|||||||
print('trust: listening on port 19')
|
print('trust: listening on port 19')
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local socket = Socket.server(19)
|
local socket = Socket.server(19, { identifier = trustId })
|
||||||
|
|
||||||
print('trust: connection from ' .. socket.dhost)
|
print('trust: connection from ' .. socket.dhost)
|
||||||
|
|
||||||
|
@ -27,15 +27,16 @@ if not password then
|
|||||||
end
|
end
|
||||||
|
|
||||||
print('connecting...')
|
print('connecting...')
|
||||||
local socket, msg = Socket.connect(remoteId, 19)
|
local trustId = '01c3ba27fe01383a03a1785276d99df27c3edcef68fbf231ca'
|
||||||
|
local socket, msg = Socket.connect(remoteId, 19, { identifier = trustId })
|
||||||
|
|
||||||
if not socket then
|
if not socket then
|
||||||
error(msg)
|
error(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
local publicKey = Security.getPublicKey()
|
local identifier = Security.getIdentifier()
|
||||||
|
|
||||||
socket:write(Crypto.encrypt({ pk = publicKey, dh = os.getComputerID() }, SHA.compute(password)))
|
socket:write(Crypto.encrypt({ pk = identifier, dh = os.getComputerID() }, SHA.compute(password)))
|
||||||
|
|
||||||
local data = socket:read(2)
|
local data = socket:read(2)
|
||||||
socket:close()
|
socket:close()
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
-- By Anavrins
|
-- By Anavrins
|
||||||
|
|
||||||
local sha2 = require('opus.crypto.sha2')
|
local sha2 = require('opus.crypto.sha2')
|
||||||
local util = require('opus.util')
|
local Util = require('opus.util')
|
||||||
|
|
||||||
local ROUNDS = 20 -- Adjust this for speed tradeoff
|
local ROUNDS = 20 -- Adjust this for speed tradeoff
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ local function crypt(data, key, nonce, cntr, round)
|
|||||||
cntr = tonumber(cntr) or 1
|
cntr = tonumber(cntr) or 1
|
||||||
round = tonumber(round) or 20
|
round = tonumber(round) or 20
|
||||||
|
|
||||||
local throttle = util.throttle()
|
local throttle = Util.throttle()
|
||||||
local out = {}
|
local out = {}
|
||||||
local state = initState(key, nonce, cntr)
|
local state = initState(key, nonce, cntr)
|
||||||
local blockAmt = math.floor(#data/64)
|
local blockAmt = math.floor(#data/64)
|
||||||
@ -157,8 +157,8 @@ local function encrypt(data, key)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function decrypt(data, key)
|
local function decrypt(data, key)
|
||||||
local nonce = util.hexToByteArray(data[1])
|
local nonce = Util.hexToByteArray(data[1])
|
||||||
data = util.hexToByteArray(data[2])
|
data = Util.hexToByteArray(data[2])
|
||||||
key = sha2.digest(key)
|
key = sha2.digest(key)
|
||||||
local ptx = crypt(data, key, nonce, 1, ROUNDS)
|
local ptx = crypt(data, key, nonce, 1, ROUNDS)
|
||||||
return textutils.unserialise(tostring(ptx))
|
return textutils.unserialise(tostring(ptx))
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
-- Indistinguishability? No: The curve does not support indistinguishability maps.
|
-- Indistinguishability? No: The curve does not support indistinguishability maps.
|
||||||
|
|
||||||
local fp = require('opus.crypto.ecc.fp')
|
local fp = require('opus.crypto.ecc.fp')
|
||||||
|
local Util = require('opus.util')
|
||||||
|
|
||||||
local eq = fp.eq
|
local eq = fp.eq
|
||||||
local mul = fp.mul
|
local mul = fp.mul
|
||||||
local sqr = fp.sqr
|
local sqr = fp.sqr
|
||||||
@ -31,6 +33,7 @@ local shr = fp.shr
|
|||||||
local mont = fp.mont
|
local mont = fp.mont
|
||||||
local invMont = fp.invMont
|
local invMont = fp.invMont
|
||||||
local sub192 = fp.sub192
|
local sub192 = fp.sub192
|
||||||
|
local unpack = table.unpack
|
||||||
|
|
||||||
local bits = 192
|
local bits = 192
|
||||||
local pMinusTwoBinary = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
local pMinusTwoBinary = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||||
@ -203,20 +206,23 @@ local function scalarMul(s, P1)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local Q = {{unpack(ZERO)}, {unpack(ONE)}, {unpack(ONE)}}
|
local Q = {{unpack(ZERO)}, {unpack(ONE)}, {unpack(ONE)}}
|
||||||
for i = #naf, 1, -1 do
|
for i = #naf, 1, -1 do -- can this loop be optimized ?
|
||||||
|
local n = naf[i]
|
||||||
Q = pointDouble(Q)
|
Q = pointDouble(Q)
|
||||||
if naf[i] > 0 then
|
if n > 0 then
|
||||||
Q = pointAdd(Q, PTable[naf[i]])
|
Q = pointAdd(Q, PTable[n])
|
||||||
elseif naf[i] < 0 then
|
elseif n < 0 then
|
||||||
Q = pointSub(Q, PTable[-naf[i]])
|
Q = pointSub(Q, PTable[-n])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return Q
|
return Q
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local throttle = Util.throttle()
|
||||||
for i = 2, 196 do
|
for i = 2, 196 do
|
||||||
GTable[i] = pointDouble(GTable[i - 1])
|
GTable[i] = pointDouble(GTable[i - 1])
|
||||||
|
throttle()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function scalarMulG(s)
|
local function scalarMulG(s)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
-- Fp Integer Arithmetic
|
-- Fp Integer Arithmetic
|
||||||
|
|
||||||
|
local unpack = table.unpack
|
||||||
|
|
||||||
local n = 0xffff
|
local n = 0xffff
|
||||||
local m = 0x10000
|
local m = 0x10000
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
-- Fq Integer Arithmetic
|
-- Fq Integer Arithmetic
|
||||||
|
|
||||||
|
local unpack = table.unpack
|
||||||
|
|
||||||
local n = 0xffff
|
local n = 0xffff
|
||||||
local m = 0x10000
|
local m = 0x10000
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ local elliptic = require('opus.crypto.ecc.elliptic')
|
|||||||
local sha256 = require('opus.crypto.sha2')
|
local sha256 = require('opus.crypto.sha2')
|
||||||
|
|
||||||
local os = _G.os
|
local os = _G.os
|
||||||
|
local unpack = table.unpack
|
||||||
|
|
||||||
local q = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532}
|
local q = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
-- SHA-256, HMAC and PBKDF2 functions in ComputerCraft
|
-- SHA-256, HMAC and PBKDF2 functions in ComputerCraft
|
||||||
-- By Anavrins
|
-- By Anavrins
|
||||||
|
local Util = require('opus.util')
|
||||||
|
|
||||||
local bit = _G.bit
|
local bit = _G.bit
|
||||||
local os = _G.os
|
|
||||||
local mod32 = 2^32
|
local mod32 = 2^32
|
||||||
local band = bit32 and bit32.band or bit.band
|
local band = bit32 and bit32.band or bit.band
|
||||||
local bnot = bit32 and bit32.bnot or bit.bnot
|
local bnot = bit32 and bit32.bnot or bit.bnot
|
||||||
@ -162,25 +162,13 @@ local function hmac(data, key)
|
|||||||
return digest(padded_key)
|
return digest(padded_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function throttler()
|
|
||||||
local ts = os.clock()
|
|
||||||
local timeout = .095
|
|
||||||
return function()
|
|
||||||
local nts = os.clock()
|
|
||||||
if nts > ts + timeout then
|
|
||||||
os.sleep(0)
|
|
||||||
ts = os.clock()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function pbkdf2(pass, salt, iter, dklen)
|
local function pbkdf2(pass, salt, iter, dklen)
|
||||||
salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)}
|
salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)}
|
||||||
local hashlen = 32
|
local hashlen = 32
|
||||||
dklen = dklen or 32
|
dklen = dklen or 32
|
||||||
local block = 1
|
local block = 1
|
||||||
local out = {}
|
local out = {}
|
||||||
local throttle = throttler()
|
local throttle = Util.throttle()
|
||||||
|
|
||||||
while dklen > 0 do
|
while dklen > 0 do
|
||||||
local ikey = {}
|
local ikey = {}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
local Config = require('opus.config')
|
local Config = require('opus.config')
|
||||||
local Util = require('opus.util')
|
|
||||||
local ECC = require('opus.crypto.ecc')
|
local ECC = require('opus.crypto.ecc')
|
||||||
|
local Util = require('opus.util')
|
||||||
|
|
||||||
local Security = { }
|
local Security = { }
|
||||||
|
|
||||||
@ -21,16 +21,6 @@ local function genKey()
|
|||||||
return table.concat(key)
|
return table.concat(key)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Security.generateKeyPair()
|
|
||||||
local privateKey = Util.hexToByteArray(genKey())
|
|
||||||
return privateKey, ECC.publicKey(privateKey)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Security.getIdentifier()
|
|
||||||
return Security.getPublicKey()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- deprecate - will use getIdentifier
|
|
||||||
function Security.getSecretKey()
|
function Security.getSecretKey()
|
||||||
local config = Config.load('os')
|
local config = Config.load('os')
|
||||||
if not config.secretKey then
|
if not config.secretKey then
|
||||||
@ -40,9 +30,17 @@ function Security.getSecretKey()
|
|||||||
return Util.hexToByteArray(config.secretKey)
|
return Util.hexToByteArray(config.secretKey)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Security.getPublicKey()
|
function Security.getIdentifier()
|
||||||
local secretKey = Security.getSecretKey()
|
local config = Config.load('os')
|
||||||
return ECC.publicKey(secretKey)
|
if config.identifier then
|
||||||
|
return config.identifier
|
||||||
|
end
|
||||||
|
-- preserve the hash the user generated
|
||||||
|
local identifier = ECC.publicKey(Security.getSecretKey())
|
||||||
|
config.identifier = Util.byteArrayToHex(identifier)
|
||||||
|
Config.update('os', config)
|
||||||
|
|
||||||
|
return config.identifier
|
||||||
end
|
end
|
||||||
|
|
||||||
function Security.updatePassword(password)
|
function Security.updatePassword(password)
|
||||||
|
@ -6,11 +6,12 @@ local Util = require('opus.util')
|
|||||||
|
|
||||||
local device = _G.device
|
local device = _G.device
|
||||||
local os = _G.os
|
local os = _G.os
|
||||||
|
local network = _G.network
|
||||||
|
|
||||||
local socketClass = { }
|
local socketClass = { }
|
||||||
|
|
||||||
function socketClass:read(timeout)
|
function socketClass:read(timeout)
|
||||||
local data, distance = _G.transport.read(self)
|
local data, distance = network.getTransport().read(self)
|
||||||
if data then
|
if data then
|
||||||
return data, distance
|
return data, distance
|
||||||
end
|
end
|
||||||
@ -25,7 +26,7 @@ function socketClass:read(timeout)
|
|||||||
local e, id = os.pullEvent()
|
local e, id = os.pullEvent()
|
||||||
|
|
||||||
if e == 'transport_' .. self.uid then
|
if e == 'transport_' .. self.uid then
|
||||||
data, distance = _G.transport.read(self)
|
data, distance = network.getTransport().read(self)
|
||||||
if data then
|
if data then
|
||||||
os.cancelTimer(timerId)
|
os.cancelTimer(timerId)
|
||||||
return data, distance
|
return data, distance
|
||||||
@ -46,7 +47,7 @@ end
|
|||||||
|
|
||||||
function socketClass:write(data)
|
function socketClass:write(data)
|
||||||
if self.connected then
|
if self.connected then
|
||||||
_G.transport.write(self, {
|
network.getTransport().write(self, {
|
||||||
type = 'DATA',
|
type = 'DATA',
|
||||||
seq = self.wseq,
|
seq = self.wseq,
|
||||||
data = data,
|
data = data,
|
||||||
@ -57,30 +58,31 @@ end
|
|||||||
|
|
||||||
function socketClass:ping()
|
function socketClass:ping()
|
||||||
if self.connected then
|
if self.connected then
|
||||||
_G.transport.ping(self)
|
network.getTransport().ping(self)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function socketClass:setupEncryption()
|
function socketClass:setupEncryption(x)
|
||||||
if false then
|
local timer = Util.timer()
|
||||||
self.sharedKey = ECC.exchange(self.privKey, self.remotePubKey)
|
self.sharedKey = ECC.exchange(self.privKey, self.remotePubKey)
|
||||||
self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1)
|
self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1)
|
||||||
self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1)
|
self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1)
|
||||||
self.rseed = SHA.pbkdf2(self.sharedKey, "3rseed", 1)
|
self.rseq = SHA.pbkdf2(self.sharedKey, x and "3rseed" or "4sseed", 1):toHex()
|
||||||
self.wseed = SHA.pbkdf2(self.sharedKey, "4sseed", 1)
|
self.wseq = SHA.pbkdf2(self.sharedKey, x and "4sseed" or "3rseed", 1):toHex()
|
||||||
end
|
_syslog('shared in ' .. timer())
|
||||||
end
|
end
|
||||||
|
|
||||||
function socketClass:close()
|
function socketClass:close()
|
||||||
if self.connected then
|
if self.connected then
|
||||||
self.transmit(self.dport, self.dhost, {
|
self.transmit(self.dport, self.dhost, {
|
||||||
type = 'DISC',
|
type = 'DISC',
|
||||||
|
seq = self.wseq,
|
||||||
})
|
})
|
||||||
self.connected = false
|
self.connected = false
|
||||||
end
|
end
|
||||||
device.wireless_modem.close(self.sport)
|
device.wireless_modem.close(self.sport)
|
||||||
_G.transport.close(self)
|
network.getTransport().close(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
local Socket = { }
|
local Socket = { }
|
||||||
@ -115,27 +117,24 @@ local function newSocket(isLoopback)
|
|||||||
error('No ports available')
|
error('No ports available')
|
||||||
end
|
end
|
||||||
|
|
||||||
function Socket.connect(host, port)
|
function Socket.connect(host, port, options)
|
||||||
if not device.wireless_modem then
|
if not device.wireless_modem then
|
||||||
return false, 'Wireless modem not found', 'NOMODEM'
|
return false, 'Wireless modem not found', 'NOMODEM'
|
||||||
end
|
end
|
||||||
|
local timer = Util.timer()
|
||||||
local socket = newSocket(host == os.getComputerID())
|
local socket = newSocket(host == os.getComputerID())
|
||||||
socket.dhost = tonumber(host)
|
socket.dhost = tonumber(host)
|
||||||
socket.privKey, socket.pubKey = Security.generateKeyPair()
|
socket.privKey, socket.pubKey = network.getKeyPair()
|
||||||
|
local identifier = options and options.identifier or Security.getIdentifier()
|
||||||
|
|
||||||
socket.transmit(port, socket.sport, {
|
socket.transmit(port, socket.sport, {
|
||||||
type = 'OPEN',
|
type = 'OPEN',
|
||||||
shost = socket.shost,
|
shost = socket.shost,
|
||||||
dhost = socket.dhost,
|
dhost = socket.dhost,
|
||||||
rseq = socket.wseq,
|
t = Crypto.encrypt({ -- this is not that much data...
|
||||||
wseq = socket.rseq,
|
ts = os.epoch('utc'),
|
||||||
t = Crypto.encrypt({
|
|
||||||
ts = os.time(),
|
|
||||||
seq = socket.seq,
|
|
||||||
nts = os.epoch('utc'),
|
|
||||||
pk = Util.byteArrayToHex(socket.pubKey),
|
pk = Util.byteArrayToHex(socket.pubKey),
|
||||||
}, Security.getPublicKey()),
|
}, Util.hexToByteArray(identifier)),
|
||||||
})
|
})
|
||||||
|
|
||||||
local timerId = os.startTimer(3)
|
local timerId = os.startTimer(3)
|
||||||
@ -152,10 +151,11 @@ function Socket.connect(host, port)
|
|||||||
socket.dport = dport
|
socket.dport = dport
|
||||||
socket.connected = true
|
socket.connected = true
|
||||||
socket.remotePubKey = Util.hexToByteArray(msg.pk)
|
socket.remotePubKey = Util.hexToByteArray(msg.pk)
|
||||||
socket:setupEncryption()
|
socket:setupEncryption(true)
|
||||||
-- Logger.log('socket', 'connection established to %d %d->%d',
|
-- Logger.log('socket', 'connection established to %d %d->%d',
|
||||||
-- host, socket.sport, socket.dport)
|
-- host, socket.sport, socket.dport)
|
||||||
_G.transport.open(socket)
|
network.getTransport().open(socket)
|
||||||
|
_syslog('connection in ' .. timer())
|
||||||
return socket
|
return socket
|
||||||
|
|
||||||
elseif msg.type == 'NOPASS' then
|
elseif msg.type == 'NOPASS' then
|
||||||
@ -173,35 +173,30 @@ function Socket.connect(host, port)
|
|||||||
return false, 'Connection timed out', 'TIMEOUT'
|
return false, 'Connection timed out', 'TIMEOUT'
|
||||||
end
|
end
|
||||||
|
|
||||||
local function trusted(socket, msg, port)
|
local function trusted(socket, msg, options)
|
||||||
if port == 19 or msg.shost == os.getComputerID() then
|
local function getIdentifier()
|
||||||
-- no auth for trust server or loopback
|
local trustList = Util.readTable('usr/.known_hosts') or { }
|
||||||
|
return trustList[msg.shost]
|
||||||
|
end
|
||||||
|
|
||||||
|
local identifier = options and options.identifier or getIdentifier()
|
||||||
|
|
||||||
|
if identifier and msg.t and type(msg.t) == 'table' then
|
||||||
|
local data = Crypto.decrypt(msg.t, Util.hexToByteArray(identifier))
|
||||||
|
|
||||||
|
if data and data.ts and tonumber(data.ts) then
|
||||||
|
_G._syslog('time diff ' .. math.abs(os.epoch('utc') - data.ts))
|
||||||
|
if math.abs(os.epoch('utc') - data.ts) < 4096 then
|
||||||
|
socket.remotePubKey = Util.hexToByteArray(data.pk)
|
||||||
|
socket.privKey, socket.pubKey = network.getKeyPair()
|
||||||
|
socket:setupEncryption()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if not Security.hasPassword() then
|
|
||||||
-- no password has been set on this computer
|
|
||||||
--return true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local trustList = Util.readTable('usr/.known_hosts') or { }
|
|
||||||
local pubKey = trustList[msg.shost]
|
|
||||||
|
|
||||||
if pubKey and msg.t then
|
|
||||||
local data = Crypto.decrypt(msg.t, Util.hexToByteArray(pubKey))
|
|
||||||
|
|
||||||
if data and data.nts then -- upgraded security
|
|
||||||
if data.nts and tonumber(data.nts) and math.abs(os.epoch('utc') - data.nts) < 1024 then
|
|
||||||
socket.remotePubKey = Util.hexToByteArray(data.pk)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--local sharedKey = modexp(pubKey, exchange.secretKey, public.primeMod)
|
function Socket.server(port, options)
|
||||||
return data and data.ts and tonumber(data.ts) and math.abs(os.time() - data.ts) < 24
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Socket.server(port)
|
|
||||||
device.wireless_modem.open(port)
|
device.wireless_modem.open(port)
|
||||||
-- Logger.log('socket', 'Waiting for connections on port ' .. port)
|
-- Logger.log('socket', 'Waiting for connections on port ' .. port)
|
||||||
|
|
||||||
@ -219,6 +214,7 @@ function Socket.server(port)
|
|||||||
socket.dhost = msg.shost
|
socket.dhost = msg.shost
|
||||||
socket.wseq = msg.wseq
|
socket.wseq = msg.wseq
|
||||||
socket.rseq = msg.rseq
|
socket.rseq = msg.rseq
|
||||||
|
socket.options = options
|
||||||
|
|
||||||
if not Security.hasPassword() then
|
if not Security.hasPassword() then
|
||||||
socket.transmit(socket.dport, socket.sport, {
|
socket.transmit(socket.dport, socket.sport, {
|
||||||
@ -228,10 +224,8 @@ function Socket.server(port)
|
|||||||
})
|
})
|
||||||
socket:close()
|
socket:close()
|
||||||
|
|
||||||
elseif trusted(socket, msg, port) then
|
elseif trusted(socket, msg, options) then
|
||||||
socket.connected = true
|
socket.connected = true
|
||||||
socket.privKey, socket.pubKey = Security.generateKeyPair()
|
|
||||||
socket:setupEncryption()
|
|
||||||
socket.transmit(socket.dport, socket.sport, {
|
socket.transmit(socket.dport, socket.sport, {
|
||||||
type = 'CONN',
|
type = 'CONN',
|
||||||
dhost = socket.dhost,
|
dhost = socket.dhost,
|
||||||
@ -241,7 +235,7 @@ function Socket.server(port)
|
|||||||
|
|
||||||
-- Logger.log('socket', 'Connection established %d->%d', socket.sport, socket.dport)
|
-- Logger.log('socket', 'Connection established %d->%d', socket.sport, socket.dport)
|
||||||
|
|
||||||
_G.transport.open(socket)
|
network.getTransport().open(socket)
|
||||||
return socket
|
return socket
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -20,6 +20,7 @@ function Util.hexToByteArray(str)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Util.byteArrayToHex(tbl)
|
function Util.byteArrayToHex(tbl)
|
||||||
|
if not tbl then error('byteArrayToHex: invalid table', 2) end
|
||||||
return ("%02x"):rep(#tbl):format(unpack(tbl))
|
return ("%02x"):rep(#tbl):format(unpack(tbl))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user