当我尝试自己实现TLS时,我遇到了这些问题

栏目: IT技术 · 发布时间: 4年前

内容简介:由于我代码使用基于 JVM 的语言写的,所以所有数字类型都是带符号的,也就是 signed 类型。但是 TLS 层的数据都是 unsigned 类型的数字,这就导致数据从 Socket 流走到 JVM 层之后会由于 JVM 的语言没有 unsigned 类型出现数字越界的问题。比如一个 u_char, 值是 128,由于它大于了 127,走到 Java 这边之后,byte 的范围是 -128~127,就会被解析为 -128 。(128=11111111, bit位的首位在 signed 类型时表示符号位,首

由于我代码使用基于 JVM 的语言写的,所以所有数字类型都是带符号的,也就是 signed 类型。但是 TLS 层的数据都是 unsigned 类型的数字,这就导致数据从 Socket 流走到 JVM 层之后会由于 JVM 的语言没有 unsigned 类型出现数字越界的问题。

比如一个 u_char, 值是 128,由于它大于了 127,走到 Java 这边之后,byte 的范围是 -128~127,就会被解析为 -128 。(128=11111111, bit位的首位在 signed 类型时表示符号位,首位为 1 表示这是一个负数,负数在 JVM 中又是以补码形式存储,所以 11111111 转化为原码之后就是 10000000 => 128,加上负数就变成 -128 了)。

由于上面的越界问题,所以从 Socket 中读数据都读出来存为 int,写数据时再转化为 u_char 写入。写入的过程就涉及字节序问题。

就比如发送每条 TLS 消息时,你都需要在消息体外面包裹一层 TLSPlaintText 结构,这个结构中必须写入一个 16 位的数字(length) 去表示数据的大小。16 位的就包含了2个字节,在这2个字节的写入上,我就遇到了问题。

我们知道 OutputStream 提供的 write 接口接收的数据单位是以字节为单位的,现在我想写入2个字节,这2个字节的写入顺序就要受字节序的影响了。

开始我是这样写的:

fun ByteBuffer.putU16(value: Int) = run {
    put((value and 0xFF).toByte())
    put((value shl 8).toByte())
}

因为我们写入时是以32位 int 写的,所以先取低8位写入第一个字节,再把32位数左移8位,剩下的写入第二个字节。这样就把32位数中的16位写入了2个字节中。

当我天真的以为这样就成功时,运行发现 Server 反馈我发送的数据有问题,通过 Wireshark 我发现,wireshark 解析出来的 length 尽然和我写入的length 值不相同。

原因是上面的写入顺序是 litte-endian 的,而网络协议一般都是按照 big-endian 的。

所以需要修改代码为:

fun ByteBuffer.putU16(value: Int) = run {
    put((value shr 8).toByte())
    put((value and 0xFF).toByte())
}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数据结构与算法

数据结构与算法

2008-7 / 29.00元

《21世纪高等院校计算机教材系列·数据结构与算法(第2版)》详细讲述了线性结构、树结构和图结构中的数据表示及数据处理的方法,对查找和排序两种重要的数据处理进行了详细的探讨。一起来看看 《数据结构与算法》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具