当我尝试自己实现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())
}

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

查看所有标签

猜你喜欢:

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

HTML 5实战

HTML 5实战

陶国荣 / 机械工业出版社 / 2011-11 / 59.00元

陶国荣编著的《HTML5实战》是一本系统而全面的HTML 5教程,根据HTML 5标准的最新草案,系统地对HTML 5的所有重要知识点进行了全面的讲解。在写作方式上,本书以一种开创性的方式使理论与实践达到极好的平衡,不仅对理论知识进行了清晰而透彻的阐述,而且根据读者理解这些知识的需要,精心设计了106个完整(每个案例分为功能描述、实现代码、效果展示和代码分析4个部分)的实战案例,旨在帮助读者通过实......一起来看看 《HTML 5实战》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试