security updates

This commit is contained in:
kepler155c@gmail.com
2019-06-29 16:35:33 -04:00
parent 69522e61d4
commit e75a357209
15 changed files with 147 additions and 119 deletions

View File

@@ -2,7 +2,7 @@
-- By Anavrins
local sha2 = require('opus.crypto.sha2')
local util = require('opus.util')
local Util = require('opus.util')
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
round = tonumber(round) or 20
local throttle = util.throttle()
local throttle = Util.throttle()
local out = {}
local state = initState(key, nonce, cntr)
local blockAmt = math.floor(#data/64)
@@ -157,8 +157,8 @@ local function encrypt(data, key)
end
local function decrypt(data, key)
local nonce = util.hexToByteArray(data[1])
data = util.hexToByteArray(data[2])
local nonce = Util.hexToByteArray(data[1])
data = Util.hexToByteArray(data[2])
key = sha2.digest(key)
local ptx = crypt(data, key, nonce, 1, ROUNDS)
return textutils.unserialise(tostring(ptx))

View File

@@ -22,6 +22,8 @@
-- Indistinguishability? No: The curve does not support indistinguishability maps.
local fp = require('opus.crypto.ecc.fp')
local Util = require('opus.util')
local eq = fp.eq
local mul = fp.mul
local sqr = fp.sqr
@@ -31,6 +33,7 @@ local shr = fp.shr
local mont = fp.mont
local invMont = fp.invMont
local sub192 = fp.sub192
local unpack = table.unpack
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}
@@ -203,20 +206,23 @@ local function scalarMul(s, P1)
end
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)
if naf[i] > 0 then
Q = pointAdd(Q, PTable[naf[i]])
elseif naf[i] < 0 then
Q = pointSub(Q, PTable[-naf[i]])
if n > 0 then
Q = pointAdd(Q, PTable[n])
elseif n < 0 then
Q = pointSub(Q, PTable[-n])
end
end
return Q
end
local throttle = Util.throttle()
for i = 2, 196 do
GTable[i] = pointDouble(GTable[i - 1])
throttle()
end
local function scalarMulG(s)

View File

@@ -1,5 +1,7 @@
-- Fp Integer Arithmetic
local unpack = table.unpack
local n = 0xffff
local m = 0x10000

View File

@@ -1,5 +1,7 @@
-- Fq Integer Arithmetic
local unpack = table.unpack
local n = 0xffff
local m = 0x10000

View File

@@ -3,6 +3,7 @@ local elliptic = require('opus.crypto.ecc.elliptic')
local sha256 = require('opus.crypto.sha2')
local os = _G.os
local unpack = table.unpack
local q = {1372, 62520, 47765, 8105, 45059, 9616, 65535, 65535, 65535, 65535, 65535, 65532}

View File

@@ -1,8 +1,8 @@
-- SHA-256, HMAC and PBKDF2 functions in ComputerCraft
-- By Anavrins
local Util = require('opus.util')
local bit = _G.bit
local os = _G.os
local mod32 = 2^32
local band = bit32 and bit32.band or bit.band
local bnot = bit32 and bit32.bnot or bit.bnot
@@ -162,25 +162,13 @@ local function hmac(data, key)
return digest(padded_key)
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)
salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)}
local hashlen = 32
dklen = dklen or 32
local block = 1
local out = {}
local throttle = throttler()
local throttle = Util.throttle()
while dklen > 0 do
local ikey = {}

View File

@@ -1,6 +1,6 @@
local Config = require('opus.config')
local Util = require('opus.util')
local ECC = require('opus.crypto.ecc')
local Util = require('opus.util')
local Security = { }
@@ -21,16 +21,6 @@ local function genKey()
return table.concat(key)
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()
local config = Config.load('os')
if not config.secretKey then
@@ -40,9 +30,17 @@ function Security.getSecretKey()
return Util.hexToByteArray(config.secretKey)
end
function Security.getPublicKey()
local secretKey = Security.getSecretKey()
return ECC.publicKey(secretKey)
function Security.getIdentifier()
local config = Config.load('os')
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
function Security.updatePassword(password)

View File

@@ -6,11 +6,12 @@ local Util = require('opus.util')
local device = _G.device
local os = _G.os
local network = _G.network
local socketClass = { }
function socketClass:read(timeout)
local data, distance = _G.transport.read(self)
local data, distance = network.getTransport().read(self)
if data then
return data, distance
end
@@ -25,7 +26,7 @@ function socketClass:read(timeout)
local e, id = os.pullEvent()
if e == 'transport_' .. self.uid then
data, distance = _G.transport.read(self)
data, distance = network.getTransport().read(self)
if data then
os.cancelTimer(timerId)
return data, distance
@@ -46,7 +47,7 @@ end
function socketClass:write(data)
if self.connected then
_G.transport.write(self, {
network.getTransport().write(self, {
type = 'DATA',
seq = self.wseq,
data = data,
@@ -57,30 +58,31 @@ end
function socketClass:ping()
if self.connected then
_G.transport.ping(self)
network.getTransport().ping(self)
return true
end
end
function socketClass:setupEncryption()
if false then
function socketClass:setupEncryption(x)
local timer = Util.timer()
self.sharedKey = ECC.exchange(self.privKey, self.remotePubKey)
self.enckey = SHA.pbkdf2(self.sharedKey, "1enc", 1)
self.hmackey = SHA.pbkdf2(self.sharedKey, "2hmac", 1)
self.rseed = SHA.pbkdf2(self.sharedKey, "3rseed", 1)
self.wseed = SHA.pbkdf2(self.sharedKey, "4sseed", 1)
end
self.rseq = SHA.pbkdf2(self.sharedKey, x and "3rseed" or "4sseed", 1):toHex()
self.wseq = SHA.pbkdf2(self.sharedKey, x and "4sseed" or "3rseed", 1):toHex()
_syslog('shared in ' .. timer())
end
function socketClass:close()
if self.connected then
self.transmit(self.dport, self.dhost, {
type = 'DISC',
seq = self.wseq,
})
self.connected = false
end
device.wireless_modem.close(self.sport)
_G.transport.close(self)
network.getTransport().close(self)
end
local Socket = { }
@@ -115,27 +117,24 @@ local function newSocket(isLoopback)
error('No ports available')
end
function Socket.connect(host, port)
function Socket.connect(host, port, options)
if not device.wireless_modem then
return false, 'Wireless modem not found', 'NOMODEM'
end
local timer = Util.timer()
local socket = newSocket(host == os.getComputerID())
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, {
type = 'OPEN',
shost = socket.shost,
dhost = socket.dhost,
rseq = socket.wseq,
wseq = socket.rseq,
t = Crypto.encrypt({
ts = os.time(),
seq = socket.seq,
nts = os.epoch('utc'),
t = Crypto.encrypt({ -- this is not that much data...
ts = os.epoch('utc'),
pk = Util.byteArrayToHex(socket.pubKey),
}, Security.getPublicKey()),
}, Util.hexToByteArray(identifier)),
})
local timerId = os.startTimer(3)
@@ -152,10 +151,11 @@ function Socket.connect(host, port)
socket.dport = dport
socket.connected = true
socket.remotePubKey = Util.hexToByteArray(msg.pk)
socket:setupEncryption()
socket:setupEncryption(true)
-- Logger.log('socket', 'connection established to %d %d->%d',
-- host, socket.sport, socket.dport)
_G.transport.open(socket)
network.getTransport().open(socket)
_syslog('connection in ' .. timer())
return socket
elseif msg.type == 'NOPASS' then
@@ -173,35 +173,30 @@ function Socket.connect(host, port)
return false, 'Connection timed out', 'TIMEOUT'
end
local function trusted(socket, msg, port)
if port == 19 or msg.shost == os.getComputerID() then
-- no auth for trust server or loopback
return true
local function trusted(socket, msg, options)
local function getIdentifier()
local trustList = Util.readTable('usr/.known_hosts') or { }
return trustList[msg.shost]
end
if not Security.hasPassword() then
-- no password has been set on this computer
--return true
end
local identifier = options and options.identifier or getIdentifier()
local trustList = Util.readTable('usr/.known_hosts') or { }
local pubKey = trustList[msg.shost]
if identifier and msg.t and type(msg.t) == 'table' then
local data = Crypto.decrypt(msg.t, Util.hexToByteArray(identifier))
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
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
end
end
--local sharedKey = modexp(pubKey, exchange.secretKey, public.primeMod)
return data and data.ts and tonumber(data.ts) and math.abs(os.time() - data.ts) < 24
end
end
function Socket.server(port)
function Socket.server(port, options)
device.wireless_modem.open(port)
-- Logger.log('socket', 'Waiting for connections on port ' .. port)
@@ -219,6 +214,7 @@ function Socket.server(port)
socket.dhost = msg.shost
socket.wseq = msg.wseq
socket.rseq = msg.rseq
socket.options = options
if not Security.hasPassword() then
socket.transmit(socket.dport, socket.sport, {
@@ -228,10 +224,8 @@ function Socket.server(port)
})
socket:close()
elseif trusted(socket, msg, port) then
elseif trusted(socket, msg, options) then
socket.connected = true
socket.privKey, socket.pubKey = Security.generateKeyPair()
socket:setupEncryption()
socket.transmit(socket.dport, socket.sport, {
type = 'CONN',
dhost = socket.dhost,
@@ -241,7 +235,7 @@ function Socket.server(port)
-- Logger.log('socket', 'Connection established %d->%d', socket.sport, socket.dport)
_G.transport.open(socket)
network.getTransport().open(socket)
return socket
else

View File

@@ -20,6 +20,7 @@ function Util.hexToByteArray(str)
end
function Util.byteArrayToHex(tbl)
if not tbl then error('byteArrayToHex: invalid table', 2) end
return ("%02x"):rep(#tbl):format(unpack(tbl))
end