数字签名(又称公钥数字签名)是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。它是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术来实现的,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。数字签名是非对称密钥加密技术与数字摘要技术的应用。
不论采取何种算法进行数字签名,其流程都是差不多的,先说一说签名流程:
签名流程
再来说一说签名验证流程:
验签流程
请注意,上面的流程并不是对消息本身签名,而是对消息的摘要值进行签名,这是因为非对称加密算法通常比较慢,而且校验摘要值可以保证消息没有篡改。不论消息有多长,在某种摘要算法下,其摘要值的长度是固定的,对其进行签名速度较快,也比较容易处理。
目前主流的签名算法有RSA数字签名算法和DSA数字签名算法。RSA数字签名算法和RSA加密算法相似,不同的是,RSA加密算法是公钥加密,私钥解密,而RSA签名算法是私钥签名,公钥验证签名。DSA(Digital Signature Algorithm)数字签名算法生成签名、验证签名的机制和RSA数字签名算法是一样的。这里不详细展开,这些算法都比较成熟,有丰富的资料可参考,一般网络库也都有实现,有兴趣的朋友自行搜索。
DSA算法结合ECC,称为ECDSA数字签名算法。在前面的文章我说过,SM2实际上就是一种椭圆曲线(EC)密码算法,所以这里先详细说说标准的ECDSA算法,然后再说说SM2数字签名算法和ECDSA算法有哪些差别。
在《 解读国密非对称加密算法SM2 》一文中,我们已经知道,对于椭圆曲线密码算法而言,最重要的是选择一条命名曲线,包括几个重要的参数:p、a、b、G(x,y)和n。而在ECDSA算法中,有三个参数很重要:
在《 详解国密SM2的加密和解密 》一文中,我们已经谈过密钥对的生成,这里再重复一下:
签名生成:
下面的步骤中,M是消息,HASH(M)是对消息进行摘要运算。d为私钥,P为公钥。
详细过程请参考 ANSI X9.62 这份文档(收费文档),上面步骤略去了几个运算值结果检查,另外需要注意上面的运算是大数运算,请不要使用普通的算术运算。
验证签名:
如果从头实现上面的运算,确实不太容易,因为ECDSA已经相当成熟,所以现在的网络库基本上都有实现。在现有的ECDSA算法基础上修改,增加对SM2签名算法的支持,相对比较容易,下面就说说SM2数字签名算法。
SM2数字签名算法在《GMT 0003.2-2012 SM2椭圆曲线公钥密码算法第2部分:数字签名算法》这份文档中有详细的描述。其中签名的流程为:
SM2签名流程
从中我们可以看到和标准ECDSA的流程有几点不同:
虽然SM2数字签名算法的计算步骤有所差别,但ECDSA中的基本运算,比如大数的加减乘除、曲线的乘积、取模运算都可以重用,所以实现起来也不是很困难。
验证签名的流程:
如果实现了签名流程,验证签名的流程也比较容易实现,主要是需要关注其中的公式,注意一些细节。
在开发SM2数字签名算法时,我们可以参考附录A中的示例,保证每个步骤的数据能对上,这样最终的结果就不会出错。
本文主要阐述了SM2数字签名算法,它并不神秘,如果参考着ECDSA来实现,从技术角度讲并不是很复杂。虽然数字签名算法可以用来防抵赖、防篡改,但还有一个问题没解决,客户端如何确保接收到的服务器公钥不是伪造的?举个例子,假如某个服务器声称自己是腾讯公司的服务器,发给你公钥,你用该公钥进行数字签名验证,可以通过,但实际上这个服务器是一个山寨版。这个时候必须要借助数字证书,才能解决这样的安全问题。