encodelib.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. # Python module to make it easy to manually encode SSH packets, by
  2. # supporting the various uint32, string, mpint primitives.
  3. #
  4. # The idea of this is that you can use it to manually construct key
  5. # exchange sequences of interesting kinds, for testing purposes.
  6. import sys
  7. import struct
  8. import random
  9. assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
  10. def tobytes(s):
  11. return s if isinstance(s, bytes) else s.encode('ASCII')
  12. def boolean(b):
  13. return b"\1" if b else b"\0"
  14. def byte(b):
  15. assert 0 <= b < 0x100
  16. return bytes([b])
  17. def uint32(u):
  18. assert 0 <= u < 0x100000000
  19. return struct.pack(">I", u)
  20. def uint64(u):
  21. assert 0 <= u < 0x10000000000000000
  22. return struct.pack(">L", u)
  23. def string(s):
  24. return uint32(len(s)) + tobytes(s)
  25. def mpint(m):
  26. s = []
  27. while m > 0:
  28. s.append(m & 0xFF)
  29. m >>= 8
  30. if len(s) > 0 and (s[-1] & 0x80):
  31. s.append(0)
  32. s.reverse()
  33. return string(bytes(s))
  34. def name_list(ns):
  35. s = b""
  36. for n in map(tobytes, ns):
  37. assert b"," not in n
  38. if s != b"":
  39. s += b","
  40. s += n
  41. return string(s)
  42. def ssh_rsa_key_blob(modulus, exponent):
  43. return string(string("ssh-rsa") + mpint(modulus) + mpint(exponent))
  44. def ssh_rsa_signature_blob(signature):
  45. return string(string("ssh-rsa") + mpint(signature))
  46. def greeting(string):
  47. # Greeting at the start of an SSH connection.
  48. return tobytes(string) + b"\r\n"
  49. # Packet types.
  50. SSH2_MSG_DISCONNECT = 1
  51. SSH2_MSG_IGNORE = 2
  52. SSH2_MSG_UNIMPLEMENTED = 3
  53. SSH2_MSG_DEBUG = 4
  54. SSH2_MSG_SERVICE_REQUEST = 5
  55. SSH2_MSG_SERVICE_ACCEPT = 6
  56. SSH2_MSG_KEXINIT = 20
  57. SSH2_MSG_NEWKEYS = 21
  58. SSH2_MSG_KEXDH_INIT = 30
  59. SSH2_MSG_KEXDH_REPLY = 31
  60. SSH2_MSG_KEX_DH_GEX_REQUEST_OLD = 30
  61. SSH2_MSG_KEX_DH_GEX_GROUP = 31
  62. SSH2_MSG_KEX_DH_GEX_INIT = 32
  63. SSH2_MSG_KEX_DH_GEX_REPLY = 33
  64. SSH2_MSG_KEX_DH_GEX_REQUEST = 34
  65. SSH2_MSG_KEXRSA_PUBKEY = 30
  66. SSH2_MSG_KEXRSA_SECRET = 31
  67. SSH2_MSG_KEXRSA_DONE = 32
  68. SSH2_MSG_USERAUTH_REQUEST = 50
  69. SSH2_MSG_USERAUTH_FAILURE = 51
  70. SSH2_MSG_USERAUTH_SUCCESS = 52
  71. SSH2_MSG_USERAUTH_BANNER = 53
  72. SSH2_MSG_USERAUTH_PK_OK = 60
  73. SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ = 60
  74. SSH2_MSG_USERAUTH_INFO_REQUEST = 60
  75. SSH2_MSG_USERAUTH_INFO_RESPONSE = 61
  76. SSH2_MSG_GLOBAL_REQUEST = 80
  77. SSH2_MSG_REQUEST_SUCCESS = 81
  78. SSH2_MSG_REQUEST_FAILURE = 82
  79. SSH2_MSG_CHANNEL_OPEN = 90
  80. SSH2_MSG_CHANNEL_OPEN_CONFIRMATION = 91
  81. SSH2_MSG_CHANNEL_OPEN_FAILURE = 92
  82. SSH2_MSG_CHANNEL_WINDOW_ADJUST = 93
  83. SSH2_MSG_CHANNEL_DATA = 94
  84. SSH2_MSG_CHANNEL_EXTENDED_DATA = 95
  85. SSH2_MSG_CHANNEL_EOF = 96
  86. SSH2_MSG_CHANNEL_CLOSE = 97
  87. SSH2_MSG_CHANNEL_REQUEST = 98
  88. SSH2_MSG_CHANNEL_SUCCESS = 99
  89. SSH2_MSG_CHANNEL_FAILURE = 100
  90. SSH2_MSG_USERAUTH_GSSAPI_RESPONSE = 60
  91. SSH2_MSG_USERAUTH_GSSAPI_TOKEN = 61
  92. SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE = 63
  93. SSH2_MSG_USERAUTH_GSSAPI_ERROR = 64
  94. SSH2_MSG_USERAUTH_GSSAPI_ERRTOK = 65
  95. SSH2_MSG_USERAUTH_GSSAPI_MIC = 66
  96. def clearpkt(msgtype, *stuff):
  97. # SSH-2 binary packet, in the cleartext format used for initial
  98. # setup and kex.
  99. s = byte(msgtype)
  100. for thing in stuff:
  101. s += thing
  102. padlen = 0
  103. while padlen < 4 or len(s) % 8 != 3:
  104. padlen += 1
  105. s += byte(random.randint(0,255))
  106. s = byte(padlen) + s
  107. return string(s)
  108. def decode_uint32(s):
  109. assert len(s) == 4
  110. return struct.unpack(">I", s)[0]
  111. def read_clearpkt(fh):
  112. length_field = fh.read(4)
  113. s = fh.read(decode_uint32(length_field))
  114. padlen, msgtype = s[:2]
  115. return msgtype, s[2:-padlen]