`
fly.net.cn
  • 浏览: 183513 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

SH通信协议(密钥的交换和加密的启动)

    博客分类:
  • ssh
阅读更多
在服务器端有一个主机密钥文件,它的内容构成是这样的:

      1. 私钥文件格式版本字符串;

      2. 加密类型(1 个字节);

      3. 保留字(4 个字节);

      4. 4 个字节的无符号整数;

      5. mp 型整数;

      6. mp 型整数;

      7. 注解字符串的长度;

      8. 注解字符串;

      9. 校验字(4 个字节);

      10. mp 型整数;

      11. mp 型整数;

      12. mp 型整数;

      13. mp 型整数;

      其 中 4、5、6 三个字段构成主机密钥的公钥部分;10、11、12、13 四个字段构成主机密钥的私钥部分。9、10、11、12、13 五个字段用字段 2 的加密类型标记的加密方法进行了加密。4 个字节的校验字交叉相等,即第一个字节与第三个字节相等,第二个字节与第四个字节相等。在服务器读取这个文件时进行这种交叉相等检查,如果不满足这个条 件,则报错退出。

      服务器程序运行的第一步,就是按照上面的字段划分读取主机密钥文件。随后生成一个随机数,再调用函数

void rsa_generate_key(RSAPrivateKey *prv,RSAPublicKey *pub, RandomState *state,unsigned int bits);

生成服务密钥,服务密钥也由公钥和私钥两部分组成。上面的这个函数第一个指针参数指向服务密钥的私钥部分,第二个指向公钥部分。然后把主机密钥的公钥部分和 服务密钥的公钥部分发送给客户端。在等到客户端回应的包后,服务器用自己的主机密钥的私钥部分和服务密钥的私钥部分解密得到客户端发来的 32 字节随机字串。然后计算自己的会话号,并用会话号的前 16字节 xor 客户端发来的 32 字节随机字串的前 16 字节,把它作为自己的会话密钥。注意,服务器把8个字节的 cookie、主机密钥的公钥部分、和服务密钥的公钥部分作为参数来计算自己的会话号。

       再来看客户端。客户端启动后的第一步骤也是读取主机密钥。然后等待服务器主机密钥、服务密钥、和 8个字节的cookie。注意,服务器发送来的只是主机密钥和服务密钥的公钥部分。接到包后,客户端立即把从服务器端收到cookie、主机密钥、和服务 密钥作为参数计算出会话号。从上面可以看出,服务器和客户端各自计算出的会话号实际是一样的。

      随后,客户端检查用户主机列表和系统主机列 表,查看从服务器收到的主机密钥是否在列表中。如果不在列表中,则把它加入列表中。然后就生成 32 字节的随机字串,这个32 字节的随机字串就是客户端的会话密钥。客户端用 16字节的会话密钥 xor 它的前 16 字节,把结果用服务器的主机密钥和服务密钥进行双重加密后发送给服务器。产生 32字节随机字串时,随机数种子由两部分组成,其中一部分从系统随机数种子文件中得到,这样来避免会话密钥被猜出。从上面服务器和客户端各自计算会话密钥 的过程可以看出,服务器和客户端计算出的会话密钥是一样的。

      上面的这几步,总结起来就要交换确定会话密钥,因为无论是 des、idea、3des、arcfour、还是 blowfish 都是对称加密方法,只有一把密钥,双方都知道了会话密钥才能启动加密。但会话密钥不能在网络上明文传送,否则加密就失去意义了。于是使用 RSA 公钥体系对会话密钥进行加密。

      RSA 公钥体系的办法是用公钥加密私钥解密,它依据这样的数学定理:

      若 p、q 是相异的两个质数,整数 r 和 m 满足

      rm == 1 (mod (p-1)(q-1))

      a 是任意的整数,整数 b、c 满足 b == a^m (mod pq),

      c == b^r (mod pq)。则

      c == a (mod pq)。

      具体实现是这样的:

     (1) 找三个正整数 p、q、r,其中 p、q 是相异的质数,r 是与(p-1)、(q-1)互质的数。

     这三个数 p、q、r就是私钥(private key)。

     (2) 再找一个正整数 m 满足 rm == 1 (mod(p-1)(q-1))。

     计算 n = pq,m、n 就是公钥(public key)。

    (3) 被加密对象 a 看成是正整数,设 a < n。若 a >= n,将 a 表示成 s (s < n,通常取 s = 2^t) 进制的,

    然后对每一位分别编码。

    (4) 加密:计算 b == a^m (mod n) (0 <= b < n),b 为加密结果。

    (5) 解密:计算 c == b^r (mod n) (0 <= c < n),c 为解密结果。

     从上面的数学定理可知,最后结果 c = a。

     服务密钥生成后,服务器发送一个包把两把密钥发送给客户端,一个是主机密钥的公钥,另一个是服务密钥的公钥。跟随这个包一起发送的还有服务器支持的加密类 型和8个字节即64位的随机字串 cookie。客户端依据这两把密钥计算会话号,会话号长16字节即128位。计算方法是:

     会话号 = MD5(主机公钥模数 n || 服务公钥模数 n || cookie)

     随后客户端计算会话密钥,计算过程是首先生成32个字节即256位随机字串,然后用16字节的会话号 xor 这32字的随机字串的前16字节,并安 msb 次序来排列构成一个MP型整数,把结果发给服务器。在用服务器发来主机公钥和服务公钥对这个MP型整数作两次 RSA 加密后,客户端发一个包把这个MP型整数交给服务器。跟随这个包一起还有客户端选定的加密类型。注意,在客户端,它用上面最初的32字节随机串 session_key 来作为会话密钥进行加密,而不是发给服务器的会话密钥 key。

     服务器接到上面MP型整数后,把它转换成32字节即256位的字串。再用自己计算出的16字节的会话号xor 这个字串的前16字节,把结果作为会话密钥。服务器计算自己的16字节会话号时也是把发给客户端的主机公钥、服务公钥、和16字节随机串 cookie 作为输入,因此它计算出的会话号与客户端计算出的一样。

    在这之后,所有的数据传输都用选用客户端指定的加密方法进行加密了,加密时使用上面的会话密钥。

    ssh 声称避免了 IP 欺骗,使用的方法在上面的密钥交换中服务器给客户端发了一个64位 cookie,要求客户端原样拷贝送回。看不出这能避免 IP 欺骗。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics