SM2 签名前要进行的预处理操作

2023-05-16

    一般情况下,计算数字签名时应执行以下操作:
1. 计算原始数据的 Hash 值;
2. 将 Hash 值作为输入,计算签名函数的输出。并不是对原始数据直接签名,而是对 Hash 值签名。
    验证签名时应执行以下操作:
1. 计算原始数据的 Hash 值;
2. 将 Hash 值和签名值作为输入,计算验签函数的输出,根据输出判断签名为“有效”或“无效”。
这只是一个简单描述,实际上 PKCS#1 中规定的签名和验签过程要复杂得多。

    计算 SM2 签名和验签的过程有点特殊,因为根据国内的行业标准,SM2 签名算法要和 SM3 Hash 算法搭配使用,并且计算 SM2 签名的输入并不是待签名数据的 SM3 杂凑值,而是一个预处理阶段的输出。
    预处理分为两步:
1. 定义一个级联生成的字节流 T1 = ENTL || ID || a || b || x_G || y_G || x_A || y_A,
   其中 || 表示字节流的拼接,
   ENTL 是用两个字节表示的签名者 ID 的比特长度(注意不是字节长度),
   ID 为签名者的标识,
   a, b, x_G, y_G 都是标准中给定的值, x_A 和 y_A 是签名者的公钥,
   对字节流 T1 计算 SM3 杂凑值,得到的输出为 Z = SM3(T1)。
   这一步并没有用到待签名数据。
2. 将待签名数据用 M 表示,将 Z 与待签名数据级联,得到 T2 = Z || M,计算 T2 的杂凑值,即    SM3(T2),SM3(T2)才是 SM2 签名函数的真正输入。
   注意预处理中用到的数都采用 big-endian 表示法!

    从上面的预处理过程可以看出,当验证签名时,也要经过同样的预处理过程,将预处理阶段的输出、签名值作为验签函数的输入。

    网上有很多 SM3 杂凑算法的开源实现,比如这个网址上提供的:https://github.com/siddontang/pygmcrypto/tree/master/src 。但是一般能找到的 SM3 实现都没有提供预处理功能,所以是不能直接用作计算 SM2 签名和验签的输入。在上面网址提供的 SM3 实现基础上,本文将给出一个预处理的实现。首先从标准中可以查到预处理第 1 步中 a、b、x_G 、 y_G 的值。签名者的公钥通常是以结构体的形式给出的,对于加密机,公钥定义为
typedef struct ECCrefPublicKey_st
{
  unsigned int bits;
  unsigned char x[64];
  unsigned char y[64];
} ECCrefPublicKey;
对于 Ukey,公钥定义为
typedef struct Struct_ECCPUBLICKEYBLOB
{
  ULONG BitLen;
  BYTE XCoordinate[64];
  BYTE YCoordinate[64];
} ECCPUBLICKEYBLOB;
    注意这两个结构体在本质上是一样的。ECCPUBLICKEYBLOB 中出现的 ULONG 并不是 unsigned long,在 Ukey 国内标准中将 ULONG 定义为无符号 32 位整数类型,因此可以把这个 ULONG 看作是 unsigned int。

    由于是结构体,可能会遇到对齐的问题,常见的情况是:硬件厂商在实现接口时是按 1 字节对齐( 即用 #pragma pack (1) 设定),最好看看硬件厂商提供的用户手册核实一下,确保没有问题。本文中假定上面两个结构体都已被设为按 1 字节对齐。
    对于 SM2 算法,公钥的 X 分量和 Y 分量都是 32 字节长,因为以 big-endian 方式存放在对应数组中,对应数组大小为 64 字节,所以数组中前 32 字节的值为 0, 后 32 字节的值对应于分量。这一点在从数组中提取出分量值时要用到。

    下面给出 SM2 签名前的预处理的计算 C 程序:

/************************************************** 
* Author: HAN Wei 
* Author's blog: http://blog.csdn.net/henter/ 
* Date: Oct 30th, 2013 
* Description: the following codes demonstrates how to 
               perform SM3 Hash pre-process for SM2 signature 
**************************************************/ 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sm3.h"

/**************************************************
*函数名称:SM3HashWithPreprocess
*功能: 计算 SM3 杂凑值(可能包含为满足 SM2 签名要求所做的预处理操作)
*参数:
 input[in]                         输入数据
 input_byte_len[in]                输入数据的字节长度
 public_key[in]                    签名者的公钥
 public_key_byte_len[in]           签名者公钥的字节长度
 signer_ID[in]                     签名者的 ID 值
 signer_ID_byte_len[in]            签名者 ID 的字节长度
 hash_value[out]                   SM3 杂凑值
 hash_value_byte_len_pointer[out]  指向表示 SM3 杂凑值字节长度变量的指针
*返回值:
    0    成功
    -1   失败
*备注:
   如果以下四个条件:
   a) 输入参数 public_key 是空指针;
   b) 输入参数 public_key_byte_len 的值等于 0;
   c) 输入参数 signer_ID 是空指针;
   d) 输入参数 signer_ID_byte_len 的值等于 0。
   中有一个成立,就直接计算输入数据 input 的 SM3 杂凑值,
   忽略输入参数 public_key, public_key_byte_len, signer_ID
   和 signer_ID_byte_len,这时不会进行 SM2 算法签名预处理
   操作。
   如果四个条件全部不成立,才执行 SM2 算法签名预处理操作,
   预处理计算过程遵循 GM/T 0009《 SM2 密码使用规范》。
**************************************************/
int SM3HashWithPreprocess(unsigned char *input,
                          unsigned int input_byte_len,
                          unsigned char *public_key,
                          unsigned int public_key_byte_len,
                          unsigned char *signer_ID,
                          unsigned int signer_ID_byte_len,
                          unsigned char *hash_value,
                          unsigned int *hash_value_byte_len_pointer);

/*********************************************************/
int SM3HashWithPreprocess(unsigned char *input,
                          unsigned int input_byte_len,
                          unsigned char *public_key,
                          unsigned int public_key_byte_len,
                          unsigned char *signer_ID,
                          unsigned int signer_ID_byte_len,
                          unsigned char *hash_value,
                          unsigned int *hash_value_byte_len_pointer)
{
  unsigned short ID_bit_len;
  unsigned char *step1_input;
  unsigned int step1_input_byte_len;
  unsigned char step1_output[32];
  unsigned char *step2_input;
  unsigned int step2_input_byte_len;

  unsigned char a[32]={0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                       0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC};
        
  unsigned char b[32]={0x28, 0xE9, 0xFA, 0x9E, 0x9D, 0x9F, 0x5E, 0x34,
                       0x4D, 0x5A, 0x9E, 0x4B, 0xCF, 0x65, 0x09, 0xA7,
                       0xF3, 0x97, 0x89, 0xF5, 0x15, 0xAB, 0x8F, 0x92,
                       0xDD, 0xBC, 0xBD, 0x41, 0x4D, 0x94, 0xE,  0x93};

  unsigned char x_G[32]={0x32, 0xC4, 0xAE, 0x2C, 0x1F, 0x19, 0x81, 0x19,
                         0x5F, 0x99, 0x4,  0x46, 0x6A, 0x39, 0xC9, 0x94,
                         0x8F, 0xE3, 0xB,  0xBF, 0xF2, 0x66, 0xB,  0xE1,
                         0x71, 0x5A, 0x45, 0x89, 0x33, 0x4C, 0x74, 0xC7};

  unsigned char y_G[32]={0xBC, 0x37, 0x36, 0xA2, 0xF4, 0xF6, 0x77, 0x9C,
                         0x59, 0xBD, 0xCE, 0xE3, 0x6B, 0x69, 0x21, 0x53,
                         0xD0, 0xA9, 0x87, 0x7C, 0xC6, 0x2A, 0x47, 0x40,
                         0x2,  0xDF, 0x32, 0xE5, 0x21, 0x39, 0xF0, 0xA0};

// 下面定义的结构体 x 用于判断当前环境是 big-endian 还是 little-endian
  union { int i;
          char c[sizeof(int)];
        } x;

  if ( (!public_key) || (!public_key_byte_len) || (!signer_ID) || (!signer_ID_byte_len) )
  {
    sm3(input, input_byte_len, hash_value);
    *hash_value_byte_len_pointer = 32U;
    return 0;
  }

// 下面为满足 SM2 签名的要求,做预处理操作
  step1_input_byte_len = (2 + signer_ID_byte_len + 32 * 6);
  if ( !(step1_input = (unsigned char *)malloc(step1_input_byte_len)) )
  {
#ifdef _DEBUG
    printf("malloc function failed at %s, line %d!\n", __FILE__, __LINE__);
#endif
    return (-1);
  }
 
/* 预处理1 */
  ID_bit_len = (unsigned short)(signer_ID_byte_len*8);

/* 判断当前环境是 big-endian 还是 little-endian。
   国密规范中要求把 ENTL(用 2 个字节表示的 ID 的比特长度)
   以 big-endian 方式作为预处理 1 输入的前两个字节  */
  x.i = 1;
  if(x.c[0] == 1)  /* little-endian */
  {
    memcpy(step1_input, (unsigned char *)(&ID_bit_len) + 1, 1);
    memcpy((step1_input + 1), (unsigned char *)(&ID_bit_len), 1); 
  }
  else  /* big-endian */
  {
    memcpy(step1_input, (unsigned char *)(&ID_bit_len), 1);
    memcpy((step1_input + 1), (unsigned char *)(&ID_bit_len) + 1, 1);
  }

  memcpy((step1_input + 2), signer_ID, signer_ID_byte_len);
  memcpy((step1_input + 2) + signer_ID_byte_len, a, 32);
  memcpy((step1_input + 2) + signer_ID_byte_len + 32, b, 32);
  memcpy((step1_input + 2 + signer_ID_byte_len + 64), x_G, 32);
  memcpy((step1_input + 2 + signer_ID_byte_len + 96), y_G, 32);
  memcpy((step1_input + 2 + signer_ID_byte_len + 128), (public_key + 4 + 32), 32);
  memcpy((step1_input + 2 + signer_ID_byte_len + 160), (public_key + 4 + 64 + 32), 32);
  sm3(step1_input, step1_input_byte_len, step1_output);

/* 预处理2 */
  step2_input_byte_len = (32 + input_byte_len);
  if ( !(step2_input = (unsigned char *)malloc(step2_input_byte_len)) )
  {
#ifdef _DEBUG
    printf("malloc function failed at %s, line %d!\n", __FILE__, __LINE__);
#endif
    free(step1_input);
    return (-1);
  }
  memcpy(step2_input, step1_output, 32);
  memcpy((step2_input + 32), input, input_byte_len);
  sm3(step2_input, step2_input_byte_len, hash_value);
  *hash_value_byte_len_pointer = 32U;
  
  free(step1_input);
  free(step2_input);
  return 0;
}

     编译时要用到文件 sm3.h 和 sm3.c,这两个文件的下载网址前面已经给出。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SM2 签名前要进行的预处理操作 的相关文章

随机推荐

  • java反射与注解详解,共同实现动态代理模式

    java反射与注解详解 xff0c 共同实现动态代理模式 个人主页 xff1a https blog csdn net hello list id xff1a 学习日记 不知不觉一年过去了 xff0c 整整一年 xff0c 这一年写了60多
  • 微信小程序快速入门

    微信小程序快速入门 在这里首先祝大家国庆节快乐 xff0c 其实原本文章都没有准备好 xff0c 也没有打算更文的 xff0c 那还是将就一下吧 xff0c 发个简单的 前言 相信大家对微信小程序并不陌生 xff0c 以前我们接触网络刚开始
  • RabbitMQ快速入门,这一篇看完教你学会

    RabbitMQ快速入门 今天学习RabbitMQ xff0c 你知道RabbitMQ是什么吗 xff0c RabbitMQ是一种消息中间件 xff0c 我们在写很多业务的时候 xff0c 有时候我们需要考虑到消息的实时性 xff0c 时效
  • 什么是协议栈

    协议栈是什么 1 协议栈是什么 简介 协议栈 xff0c 英语名称为Protocol stack xff0c 又称协议堆叠 xff0c 是计算机网络协议套件的一个具体的软件实现 协议套件中的一个协议通常是只为一个目的而设计的 xff0c 这
  • 任务,任务的切换,(TCB)

    任务也可以称作为进程 xff0c 是一个简单的程序 xff0c 该程序认为 CPU完全属于自己 xff0c 实时的应用的程序的设计的时候分割成了许多的任务 xff0c 每一个任务都对应应用的某一部分 每一个任务都被赋予一定的优先级 xff0
  • 浅谈pthread_setschedparam的使用

    浅谈pthread setschedparam 的使用 int pthread setschedparam pthread t target thread int policy const struct sched param param
  • 互斥量、临界区、信号量、事件标志组和消息邮箱

    http ejs90ejs iteye com blog 1351642 互斥量 临界区 信号量 事件标志组和消息邮箱 2010年07月23日 为了好的理解互斥量 临界区 信号量 事件标志组和消息邮箱 xff0c 下面一些知识对初学者来说很
  • C语言中的多线程简介

    线程 Thread 专业术语称之为程序执行流的最小单元 线程是不会执行程序的 xff0c 可以理解成线程就是一个载体 xff0c 将 要执行的代码 运送到CPU进行处理 多线程就是多个线程同时并发执行 xff08 注意并发与并行的区别 xf
  • Android包管理机制(一) PackageInstaller的初始化

    Android包管理机制 xff08 一 xff09 PackageInstaller的初始化 前言 包管理机制是Android中的重要机制 xff0c 是应用开发和系统开发需要掌握的知识点之一 包指的是Apk jar和so文件等等 xff
  • 无人机与视觉结合项目

    无人机巡航实现火灾检测项目 硬件 xff1a 无人机选用的是匿名科创的无人机 xff0c 是由stm32作为主控 选用jetson nano作为视觉识别的主要处理器 将jetson nano挂载到无人机上 无人机巡航原理 上位机的地图里设置
  • 万里挑一!Intel选中研扬UP Squared Board的理由

    xfeff xfeff 近日 xff0c 研扬携手Intel 全力打造一款 UP SQUARED GROVE 物联网开发套件 作为这款套件的核心 UP UP Squared 来自于工业自动化和智能控制解决方案的主要开发商 研扬科技 工业自动
  • ROS环境下串口通信

    1 环境 xff1a 操作系统 Ubuntu 14 04ROS版本 ROS Indigo 2 步骤 xff1a 2 1 下载安装ROS对应版本的工具包 此处为indigo版 输入以下命令安装 xff1a sudo apt span clas
  • docker的迁移备份

    在工作中 xff0c 有时候可能需要把正在运行的容器 xff0c 迁移到另外一台服务器上 或者需要把某个容器备份 本文档记录docker如何迁移和备份容器 容器保存为镜像 下面是我虚拟机中正在运行的容器 以mynginx容器为例 xff0c
  • 技术面试(一)认识技术面试

    面试这件事听起来似乎挺简单 xff0c 做起来却非常困难 不妨先听听面试官的真实 吐槽 xff1a 是不是拿算法题让候选人做就好了 xff1f 可如果他做过这个题目怎么办 xff1f 候选人都是工作好多年的老司机了 xff0c 怎么有面试官
  • Pix4飞控硬件平台框架(一)

    硬件平台简介 本文只是为了让大家简单入门为主 xff0c 所以我选择的硬件学习平台是Pixhawk系列的mRoPixhawk xff0c 兼容原始版本Pixhawk1 xff0c 基于Pixhawk project FMUv3开源硬件设计
  • Pix4飞控常见问题解决方法(二)

    一 无法解锁 xff08 黄灯闪烁 xff09 无法解锁的原因会有多种 xff0c 请按照如下步骤进行检查 xff1a 1 初始设置是否全部完成 a 机架类型选择是否正确 xff0c 或者你根本就没有选择 xff1f 注意 xff0c 新版
  • 基于libuvc的相机配置说明

    很多相机支持uvc 1 的传输格式 ros官网自带的libuvc xff0c 支持uvc格式的视频流 xff0c 本文主要对这个链接中的一些细节 xff0c 进行补充说明 step 1 插入usb step 2 获取基本信息 查找camer
  • Ehcache依赖版本问题:Another CacheManager with same name 'es' already exists in the same VM.

    最近在写一个shiro 的demo用到Ehcache缓存配置 结果在启动项目的时候出错 span style font size 14px Caused by net sf ehcache CacheException Another Ca
  • ubuntu 创建新用户并添加到docker组

    useradd myuser passwd myuser first create the directory mkdir p home myuser usermod s bin bash d home myuser myuser cp r
  • SM2 签名前要进行的预处理操作

    一般情况下 xff0c 计算数字签名时应执行以下操作 xff1a 1 计算原始数据的 Hash 值 xff1b 2 将 Hash 值作为输入 xff0c 计算签名函数的输出 并不是对原始数据直接签名 xff0c 而是对 Hash 值签名 验