首页 > 代码库 > C语言实现的SM2数字签名验证

C语言实现的SM2数字签名验证

    最近在工作中遇到一个需求:签名者使用密码设备(如加密机)生成了一些 SM2 签名,现在用户需要对签名进行验证,可是验签方没有密码设备,验签必须使用软件实现。在 CSDN 上找到了 goldboar 写的 SM2 签名及验签函数(http://download.csdn.net/detail/goldboar/3833072),但是不能直接使用。原因如下:

1) goldboar 的程序是自己生成 SM2 密钥对,用密钥对产生签名再验证签名,而现在需要使用外部传入的公钥、签名来做验签;

2) goldboar 的程序中使用的 ECC 参数是示例参数,不是 GM/T 0003.5-2012 规范中定义的参数;

3) goldboar 的程序是示例程序,没有对动态分配的内存进行仔细地清理,内存泄漏量不少。

 

   在《密码设备应用接口规范》中,对 SM2 公钥的数据结构定义如下:

#define  ECCref_MAX_BITS   512

#define  ECCref_MAX_LEN  ((ECCref_MAX_BITS+7) / 8)

typedef struct ECCrefPublicKey_st

{

   unsigned int  bits;

   unsigned char  x[ECCref_MAX_LEN];

   unsigned char  y[ECCref_MAX_LEN];

} ECCrefPublicKey;

  对 SM2 签名的数据结构定义如下:

typedef struct ECCSignature_st

{

  unsigned char  r[ECCref_MAX_LEN];

  unsigned char  s[ECCref_MAX_LEN];

} ECCSignature;

   可以看出公钥和签名都是以坐标分量的形式给出的。现在已经有以下信息:对原始数据的 SM3 哈希值(已经过预处理,对预处理的介绍可以看 http://blog.csdn.net/henter/article/details/13622601 )、SM2 公钥、SM2 签名,要根据这些信息来验证签名。

  于是在 goldboar 写的 SM2 程序的基础上,改写了一个纯粹用来做 SM2 签名验证的函数,编译时需要用到OpenSSL的头文件和库文件(libeay32.lib或libeay32.dll)。与 goldboar 的程序区别如下:
1) 仅用于做验签,不能签名;
2) 验签使用外部传入的 SM2 公钥,SM2 公钥以 (x,y) 坐标形式传入;
3) 签名也是以 (r,s) 坐标形式传入;
4) 增加了一些内存清理语句,内存泄漏有改善;
5) 验签函数中采用的椭圆曲线参数是规范 GM/T 0003.5-2012 中定义的参数。
6) 将一些对椭圆曲线参数的验证操作放入 _DEBUG 宏限制的范围内。因为参数是规范推荐的,已经过验证,所以在程序中无需再验证。将这些验证语句放入 _DEBUG 宏限制的范围内以后,如果编译 release 版本时就不会包含这些验证语句,效率可以有一点提升。

 

调用OpenSSL的椭圆曲线运算函数以后,总是会有一点内存泄漏,OpenSSL官方对于内存泄漏在网页 http://www.openssl.org/support/faq.html 上是这样解释的:

  I think I‘ve detected a memory leak, is this a bug?
  In most cases the cause of an apparent memory leak is an OpenSSL internal table that is allocated when an application starts up. Since such tables do not grow in size over time they are harmless.
   从中可以看出,只要内存泄漏不随着调用函数次数的增加而增加,就不用担心。于是在 SM2 签名验签函数的基础上又写了一个测试函数,实验后发现如果反复验签多次,与只做一次验签相比,产生的内存泄漏数量没有增长,这就算是可以接受了。

    SM2 签名验签函数的下载网址是:http://download.csdn.net/detail/henter/7637429