Node.js 中使用 ECDSA 签名遇到的坑
文/Fenying
最近有个朋友问我关于 Node.js 下使用 ECDSA 的问题,主要是使用 Node.js 的 Crypto 模块无法校验网络传输过来的签名结果。在踩坑无数后,终于搞清楚了原因。
坑 0x00:签名输出格式
在排除了证书、消息不一致的可能之后,我开始对比使用 Node.js 签名的结果与网络传输过来的签名,发现长度不一致,大约差了5~7个字节。于是去网上搜索了一下,才知道原来 Node.js (基于 OpenSSL)签名得到的是 DER 格式的内容,而网络上常用的 ECDSA 签名结果是 IEEE P1363 格式的。(也可以写作 R|S)
知道问题了就好解决了。但是,DER 和 IEEE P1363 两个格式互转也不是那么容易的。
简单科普一下,ECDSA 是指基于 ECC 椭圆加密算法的签名方式,签名结果是两个整数 R 和 S。 R 和 S 一般长度相同,或者接近。如果长度不同,在各自前面补字节 0x00 直到等长。把 R 和 S 以大头字节序表示,然后依次前后拼接,就是所谓 IEEE P1363 格式。
坑 0x01:DER 的整数问题
先来了解一下 ECDSA 的 DER 输出格式,大概如下:
SEQUENCE <LENGTH> INTEGER <INTEGER_LENGTH> <INTEGER_VALUE...> # 整数 R INTEGER <INTEGER_LENGTH> <INTEGER_VALUE...> # 整数 S
其中
-
SEQUENCE
是 DER 数组(串?)标头,用一个字节 0x30 表示 -
<LENGTH>
是 SEQUENCE 的长度,用一个字节表示,不包括标头和这个长度本身 -
INTEGER
是整数标头,用一个字节 0x02 表示 -
<INTEGER_LENGTH>
是整数的字节长度,用一个字节表示。 -
<INTEGER_VALUE>
是整数的内容,以大头字节序表示。
另一个坑我也已经写出来了,不知道有人发现没有?没想到的话,继续往下。
IEEE P1363 格式下,R 和 S 都是等长的。所以只要把 IEEE P1363 格式的签名从中间切分就可以得到 R 和 S 的内容了。而且 IEEE P1363 格式下,R 和 S 也是以大头字节序表示的,因此没有字节序转换问题了。现在,只需要按上面的格式构造一个 DER 即可。
坑 0x01.0:缺少整数前置字节 0x00
我第一次尝试将 IEEE P1363 格式的签名转换成 DER 格式,并没有失败,但是当我换一个签名结果,却失败了……我对比了 DER 和 IEEE P1363 的区别,发现了一个特点,在 DER 格式下,R 和 S 偶尔会有前置字节 0x00,但不是一定的。
查资料后才明白,DER 下没有“无符号整数”之说,也就是说整数都是有符号的。如果 INTEGER 所表示的整数最高字节大于 0x7F,也就是最高位(符号位)为 1,则表示负数。如果要表示正数,必须在前面补一个字节 0x00……
参考 https://bitcointalk.org/index.php?topic=215205.msg2258789#msg2258789
坑 0x01.1:多余的整数前置字节 0x00
在我修改代码后,虽然提高了成功率,可仍然有失败的情况,仔细看了下,原来是因为 IEEE P1363 格式里,R 和 S 可能被补了不止 1 个字节 0x00……
而 DER 下虽然要求补字节 0x00,却是有且只能有一个字节 0x00。
到此,问题都解决了——直到我测试了 521-bit (是的,你没看错,不是 512) 长度的密钥时,完全失败,毫无例外。
坑 0x02:DER SEQUENCE 的长度超过 0x7F
前面说了,<LENGTH>
只能用一个字节表示,这是一个整数,前文我提到的整数正负问题,这里也存在!
即是说,ECDSA 签名使用 DER 输出格式时,如果使用 521-bit (是的,你没看错,不是 512) 长度的密钥时,DER的长度将超出 0x7F,使得 <LENGTH>
变成了负数!
而解决方案不是补字节 0x00,而是用字节 0x81 填充 <LENGTH>
,再在下一个字节用一个无符号整数的表示长度(0 ~ 255)。
(全文完)

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Centos7 Python3.7 执行 RPi.GPIO
一、GPIO介绍 图中箭头所指,焊脚是4方的,表明是物理引脚1。 二、测试硬件连接是否可以 物理引脚1是3.3v电压(火线),39好引脚是GND(零线),连接电阻和二极管,应该是常亮的,如下图连接: 图中:三个电阻,每个是100欧,串联为300欧。二极发光管有正负极之分,长脚为正极,断脚为负极。 三、软件测试(前提已经安装RPi.GPIO) 1.硬件连接图如下:39号引脚和7号引脚(与1好引脚在同一列,第4排) 2.软件控制: 执行如下命令: sudo /usr/local/python371/bin/ipython 输入如下代码: import RPi.GPIO as GPIO GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(4,GPIO.OUT) GPIO.output(4,GPIO.HIGH) # GPIO.output(4,GPIO.LOW) ## 最后执行,将电压降下来 3.效果图如下: 四、遇到的问题: 如果不使用sudo或使用root用户执行,会报错,显示如下: In [4]: GPI...
- 下一篇
(译)React hooks:它不是一种魔法,只是一个数组——使用图表揭秘提案规则
原文地址:https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e 译文:染陌 (Github) 译文地址:https://github.com/answershuto/Blog 转载请著名出处 我是一名hooks API的忠实粉丝,然而它对你的使用会有一些奇怪的约束,所以我在本文中使用一个模型来把原理展示给那些想去使用新的API却难以理解它的规则的人。 警告:Hooks 还处于实验阶段 本文提到的 Hooks API 还处于实验阶段,如果你需要的是稳定的 React API 文档,可以从这里找到。 解密 Hooks 的工作方式 我发现一些同学苦苦思索新的 Hooks API 中的“魔法”,所以我打算尝试着去解释一下,至少从表层出发,它是如何工作的。 Hooks 的规则 React 核心团队在Hooks的提案中提出了两个在你使用Hooks的过程中必须去遵守的主要规则。 请不要在循环、条件或者嵌套函数中调用 Hooks 都有在 React 函数中才去调用 Hooks 后者我觉得是显而易见的,你需...
相关文章
文章评论
共有0条评论来说两句吧...