Skip to content

Instantly share code, notes, and snippets.

@gorsuch
Created July 7, 2011 17:14
Show Gist options
  • Save gorsuch/1070018 to your computer and use it in GitHub Desktop.
Save gorsuch/1070018 to your computer and use it in GitHub Desktop.
simple twisted ssh server w/o keys
from twisted.cred import portal, checkers, credentials
from twisted.conch import error, avatar, recvline, interfaces as conchinterfaces
from twisted.conch.ssh import factory, userauth, connection, keys, session, common
from twisted.conch.insults import insults
from twisted.application import service, internet
from zope.interface import implements
import os
class SSHDemoProtocol(recvline.HistoricRecvLine):
def __init__(self, user):
self.user = user
def connectionMade(self):
recvline.HistoricRecvLine.connectionMade(self)
self.terminal.write("Welcome to my test SSH server.")
self.terminal.nextLine( )
self.showPrompt( )
def showPrompt(self):
self.terminal.write("$ ")
def lineReceived(self, line):
self.terminal.write(line)
self.terminal.nextLine()
self.showPrompt( )
class SSHDemoAvatar(avatar.ConchUser):
implements(conchinterfaces.ISession)
def __init__(self, username):
avatar.ConchUser.__init__(self)
self.username = username
self.channelLookup.update({'session':session.SSHSession})
def openShell(self, protocol):
serverProtocol = insults.ServerProtocol(SSHDemoProtocol, self)
serverProtocol.makeConnection(protocol)
protocol.makeConnection(session.wrapProtocol(serverProtocol))
def getPty(self, terminal, windowSize, attrs):
return None
def execCommand(self, protocol, cmd):
raise NotImplementedError
def closed(self):
pass
class SSHDemoRealm:
implements(portal.IRealm)
def requestAvatar(self, avatarId, mind, *interfaces):
if conchinterfaces.IConchUser in interfaces:
return interfaces[0], SSHDemoAvatar(avatarId), lambda: None
else:
raise Exception, "No supported interfaces found."
def getRSAKeys():
if not (os.path.exists('public.key') and os.path.exists('private.key')):
# generate a RSA keypair
print "Generating RSA keypair..."
from Crypto.PublicKey import RSA
KEY_LENGTH = 1024
rsaKey = RSA.generate(KEY_LENGTH, common.entropy.get_bytes)
publicKeyString = keys.makePublicKeyString(rsaKey)
privateKeyString = keys.makePrivateKeyString(rsaKey)
# save keys for next time
file('public.key', 'w+b').write(publicKeyString)
file('private.key', 'w+b').write(privateKeyString)
print "done."
else:
publicKeyString = file('public.key').read()
privateKeyString = file('private.key').read()
return publicKeyString, privateKeyString
if __name__ == "__main__":
sshFactory = factory.SSHFactory()
sshFactory.portal = portal.Portal(SSHDemoRealm())
users = {'admin': 'aaa', 'guest': 'bbb'}
sshFactory.portal.registerChecker(checkers.InMemoryUsernamePasswordDatabaseDontUse(**users))
pubKeyString, privKeyString = getRSAKeys()
sshFactory.publicKeys = {
'ssh-rsa': keys.getPublicKeyString(data=pubKeyString)}
sshFactory.privateKeys = {
'ssh-rsa': keys.getPrivateKeyObject(data=privKeyString)}
from twisted.internet import reactor
reactor.listenTCP(2222, sshFactory)
reactor.run( )
@CDWimmer
Copy link

why name this "without keys" when it literally either requires or will generate a key...

@gorsuch
Copy link
Author

gorsuch commented May 17, 2022

why name this "without keys" when it literally either requires or will generate a key...

@CDWimmer great question -- honestly, this gist was written 11 years ago, and I barely remember it. I'm not sure why I named it that way.

@CDWimmer
Copy link

CDWimmer commented May 17, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment