1. 二进制协议格式
每个数据包为以下格式
uint32 packet_length
byte padding_length
byte[n1] payload; n1 = packet_length - padding_length - 1
byte[n2] random padding; n2 = padding_length
byte[m] mac (Message Authentication Code - MAC); m = mac_length
packet_length: 以字节为单位的数据包长度,不包括 'mac' 或 'packet_length' 域自身。
padding_length: 'random padding' 的长度(字节)。
random padding: 任意长度的填充,使(packet_length || padding_length || payload || random padding)的总长度是加密分组长度或 8 中较大者的倍数。最少必须有 4 字节的填充。填充应包含随机字节。填充的最大长度为 255 字节。
mac: 消息验证码。如果已经协商了消息验证,该域包含 MAC。初始时,MAC 算法必须是"none"。
2. 协议过程
1) 协议版本交换
当 TCP 连接建立后,双方都必须发送一个标识字符。该标识字串必须是
SSH-protoversion-softwareversion SP comments CR LF
protoversion: 协议版本
softwareversion: 软件版本
SP: 空格
comments: 可选字符串
CR: 回车
LF: 换行
如使用同一主机上使用 OpenSSH 时,客户端发送:
服务器端都会发送:
2) 算法协商
密钥交换从每一方发送如下数据包开始:
byte SSH_MSG_KEXINIT
byte[16] cookie (random bytes)
name-list kex_algorithms
name-list server_host_key_algorithms
name-list encryption_algorithms_client_to_server
name-list encryption_algorithms_server_to_client
name-list mac_algorithms_client_to_server
name-list mac_algorithms_server_to_client
name-list compression_algorithms_client_to_server
name-list compression_algorithms_server_to_client
name-list languages_client_to_server
name-list languages_server_to_client
boolean first_kex_packet_follows
uint32 0 (为将来扩展预留)`
cookie: 必须是一个由发送方生成的随机值。它的作用是使任何一方都不可能对密钥和会话标识符拥有完全决定权。
kex_algorithms: 密钥交换算法。
server_host_key_algorithms: 受支持的为服务器主机密钥服务的算法的名称列表,按优先级排序。
encryption_algorithms: 可接受的对称加密算法(也称为加密器)的名称列表,按优先级排序。
mac_algorithms: 可接受的 MAC 算法的名称列表,按优先级排序。
compression_algorithms: 可接受的压缩算法的名称列表,按优先级排序。
languages: 语言标志的名称列表,按优先级排序。
first_kex_packet_follows: 表明是否有一个猜测的密钥交换数据包跟随。
如以 OpenSSH 为例,客户端和服务器都会发送:
3) Diffie-Hellman 密钥交换
首先,客户端发送:
byte SSH_MSG_KEXDH_INIT
mpint e
服务器响应如下:
byte SSH_MSG_KEXDH_REPLY
string K_S,服务器公钥和证书 (
mpint f
string s,对 H 的签名
密钥交换在每一方发送一个 SSH_MSG_NEWKEYS 消息后结束
byte SSH_MSG_NEWKEYS
以 OpenSSH 为例
客户端发送:
服务端响应:
客户端发送 New Keys:
服务端发送 New Keys:
之后,数据都以加密方式传输。
4) 总体过程
参考文档
http://git.oschina.net/lowkey2046/libssh/tree/master/document