详解Node.js 中使用 ECDSA 签名遇到的坑


Posted in Javascript onNovember 26, 2018

最近有个朋友问我关于 Node.js 下使用 ECDSA 的问题,主要是使用 Node.js 的 Crypto 模块无法校验网络传输过来的签名结果。在踩坑无数后,终于搞清楚了原因。

坑 0x00:签名输出格式

在排除了证书、消息不一致的可能之后,我开始对比使用 Node.js 签名的结果与网络传输过来的签名,发现长度不一致,大约差了5~7个字节。于是去网上搜索了一下,才知道原来 Node.js (基于 OpenSSL)签名得到的是 DER 格式的内容,而网络上常用的 ECDSA 签名结果是 IEEE P1363 格式的。(也可以写作 R|S)

参考:https://stackoverflow.com/a/39575576

知道问题了就好解决了。但是,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)。

参考:https://stackoverflow.com/a/47099047

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery1.6 使用方法三
Nov 23 Javascript
jquery插件制作 手风琴Panel效果实现
Aug 17 Javascript
jQuery使用before()和after()在元素前后添加内容的方法
Mar 26 Javascript
require.js配合插件text.js实现最简单的单页应用程序
Jul 12 Javascript
jQuery插件ajaxFileUpload使用实例解析
Oct 19 Javascript
vue组件间通信解析
Mar 01 Javascript
vue.js配合$.post从后台获取数据简单demo分享
Aug 11 Javascript
Jquery的Ajax技术使用方法
Jan 21 jQuery
微信小程序实现的一键拨号功能示例
Apr 24 Javascript
基于jQuery实现挂号平台首页源码
Jan 06 jQuery
Node在Controller层进行数据校验的过程详解
Aug 28 Javascript
js面向对象方式实现拖拽效果
Mar 03 Javascript
Vue.js的动态组件模板的实现
Nov 26 #Javascript
解决Vue开发中对话框被遮罩层挡住的问题
Nov 26 #Javascript
Vue项目部署在Spring Boot出现页面空白问题的解决方案
Nov 26 #Javascript
electron制作仿制qq聊天界面的示例代码
Nov 26 #Javascript
Vuex的初探与实战小结
Nov 26 #Javascript
微信小程序页面间值传递的两种方法
Nov 26 #Javascript
Vue中的methods、watch、computed的区别
Nov 26 #Javascript
You might like
回首过去10年中最搞笑的10部动漫,哪一部让你节操尽碎?
2020/03/03 日漫
使用Sphinx对索引进行搜索
2013/06/25 PHP
CentOS 6.3下安装PHP xcache扩展模块笔记
2014/09/10 PHP
PHP简单处理表单输入的特殊字符的方法
2016/02/03 PHP
php微信开发之上传临时素材
2016/06/24 PHP
Laravel框架分页实现方法分析
2018/06/12 PHP
Yii框架where查询用法实例分析
2019/10/22 PHP
javascript代码加载优化方法
2011/01/30 Javascript
情人节之礼 js项链效果
2012/02/13 Javascript
js如何取消事件冒泡
2013/09/23 Javascript
基于MVC4+EasyUI的Web开发框架形成之旅之界面控件的使用
2015/12/16 Javascript
JS原型链怎么理解
2016/06/27 Javascript
JavaScript获取短信验证码(周期性)
2016/12/29 Javascript
详解js中==与===的区别
2017/01/08 Javascript
HTML5实现微信拍摄上传照片功能
2017/04/21 Javascript
jQuery实现简单复制json对象和json对象集合操作示例
2018/07/09 jQuery
javascript实现评分功能
2020/06/24 Javascript
Vue 根据条件判断van-tab的显示方式
2020/08/03 Javascript
[01:10]DOTA2 Supermajor:英雄,由我们见证
2018/05/14 DOTA
python实现从字符串中找出字符1的位置以及个数的方法
2014/08/25 Python
在Python中操作字典之setdefault()方法的使用
2015/05/21 Python
python 协程 gevent原理与用法分析
2019/11/22 Python
对python pandas中 inplace 参数的理解
2020/06/27 Python
Python计算矩阵的和积的实例详解
2020/09/10 Python
python入门教程之基本算术运算符
2020/11/13 Python
One.com挪威:北欧成长最快的网络托管公司
2016/11/19 全球购物
大学中国梦演讲稿
2014/04/23 职场文书
校园元旦活动总结
2014/07/09 职场文书
幼儿园六一活动总结
2014/08/27 职场文书
工程承包协议书范本
2014/09/29 职场文书
初中差生评语
2014/12/29 职场文书
城镇居民医疗保险工作总结
2015/08/10 职场文书
2016国庆节活动宣传语
2015/11/25 职场文书
会计入职心得体会
2016/01/22 职场文书
JavaScript高级程序设计之基本引用类型
2021/11/17 Javascript
使用SQL实现车流量的计算的示例代码
2022/02/28 SQL Server