数字签名
简介
带密钥的消息摘要算法。与手写签名类似,起到了抗否认的作用。手写签名针对纸质文件内容确认,数字签名对数据进行摘要处理。如果经过手写签名的文件被修改,该文件无效。同理,经过数字签名的数据,通过验证签名操作辨别该数据是否被修改。如Windows操作系统的产品密钥
数字签名算法包含了公钥和私钥,是非对称加密算法与消息摘要算法的结合体,近似看成是附加了公钥和私钥的消息摘要算法
发送方将发送的数据进行签名处理,发送携带签名的数据。接受方可以验证该签名与数据是否相符来确认数据完整性 用于签名的相关信息私有,用于验证签名的相关信息公有,且必须成对出现。遵循“私钥签名。公钥验证”的签名/验证方式
数字签名主要包括RSA、DSA和ECDSA算法。RSA源于质因数分解,DSA及ECDSA源于离散对数
RSA
RSA算法不仅是非对称加密算法的经典,也是数字签名算法的经典。
分类:RSA签名长度与密钥长度相同
- MD系列:密钥长度1024
- MD2withRSA
- MD5withRSA
- SHA系列:SHA1密钥1024,其余2048
- SHA1withRSA
- SHA224withRSA
- SHA256withRSA
- SHA384withRSA
- SHA512withRSA
- MD系列:密钥长度1024
代码
- Java API
// 签名 public static byte[] sign(byte[] data, byte[] privateKey) throws Exception { // 将传入私钥转换成可用私钥 PKCS8EncodedKeySpec pkcs8KeysSpec = new PKCS8EncodedKeySpce(privateKey); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); // 密钥是RSA算法的密钥 PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeysSpec); // 签名 Signature signature = Signature.getInstance("MD5withRSA"); // 指明签名算法 signature.initSign(priKey); // 初始化传入私钥 signature.update(data); // 传入待签名数据 return signature.sign(); // 生成并返回签名 } // 验签 public static byte[] verify(byte[] data, byte[] publicKey byte[] sign) throws Exception { // 将传入公钥转换成可用公钥 PKCS8EncodedKeySpec pkcs8KeysSpec = new PKCS8EncodedKeySpce(publicKey); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); // 密钥是RSA算法的密钥 PrivateKey pubKey = keyFactory.generatePrivate(pkcs8KeysSpec); // 验证签名 Signature signature = Signature.getInstance("MD5withRSA"); // 指明签名算法 signature.initSign(pubKey); // 初始化传入公钥 signature.update(data); // 传入签名数据 return signature.verify(); // 返回验证结果布尔值 }
DSA
DSA (Digital Signature Algorithm 数字签名算法) 仅可进行数字签名,使用DSA算法的数字证书无法进行加密通信,而RSA不仅可进行数字签名,还可进行加解密
DSA可认为是RSA的简化版,仅支持SHA系列算法。密钥长度默认1024,范围512 - 1024(64倍数)。签名长度与密钥长度无关
- SHA1withDSA
- SHA224withDSA
- SHA256withDSA
- SHA384withDSA
- SHA512withDSA
实现流程
流程参考wiki-数字签名算法。其中
参数选择
- 选择长度为 N 比特的质数 q (N即为模数长度,q为小素数因子)
- 选择长度为 L 比特的质数 p (L即为密钥长度),使得
,其中 k 为常数。FIPS(联邦信息处理标准) 186-4 规定 (L,N) 必须为 (1024, 160)、(2048, 224)、(2048, 256) 或 (3072, 256) 其中一种 - 从 2 至 p-2 随机选择 h,一般可选 2,在下一步求原根 g 中进行模幂(先进行幂运算后在求模)运算时效率较高
- 计算基数(该基数需要为p的原根)
。若 ,则取 h 为它值进行计算
用户密钥:每个用户独自计算密钥组合
- 选择私钥: 从 1 至 q-2 随机选择私钥 x
- 计算公钥:
,并发布
签名
- 随机选取
, 与 互质 - 计算
,若 ,则取 为它值进行计算 - 计算
,若 ,则取 为它值进行计算。其中 为模反元素, 是待签名内容的散列值 - 签名为
- 随机选取
验签
- 验证
且 - 计算
- 计算
- 计算
- 计算
时,签名有效
- 验证
原理
- 数论基础:费马小定理 - 若
是一整数, 是一质数, 不是 的倍数,则 - 根据签名可知
- 式(1) 两边同乘
- 根据验签可知
- 将计算公钥的公式
代入 式(3) 得到 - 由于
作为 的指数,计算时使用 。因此可将 式(2) 代入 式(4) 对指数进行化简 - 根据验签
,代入 式(5) 得 - 此时 式(6) 与签名时
的定义一致
ECDSA
ECDSA (Elliptic Curve Digital Signature Algorithm 椭圆曲线数字签名算法) 是ECC与DSA的结合。速度快、强度高、签名短。用途有 以太坊数字加密货币,Windows操作系统的产品密钥等
常见ECDSA算法有:NONEwithECDSA、RIPEMD160withECDSA、SHA系列withECDSA
密钥长度
与一般的圆锥曲线算法一致,密钥长度大约为安全等级位数的2倍
涉及到的数学内容
加密中使用的椭圆曲线:
为非标准椭圆圆锥曲线,与椭圆函数 不同(只是与其相关才命名为椭圆曲线),不能互相转换 加法规则
- 封闭性:如果
和 是曲线上的点,其加法定义为 和 所形成的直线,和曲线E交点 的相反点(关于x轴对称点) 即为它们的和,也是曲线上的点 - 求坐标:计算直线斜率
,而后将直线方程代入得到坐标公式
- 求坐标:计算直线斜率
- 存在无穷远点(point at infinity):存在一个特殊的点
,满足 。无穷远点:平行线相交与无穷远点 - 存在逆元素(Inverse element):对于任意曲线上的点
,存在一个点 ,使得 。情况3中的 为 的逆元,即x轴对称点。几何理解:根据加分定义, 与 的连线与对称线平行(重合),交点即为
- 封闭性:如果
标量乘法:在椭圆曲线中,标量乘法
是指将点 与标量 相乘,表示 在曲线上的重复加法,根据封闭性, 结果依然在曲线上 是通过将 与自己加 次得到的 - 如果
,那么 ,即 自身相加三次 - 计算
时反复相加即可
- 如果
- 坐标计算:
时,即倍点。如 情况2 中的 ,切线交点为 ,结果为 。使用求导计算切线斜率 后,将 代入坐标公式即可 - 已知标量
和点 求出 较为简单。已知结果点 和基点 求标量 是难题,即 椭圆曲线离散对数问题。加密中 即为公钥,标量 为私钥
实现流程
公私钥产生
是定义的椭圆曲线 是椭圆曲线上的一个基点(生成元点)。此参数公开 是生成元点 的阶。此参数公开 - 阶:
的最小整数 做标量乘法时不断得到新的点。直到标量为 时结果为无穷远点 - 此时根据公式
,得到 ,即得到了之前得到过的点,由此进入了循环 - 因此,
可以确定 的重复加法生成的点集的大小
- 阶:
- 私钥
是一个随机选择的数,且 - 公钥
是通过 计算得到的(私钥 与生成元点 的乘积)
签名
- 随机选取
生成点集中的一个点 - 随机选择整数
。其中 是临时值,必须保密,且每次签名时都要重新生成,以保证签名的安全性 - 计算点
,得到坐标
- 随机选择整数
- 计算
。 如果 , 重新选点集中的点(重新选择 ) - 计算
. 如果 , 重新选点集中的点(重新选择 )。此处计算消息 的摘要值,并加入私钥 是 的模 的逆元,即满足
- 签名为
- 随机选取
验签
- 判断
与 是否都在 内(由于 ) - 计算
- 计算
- 计算
。如果得到无穷远点,验证失败 - 判断
是否成立。成立则验证成功,否则验证失败
- 判断
原理
- 根据验签时计算出的点
- 根据公钥定义
代入 式(1) - 将
代入 式(2) - 将
的定义 代入 式(3) - 由于
,所以若验签成功时, 即为签名时的 ,即 - 根据
的定义 ,因此