Skip to content

Instantly share code, notes, and snippets.

@rphillips
Created June 19, 2015 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rphillips/8e996de28468b6a6209f to your computer and use it in GitHub Desktop.
Save rphillips/8e996de28468b6a6209f to your computer and use it in GitHub Desktop.
local openssl = require('openssl')
local tcp = require('coro-tcp')
local table = require('table')
local bit = require('bit')
local LOCAL_VERSION = "SSH-2.0-LUVIT-1"
local SUPPORTED_HOSTKEY_ALGOS = "ssh-rsa"
local SUPPORTED_MAC_MODE = "hmac-sha2-256"
local SUPPORTED_CIPHER_MODE = "aes256-ctr"
local SUPPORTED_KEX_ALGOS = "ecdh-sha2-nistp256"
local SUPPORTED_COMPRESSION_MODE = "none"
local function parseUint32(buffer, offset)
offset = offset or 1
local num = bit.bor(
bit.lshift(string.byte(buffer, offset), 24),
bit.lshift(string.byte(buffer, offset + 1), 16),
bit.lshift(string.byte(buffer, offset + 2), 8),
string.byte(buffer, offset + 3)
)
return num, 4
end
local function writeUint32(num)
return table.concat({
string.char(bit.band(bit.rshift(num, 24), 0xff)),
string.char(bit.band(bit.rshift(num, 16), 0xff)),
string.char(bit.band(bit.rshift(num, 8), 0xff)),
string.char(bit.band(num, 0xff)),
})
end
exports.client = function()
local rawRead, rawWrite, socket
local buffer = ''
local function exchangeVersion()
buffer = buffer .. rawRead()
local idx = buffer:find('\n')
if idx == -1 then return end
buffer = buffer:sub(idx + 1)
rawWrite(LOCAL_VERSION .. '\r\n')
end
local padLengthMultiple = 16
local function send(payload)
payload = table.concat(payload)
local pktlen = #payload + 9
pktlen = pktlen + ((padLengthMultiple - 1) * pktlen) % padLengthMultiple
local padLen = pktlen - #payload - 5
local frame = {
writeUint32(pktlen - 4),
string.char(padLen),
payload,
openssl.random(padLen)
}
rawWrite(table.concat(frame))
end
local function readKex()
local length, offsetAdd, offset, pktLen
buffer = buffer .. rawRead()
if #buffer < 20 then return end
pktLen, offsetAdd = parseUint32(buffer)
while #buffer < pktLen - 4 do
buffer = buffer.. rawRead()
end
local padLen = string.byte(buffer, 5)
local type = string.byte(buffer, 6)
local cookie = string.sub(buffer, 7, 22)
length, offsetAdd = parseUint32(buffer, 23)
offset = 23 + offsetAdd + length - 1
local kexStr = buffer:sub(27, offset)
offset = offset + 1
length, offsetAdd = parseUint32(buffer, offset)
offset = offset + offsetAdd
local keyFormats = buffer:sub(offset, offset + length - 1)
offset = offset + length
length, offsetAdd = parseUint32(buffer, offset)
offset = offset + offsetAdd
local clientServerCiphers = buffer:sub(offset, offset + length - 1)
offset = offset + length
length, offsetAdd = parseUint32(buffer, offset)
offset = offset + offsetAdd
local serverClientCiphers = buffer:sub(offset, offset + length - 1)
offset = offset + length
length, offsetAdd = parseUint32(buffer, offset)
offset = offset + offsetAdd
local clientServerHMAC = buffer:sub(offset, offset + length - 1)
offset = offset + length
length, offsetAdd = parseUint32(buffer, offset)
offset = offset + offsetAdd
local serverClientHMAC = buffer:sub(offset, offset + length - 1)
offset = offset + length
length, offsetAdd = parseUint32(buffer, offset)
offset = offset + offsetAdd
local clientServerCompression = buffer:sub(offset, offset + length - 1)
offset = offset + length
length, offsetAdd = parseUint32(buffer, offset)
offset = offset + offsetAdd
local serverClientCompression = buffer:sub(offset, offset + length - 1)
buffer = buffer:sub(pktLen + 5)
p('type', type)
p('cookie', cookie)
p('kexStr', kexStr)
p('keyFormats', keyFormats)
p('clientServerCiphers', clientServerCiphers)
p('serverClientCiphers', serverClientCiphers)
p('clientServerHMAC', clientServerHMAC)
p('serverClientHMAC', serverClientHMAC)
p('clientServerCompression', clientServerCompression)
p('serverClientCompression', serverClientCompression)
local msg = {
string.char(20),
openssl.random(16),
writeUint32(#SUPPORTED_KEX_ALGOS), SUPPORTED_KEX_ALGOS, -- kexlist
writeUint32(#SUPPORTED_HOSTKEY_ALGOS), SUPPORTED_HOSTKEY_ALGOS, -- server host key algos
writeUint32(#SUPPORTED_CIPHER_MODE), SUPPORTED_CIPHER_MODE, -- cipher list
writeUint32(#SUPPORTED_CIPHER_MODE), SUPPORTED_CIPHER_MODE, -- cipher list
writeUint32(#SUPPORTED_MAC_MODE), SUPPORTED_MAC_MODE, -- hmac
writeUint32(#SUPPORTED_MAC_MODE), SUPPORTED_MAC_MODE, -- hmac
writeUint32(#SUPPORTED_COMPRESSION_MODE), SUPPORTED_COMPRESSION_MODE, -- compress
writeUint32(#SUPPORTED_COMPRESSION_MODE), SUPPORTED_COMPRESSION_MODE, -- compress
writeUint32(0), "", -- languages
writeUint32(0), "", -- languages
string.rep(string.char(0), 5) -- reserve
}
send(msg)
end
local function connect(options)
rawRead, rawWrite, socket = tcp.connect(options.host, options.port)
exchangeVersion()
readKex()
end
return {
connect = connect
}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment