详解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 相关文章推荐
js 变量类型转换常用函数与代码[比较全]
Dec 01 Javascript
JavaScript DOM学习第八章 表单错误提示
Feb 19 Javascript
Javascript 面向对象 命名空间
May 13 Javascript
Knockoutjs的环境搭建教程
Nov 26 Javascript
Javascript中常见的校验如域名、手机、邮箱等等
Jan 02 Javascript
PHP开发者必须掌握的6个关键字
Apr 14 Javascript
JavaScript基于ajax编辑信息用法实例
Jul 15 Javascript
详解JavaScript中基于原型prototype的继承特性
May 05 Javascript
js实现搜索栏效果
Nov 16 Javascript
微信小程序页面间传值与页面取值操作实例分析
Apr 30 Javascript
浅谈VUE中演示v-for为什么要加key
Jan 16 Javascript
vue 使用饿了么UI仿写teambition的筛选功能
Mar 01 Vue.js
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
PHP以指定字段为索引返回数据库所取的数据数组
2013/06/30 PHP
phpmyadmin提示The mbstring extension is missing的解决方法
2014/12/17 PHP
php通过asort()给关联数组按照值排序的方法
2015/03/18 PHP
php检查是否是ajax请求的方法
2015/04/16 PHP
学习php设计模式 php实现策略模式(strategy)
2015/12/07 PHP
JavaScript在IE和Firefox(火狐)的不兼容问题解决方法小结
2010/04/13 Javascript
单独使用CKFinder选择图片的方法
2010/08/21 Javascript
javascript学习笔记(十) js对象 继承
2012/06/19 Javascript
jquery $.each() 使用小探
2013/08/23 Javascript
jQuery+css3实现文字跟随鼠标的上下抖动
2015/07/31 Javascript
jQuery unbind 删除绑定事件详解
2016/05/24 Javascript
前端面试题及答案整理(二)
2016/08/26 Javascript
JS制作适用于手机和电脑的通知信息效果
2016/10/28 Javascript
vue-ajax小封装实例
2017/09/18 Javascript
Vue.js实现大转盘抽奖总结及实现思路
2019/10/09 Javascript
详解关闭令人抓狂的ESlint 语法检测配置方法
2019/10/28 Javascript
vue 指令和过滤器的基本使用(品牌管理案例)
2019/11/04 Javascript
nuxt+axios实现打包后动态修改请求地址的方法
2020/04/22 Javascript
基于JavaScript实现简单抽奖功能代码实例
2020/10/20 Javascript
Python笔记(叁)继续学习
2012/10/24 Python
使用Python3中的gettext模块翻译Python源码以支持多语言
2015/03/31 Python
Python使用Matplotlib模块时坐标轴标题中文及各种特殊符号显示方法
2018/05/04 Python
python 数字类型和字符串类型的相互转换实例
2018/07/17 Python
flask 实现token机制的示例代码
2019/11/07 Python
python将数组n等分的实例
2019/12/02 Python
Python 2种方法求某个范围内的所有素数(质数)
2020/01/31 Python
Django自关联实现多级联动查询实例
2020/05/19 Python
Python替换NumPy数组中大于某个值的所有元素实例
2020/06/08 Python
Python中的__init__作用是什么
2020/06/09 Python
New Balance德国官方网站:购买鞋子和服装
2019/08/31 全球购物
财务管理专业毕业生求职信范文
2013/09/21 职场文书
市场安全管理制度
2014/01/26 职场文书
关于国庆节的演讲稿
2014/09/05 职场文书
晚会开幕词
2015/01/28 职场文书
综合素质评价自我评价
2015/03/06 职场文书
初中语文教师研修日志
2015/11/13 职场文书