secure telnet

This commit is contained in:
kepler155c@gmail.com 2019-06-29 23:43:21 -04:00
parent 1c29197983
commit 67779ab814
6 changed files with 51 additions and 41 deletions

View File

@ -6,7 +6,7 @@ local kernel = _G.kernel
local term = _G.term local term = _G.term
local window = _G.window local window = _G.window
local function telnetHost(socket) local function telnetHost(socket, mode)
local methods = { 'clear', 'clearLine', 'setCursorPos', 'write', 'blit', local methods = { 'clear', 'clearLine', 'setCursorPos', 'write', 'blit',
'setTextColor', 'setTextColour', 'setBackgroundColor', 'setTextColor', 'setTextColour', 'setBackgroundColor',
'setBackgroundColour', 'scroll', 'setCursorBlink', } 'setBackgroundColour', 'scroll', 'setCursorBlink', }
@ -43,7 +43,7 @@ local function telnetHost(socket)
local shellThread = kernel.run({ local shellThread = kernel.run({
terminal = win, terminal = win,
window = win, window = win,
title = 'Telnet client', title = mode .. ' client',
hidden = true, hidden = true,
co = coroutine.create(function() co = coroutine.create(function()
Util.run(_ENV, 'sys/apps/shell.lua', table.unpack(termInfo.program)) Util.run(_ENV, 'sys/apps/shell.lua', table.unpack(termInfo.program))
@ -68,6 +68,23 @@ local function telnetHost(socket)
end) end)
end end
Event.addRoutine(function()
print('ssh: listening on port 22')
while true do
local socket = Socket.server(22, { ENCRYPT = true })
print('ssh: connection from ' .. socket.dhost)
Event.addRoutine(function()
local s, m = pcall(telnetHost, socket, 'SSH')
if not s and m then
print('ssh error')
_G.printError(m)
end
end)
end
end)
Event.addRoutine(function() Event.addRoutine(function()
print('telnet: listening on port 23') print('telnet: listening on port 23')
while true do while true do
@ -76,7 +93,7 @@ Event.addRoutine(function()
print('telnet: connection from ' .. socket.dhost) print('telnet: connection from ' .. socket.dhost)
Event.addRoutine(function() Event.addRoutine(function()
local s, m = pcall(telnetHost, socket) local s, m = pcall(telnetHost, socket, 'Telnet')
if not s and m then if not s and m then
print('Telnet error') print('Telnet error')
_G.printError(m) _G.printError(m)

View File

@ -5,7 +5,8 @@
* background read buffering * background read buffering
]]-- ]]--
local Event = require('opus.event') local Crypto = require('opus.crypto.chacha20')
local Event = require('opus.event')
local network = _G.network local network = _G.network
local os = _G.os local os = _G.os
@ -32,7 +33,10 @@ end
function transport.read(socket) function transport.read(socket)
local data = table.remove(socket.messages, 1) local data = table.remove(socket.messages, 1)
if data then if data then
return unpack(data) if socket.options.ENCRYPT then
return table.unpack(Crypto.decrypt(data[1], socket.enckey)), data[2]
end
return table.unpack(data)
end end
end end

View File

@ -9,7 +9,7 @@ local read = _G.read
local shell = _ENV.shell local shell = _ENV.shell
local term = _G.term local term = _G.term
local args = { ... } local args, options = Util.parse(...)
local remoteId = tonumber(table.remove(args, 1) or '') local remoteId = tonumber(table.remove(args, 1) or '')
if not remoteId then if not remoteId then
@ -22,13 +22,14 @@ if not remoteId then
end end
if multishell then if multishell then
multishell.setTitle(multishell.getCurrent(), 'Telnet ' .. remoteId) multishell.setTitle(multishell.getCurrent(),
(options.s and 'Secure ' or 'Telnet ') .. remoteId)
end end
local socket, msg, reason local socket, msg, reason
while true do while true do
socket, msg, reason = Socket.connect(remoteId, 23) socket, msg, reason = Socket.connect(remoteId, options.s and 22 or 23)
if socket then if socket then
break break

View File

@ -166,10 +166,10 @@ local function decrypt(data, key)
end end
local obj = {} local obj = {}
local mt = {['__index'] = obj} local rng_mt = {['__index'] = obj}
function obj:nextInt(byte) function obj:nextInt(byte)
if byte < 1 or byte > 6 then error("Can only return 1-6 bytes", 2) end if not byte or byte < 1 or byte > 6 then error("Can only return 1-6 bytes", 2) end
local output = 0 local output = 0
for i = 0, byte-1 do for i = 0, byte-1 do
if #self.block == 0 then if #self.block == 0 then
@ -189,7 +189,7 @@ local function newRNG(seed)
o.cnt = 0 o.cnt = 0
o.block = {} o.block = {}
return setmetatable(o, mt) return setmetatable(o, rng_mt)
end end
return { return {

View File

@ -1,6 +1,4 @@
local Config = require('opus.config') local Config = require('opus.config')
local ECC = require('opus.crypto.ecc')
local Util = require('opus.util')
local Security = { } local Security = { }
@ -13,32 +11,18 @@ function Security.hasPassword()
return not not Security.getPassword() return not not Security.getPassword()
end end
local function genKey()
local key = { }
for _ = 1, 32 do
table.insert(key, ("%02x"):format(math.random(0, 0xFF)))
end
return table.concat(key)
end
function Security.getSecretKey()
local config = Config.load('os')
if not config.secretKey then
config.secretKey = genKey()
Config.update('os', config)
end
return Util.hexToByteArray(config.secretKey)
end
function Security.getIdentifier() function Security.getIdentifier()
local config = Config.load('os') local config = Config.load('os')
if config.identifier then
return config.identifier if not config.identifier then
local key = { }
for _ = 1, 32 do
table.insert(key, ("%02x"):format(math.random(0, 0xFF)))
end
config.identifier = table.concat(key)
Config.update('os', config)
end 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 return config.identifier
end end

View File

@ -47,6 +47,9 @@ end
function socketClass:write(data) function socketClass:write(data)
if self.connected then if self.connected then
if self.options.ENCRYPT then
data = Crypto.encrypt({ data }, self.enckey)
end
network.getTransport().write(self, { network.getTransport().write(self, {
type = 'DATA', type = 'DATA',
seq = self.wseq, seq = self.wseq,
@ -70,7 +73,7 @@ function socketClass:setupEncryption(x)
SHA.pbkdf2(self.sharedKey, x and "4sseed" or "3rseed", 1)) SHA.pbkdf2(self.sharedKey, x and "4sseed" or "3rseed", 1))
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.rseq = self.rrng:nextInt(5) self.rseq = self.rrng:nextInt(5)
self.wseq = self.wrng:nextInt(5) self.wseq = self.wrng:nextInt(5)
@ -144,15 +147,15 @@ function Socket.connect(host, port, options)
if e == 'modem_message' and if e == 'modem_message' and
sport == socket.sport and sport == socket.sport and
type(msg) == 'table' and type(msg) == 'table' and
msg.dhost == socket.shost and msg.dhost == socket.shost then
type(msg.pk) == 'string' then
os.cancelTimer(timerId) os.cancelTimer(timerId)
if msg.type == 'CONN' then if msg.type == 'CONN' and type(msg.pk) == 'string' then
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.options = msg.options or { }
socket:setupEncryption(true) socket:setupEncryption(true)
network.getTransport().open(socket) network.getTransport().open(socket)
return socket return socket
@ -210,7 +213,7 @@ function Socket.server(port, options)
local socket = newSocket(msg.shost == os.getComputerID()) local socket = newSocket(msg.shost == os.getComputerID())
socket.dport = dport socket.dport = dport
socket.dhost = msg.shost socket.dhost = msg.shost
socket.options = options socket.options = options or { }
if not Security.hasPassword() then if not Security.hasPassword() then
socket.transmit(socket.dport, socket.sport, { socket.transmit(socket.dport, socket.sport, {
@ -227,6 +230,7 @@ function Socket.server(port, options)
dhost = socket.dhost, dhost = socket.dhost,
shost = socket.shost, shost = socket.shost,
pk = Util.byteArrayToHex(socket.pubKey), pk = Util.byteArrayToHex(socket.pubKey),
options = socket.options.ENCRYPT and { ENCRYPT = true },
}) })
network.getTransport().open(socket) network.getTransport().open(socket)