实验一-密码引擎-加密API实现与测试

1 下载并查找GMT 0018-2012密码设备应用接口规范原始文档进行学习 (5分)
2 实现GMT 0018-2012密码设备应用接口规范的接口函数,至少实现:
1)设备管理中的打开设备,关闭设备,获取设备信息,产生随机数(4分)
2)密钥管理导出 ECC 签名公钥;SDF_ExportSignPublicKey_ECC I.导出 ECC加密公钥∶SDF_ExportEncPublicKey_ECC J. 产生 ECC非对称密钥对并输出∶SDF_GenerateKeyPair_ECC
K. (6分)
3)非对称算法(至少支持SM2):外部密钥 ECC验证∶SDF_ExternalVerify_ECC ,内部密钥 ECC签名;SDF_InternalSign_ECC ,内部密钥 ECC验证∶SDF_InternalVerify_ECC  外部密钥 ECC加密∶SDF_ExternalEncrypt_ECC
(8分)
4)对称算法(至少支持SM4)∶SDF_Encrypt  对称解密∶SDF_Dccrypt 计算 MAC∶SDF_CalculateMAC(6分)
5)杂凑算法(至少支持SM3):· 杂凑运算初始化∶SDF_HashInit· 多包杂凑运算∶SDF_HashUpdate· 杂凑运算结束∶SDF_HashFinal(6分)

密钥管理要求(10分)
基于本标准设计、开发的密码设备在密钥管理方面,应满足以下要求; 1)设备密钥的使用不对应用系统开放; 2) 密钥必须用安全的方法产生并存储;
3) 在任何时间、任何情况下,除公钥外的密钥均不能以明文形式出现在密码设备外; 4) 密码设备内部存储的密钥应具备有效的密钥保护机制,防止解剖、探测和非法读取; 5) 密码设备内部存储的密钥应具备权限控制机制,防止非法使用和导出。

设备状态要求(5分)
基于本标准设计、开发的密码设备在设备状态方面,应满足以下要求; 1) 密码设备应具有初始和就绪两个状态;
2) 未安装设备密钥的密码设备应处干初始状态,已安装设备密钥的密码设备应处于就绪状态; 3) 在初始状态下,除可读取设备信息、设备密钥的生成或恢复操作外,不能执行任何操作,生成或恢复设备密钥后,密码设备处于就绪状态;
4) 在就绪状态下,除设备密钥的生成或恢复操作外,应能执行任何操作; 5) 在就绪状态下进行的密钥操作,设备操作员应经过密码设备的认证。


1.下载并查找GMT 0018-2012密码设备应用接口规范原始文档进行学习

 

设备管理类函数

  1. 打开设备:SDF_OpenDevice
  2. 关闭设备:SDF_CloseDevice
  3. 创建会话:SDF_OpenSession
  4. 关闭会话:SDF_CloseSession
  5. 获取设备信息:SDF_GetDeviceInfo
  6. 产生随机数:SDF_GenerateRandom
  7. 获取私钥使用权限:SDF_GetPrivateKeyAccessRight
  8. 释放私钥使用权限:SDF_ReleasePrivateKeyAccessRight

密钥管理类函数

  1. 导出 RSA 签名公钥:SDF_ExportSignPublicKey_RSA
  2. 导出 RSA 加密公钥:SDF_ExportEncPublicKey_RSA
  3. 产生RSA非对称密钥对并输出:SDF_GenerateKeyPair_RSA
  4. 生成会话密钥并用内部RSA公钥加密输出:SDF_GenerateKeyWithIPK_RSA
  5. 生成会话密钥并用外部RSA公钥加密输出:SDF_GenerateKeyWithEPK_RSA
  6. 导人会话密钥并用内部RSA私钥解密:SDF_ImportKeyWithISK_RSA
  7. 基于 RSA 算法的数宇信封转换:SDF_ExchangeDigitEnvelopeBaseOnRSA
  8. 导出 ECC 签名公钥:SDF_ExportSignPublicKey_ECC
  9. 导出 ECC 加密公钥:SDF_ExportEncPublicKey_ECC
  10. 产生ECC非对称密钥对并输出:SDF_GenerateKeyPair_ECC
  11. 生成会话密钥并用内部ECC公钥加密输岀:SDF_GenerateKeyWithIPK_ECC
  12. 生成会话密钥并用外部ECC公钥加密输出:SDF_GenerateKeyWithEPK_ECC
  13. 导入会话密钥并用内部ECC私钥解密:SDFJmportKeyWithlSKJECC
  14. 生成密钥协商参数并输出:SDF_GenerateAgreementDataWithECC
  15. 计算会话密钥:SDF_GenerateKey WithECC
  16. 产生协商数据并计算会话密钥:SDF_GenerateAgreementDataAndKeyWithECC
  17. 基于 ECC算法的数字信封转换:SDF_ExchangeDigitEnvelopeBaseOnECC
  18. 生成会话密钥并用密钥加密密钥加密输出: SDF_GenerateKeyWithKEK
  19. 导入会话密钥并用密钥加密密钥解密:SDF_ImportKeyWithKEK
  20. 销毁会话密钥:SDF_DestroyKey

非对称算法运算类函数

  1. 外部公钥 RSA 运算:SDF_ExternalPublicKeyOperation_RSA
  2. 内部公钥 RSA 运算:SDF_InternalPublicKeyOperation_RSA
  3. 内部私钥 RSA 运算:SDF_InternalPrivateKeyOperation_RSA
  4. 外部密钥 ECC 验证:SDF_ExternalVerify_ECC
  5. 内部密钥 ECC 签名:SDF_InternalSign_ECC
  6. 内部密钥 ECC 验证:SDF_InternalVerify_ECC
  7. 外部密钥 ECC 加密:SDF_ExternalEncrypt_ECC

对称算法运算类函数

  1. 对称加密:SDF_Encrypt
  2. 对称解密:SDF_Decrypt
  3. 计算MAC:SDF_CalculateMAC

杂凑运算类函数

  1. 杂凑运算初始化:SDF_HashInit
  2. 多包杂凑运算:SDF_HashUpdate
  3. 杂凑运算结束:SDF_HashFinal

 2.实现GMT 0018-2012密码设备应用接口规范的接口函数

 打开设备

原型:int SDF_OpenDevice(void ** phDeviceHandle);

功能:打开密码设备

参数:phDeviceHandle[out] 返回设备句柄

返回值:0 成功

      非0 失败,返回错误代码

 

关闭设备

原型:int SDF_CloseDevice(void * hDeviceHandle);

功能:关闭密码设备,并释放相关资源

参数:hDeviceHandle[in] 已打开的设备句柄

返回值:0 成功

        非0 失败,返回错误代码

 

获取设备信息

原型:int SDF_GetDeviceInfo(void * hSessionHandle,DEVICEINFO * pstDeviceInfo);

功能:获取设备信息

参数:hSessionHandle[in] 与设备建立的会话句柄

      pstDeviceInfo[out] 设备能力描述信息,内容及格式见设备信息定义

返回值:0 成功

        非0 失败,返回错误代码

 

产生随机数

原型:int SDF_GenerateRandom (void * hSessionHandle, unsigned 
int uiLength,unsigned char * pucRandom);

功能:获取指定长度的随机数

参数:hSessionHandle[in] 与设备建立的会话句柄

      uiLength[in]       欲获取的随机数长度

      pucRandom[out]     缓冲区指针,用于存放获取的随机数

返回值:0 成功

        非0 失败,返回错误代码

 

产生ECC密钥对并输出

原型:int SDF_GenerateKeyPair_ECC( void * hSessionHandle,unsigned int uiAlgID,unsigned int uiKeyBits, 
ECCrefPublicKey * pucPublicKey,ECCrefPrivateKey * pucPrivateKey); 功能:请求密码设备产生指定类型和模长的ECC密钥对 参数:hSessionHandle[in] 与设备建立的会话句柄 uiAlgID[in] 指定算法标识 uiKeyBits[in] 指定密钥长度 pucPublicKey[out] ECC公钥结构 pucPrivateKey[out] ECC私钥结构 返回值:0 成功 非0 失败,返回错误代码

 

使用外部ECC公钥对ECC签名值进行验证运算

原型:int SDF_ExternalVerify_ECC(void * hSessionHandle,unsigned int uiAlgID,ECCrefPublicKey * pucPublicKey, 
unsigned char * pucDataInput, unsigned int uiInputLength, ECCSignature * pucSignature); 功能:使用外部ECC公钥对ECC签名值进行验证运算 参数:hSessionHandle[in] 与设备建立的会话句柄 uiAlgID[in] 算法标识,指定使用的ECC算法 pucPublicKey[in] 外部ECC公钥结构 pucData[in] 缓冲区指针,用于存放外部输入的数据 uiDataLength[in] 输入的数据长度 pucSignature[in] 缓冲区指针,用于存放输入的签名值数据 返回值:0 成功 非0 失败,返回错误代码 备注:输入数据为待签数据的杂凑值。当使用SM2算法时,该输入数据为待签数据经过SM2签名预处理的结果,预处理过程见GM/T 0009

 

使用内部ECC私钥对数据进行签名运算

 

原型:int SDFInternalSign_ECC(void * hSessionHandle, unsigned int uiISKIndex, unsigned char * pucData,
unsigned int uiDataLength, ECCSignature * pucSignature); 功能:使用内部ECC私钥对数据进行签名运算 参数:hSessionHandle[in] 与设备建立的会话句柄 uiISKIndex[in] 密码设备内部存储的ECC签名私钥的索引值 pucData[in] 缓冲区指针,用于存放外部输入的数据 uiDataLength[in] 输入的数据长度 pucSignature[out] 缓冲区指针,用于存放输入的签名值数据 返回值:0 成功 非0 失败,返回错误代码 备注:输入数据为待签数据的杂凑值。当使用SM2算法时,该输入数据为待签数据经过SM2签名预处理的结果,预处理过程见GM/T 0009

 

使用内部ECC公钥对ECC签名值进行验证运算

 

原型:int SDF_InternalVerify_ECC(void * hSessionHandle,unsigned int uiISKIndex,unsigned char * pucData,
unsigned int uiDataLength, ECCSignature * pucSignature); 功能:使用内部ECC公钥对ECC签名值进行验证运算 参数:hSessionHandle[in] 与设备建立的会话句柄 uiISKIndex[in] 密码设备内部存储的ECC签名私钥的索引值 pucData[in] 缓冲区指针,用于存放外部输入的数据 uiDataLength[in] 输入的数据长度 pucSignature[out] 缓冲区指针,用于存放输入的签名值数据 返回值:0 成功 非0 失败,返回错误代码 备注:输入数据为待签数据的杂凑值。当使用SM2算法时,该输入数据为待签数据经过SM2签名预处理的结果,预处理过程见GM/T 0009

 

使用外部ECC公钥对数据进行加密运算

原型:int SDF_ExternalEncrypt_ECC(void * hSessionHandle, unsigned int uiAlgID,
ECCrefPublicKey * pucPublicKey, unsigned char * pucData, unsigned int uiDataLength, ECCCipher * pucEncData); 功能:使用外部ECC公钥对数据进行加密运算 参数:hSessionHandle[in] 与设备建立的会话句柄 uiAlgID[in] 算法标识,指定使用的ECC算法 pucPublicKey[in] 外部ECC公钥结构 pucData[in] 缓冲区指针,用于存放外部输入的数据 uiDataLength[in] 输入的数据长度 pucEncData[out] 缓冲区指针,用于存放输出的数据密文 返回值:0 成功 非0 失败,返回错误代码

 

使用指定的密钥句柄和IV对数据进行对称加密运算

原型:int SDF_Encrypt(void * hSessionHandle,void * hKeyHandle,unsigned int uiAlgID, unsigned char * pucIV, 
unsigned char * pucData, unsigned int uiDataLength , unsigned char * pucEncData,unsigned int * puiEncDataLength); 功能:使用指定的密钥句柄和IV对数据进行对称加密运算 参数:hSessionHandle[in] 与设备建立的会话句柄 hKeyHandle[in] 指定的密钥句柄 uiAlgID[in] 算法标识,指定对称加密算法 pucIV[in|out] 缓冲区指针,用于存放输入和返回的IV数据 pucData[in] 缓冲区指针,用于存放输入的数据明文 uiDataLength[in] 输入的数据明文长度 pucEncData[out] 缓冲区指针,用于存放输出的数据密文 puiEncDataLength[out] 输出的数据密文长度 返回值:0 成功 非0 失败,返回错误代码 备注:此函数不对数据进行填充处理,输入的数据必须是指定算法分组长度的整数倍

 

使用指定的密钥句柄和IV对数据进行对称解密运算

原型:int SDF_Decrypt (void * hSessionHandle, void * hKeyHandle, unsigned int uiAlgID, unsigned char * pucIV,
unsigned char * pucEncData, unsigned int uiEncDataLength, unsigned char * pucData, unsigned int * puiDataLength); 功能:使用指定的密钥句柄和IV对数据进行对称解密运算 参数:hSessionHandle[in] 与设备建立的会话句柄 hKeyHandle[in] 指定的密钥句柄 uiAlgID[in] 算法标识,指定对称加密算法 pucIV[in|out] 缓冲区指针,用于存放输入和返回的IV数据 pucEncData[in] 缓冲区指针,用于存放输入的数据明文 uiEncDataLength[in] 输入的数据明文长度 pucData[out] 缓冲区指针,用于存放输出的数据密文 puiDataLength[out] 输出的数据密文长度 返回值:0 成功 非0 失败,返回错误代码 备注:此函数不对数据进行填充处理,输入的数据必须是指定算法分组长度的整数倍

 

使用指定的密钥句柄和IV对数据进行MAC运算

原型:int SDF_CalculateMAC(void * hSessionHandle,void * hKeyHandle, unsigned int uiAlgID, unsigned char * pucIV, 
unsigned char * pucData, unsigned int uiDataLength ,unsigned char * pucMAC, unsigned int * puiMACLength); 功能:使用指定的密钥句柄和IV对数据进行MAC运算 参数:hSessionHandle[in] 与设备建立的会话句柄 hKeyHandle[in] 指定的密钥句柄 uiAlgID[in] 算法标识,指定对称加密算法 pucIV[in|out] 缓冲区指针,用于存放输入和返回的IV数据 pucData[in] 缓冲区指针,用于存放输出的数据明文 uiDataLength[in] 输入的数据明文长度 pucMAC[out] 缓冲区指针,用于存放输出的MAC值 puiMACLength[out] 输出的MAC值长度 返回值:0 成功 非0 失败,返回错误代码 备注:此函数不对数据进行分包处理,多包数据MAC运算由IV控制最后的MAC值

 

杂凑运算初始化

原型:int SDF_HashInit(void * hSession Handle, unsigned int uiAlgID,ECCrefPublicKey * pucPublicKey,unsigned char * pucID, unsigned int uiIDLength);

功能:三步式数据杂凑运算第一步,杂凑运算初始化

参数:hSessionHandle[in] 与设备建立的会话句柄

      uiAlgID[in]        指定杂凑算法标识

      pucPublicKey[in]   签名者公钥。当uiAlgID为SGD_SM3时有效。

      pucID[in]          签名者的ID值,当uiAlgID为SGD_SM3时有效。

      uiIDLength[in]     签名者ID的长度,当uiAlgID为SGD.SM3时有效。

返回值:0 成功

        非0 失败,返回错误代码

备注:uiIDLength非零且uiAlgID为SGD_SM3时,函数执行SM2的预处理1操作。计算过程见GM/T 0009

 

多包杂凑运算

原型:int SDF_HashUpdate(void * hSessionHandle,unsigned char * pucData,unsigned int uiDataLength);

功能:三步式数据杂凑运算第二步,对输入的明文进行杂凑运算

参数:hSessionHandle[in] 与设备建立的会话句柄

      pucData[in]        缓冲区指针,用于存放输入的数据明文

      uiDataLength[in]   输入的数据明文长度

返回值:0 成功

        非0 失败,返回错误代码

 

杂凑运算结束

原型:int SDF_HashFinal (void * hSessionHandle,unsigned char * pucHash,unsigned int * puiHashLength);

功能:三步式数据杂凑运算第三步,杂凑运算结束返回杂凑数据并清除中间数据

参数:hSessionHandle[in] 与设备建立的会话句柄

      pucHash[out]       缓冲区指针,用于存放输出的杂凑数据

      puiHashLength[out] 返回的杂凑数据长度

返回值:0 成功

        非0 失败,返回错误代码

 

实践过程

sdf.h

#ifndef _SDF_H
#define _SDF_H //定义设备信息结构 typedef struct DeviceInfo_st{ unsigned char IssuerName[40]; //设备生产商名称 unsigned char DeviceName[16]; unsigned char DeviceSerial[16]; unsigned int DeviceVersion; unsigned int StandardVersion; unsigned int AsymAlgAbility[2]; unsigned int SymAlgAbility; unsigned int HashAlgAbility; unsigned int BufferSize; }DEVICEINFO; //Error Code #define SDF_OK 0x0 //操作成功 #define SDR_BASE 0x01000000 //错误码基础值 #define SDR_UNKNOWERR SDR_BASE+0x00000001 //未知错误 #define SDR_NOTSUPPORT SDR_BASE+0x00000002 //不支持的接口调用 #define SDR_COMMFAIL SDR_BASE +0x00000003 //与设备通信失败 #define SDR_HARDFAIL SDR_BASE+ 0x00000004 //运算模块无响应 #define SDR_OPENDEVICE SDR_BASE+0x00000005 //打开设备失败 #define SDR_OPENSESSION SDR_BASE + 0x00000006 //创建会话失败 #define SDR_PARDENY SDR_BASE +0x00000007 //无私钥使用权限 #define SDR_KEYNOTEXIST SDR_ BASE+0x00000008 //不存在的密钥调用 #define SDR_ALGNOTSUPPORT SDR_BASE + 0x00000009 //不支持的算法调用 #define SDR_ALGMODNOTSUPPORT SDR_BASE+ 0x0000000A //不支持的算法模式调用 #define SDR_PKOPERR SDR_BASE+ 0x0000000B //公钥运算失败 #define SDR_SK OPERR SDR_BASE + 0x0000000C //私钥运算失败 #define SDR_SIGNERR SDR _BASE+0x0000000D //签名运算失败 #define SDR_VERIFYERR SDR_BASE +0x0000000E //验证签名失败 #define SDR_SYMOPERR SDR_BASE+ 0x0000000F //对称算法运算失败 #define SDR_STEPERR SDR_BASE+0x00000010 //多步运算步骤锗误 #define SDR_FILES1ZEERR SDR_BASE+0x00000011 //文件长度超出限制 #define SDR_FILENOEXIST SDR_BASE+0x00000012 //指定的文件不存在 #define SDR_FILEOFSERR SDR_BASE+0x00000013 //文件起始位置错误 #define SDR_KEYTYPEERR SDR_BASE+0x00000014 //密钥类型缙误 #define SDR_KEYERR SDR_BASE+0x00000015 //密钥缙误 #define SDR_ENCDATAERR SDR_BA3E+0x00000016 //ECC加密数据错误 #define SDR_RANDERR SDR_BASE+0x00000017 //随机数产生失败 #define SDR_PRKRERR SDR_BASE+0x00000018 //私钥使用权限获取失败 #define SDR_MACFRR SDR_BASE+0x00000019 //MAC运算失败 #define SDR_FILEEXISTS SDR_BASE+ 0x0000001A //指定文件已存在 #define SDR_FILEWERR SDR_BASE+0x0000001B //文件写入失败 #define SDR_NORUFFER SDR_BASE+0x0000001c //存储空间不足 #define SDR_INARGERR SDR_BASE+0x0000001D //输入参数错误 #define SDR_OUTARGERR SDR_BASE +0x0000001E //输出参数错误 //设备管理 /* 功能:打开密码设备 参数: phDeviceHandle[out]返回设备句柄 返回值: 0 成功 非0 失败,返回错误代码 备注: phDeviceHandle由函数初始化并填写内容 */ int SDF_OpenDevice(void ** phDeviceHandle); /* 功能:关闭密码设备,并释放相关资源。 参数: hDeviceHandle[in] 已打开的设备句柄 返回值: 0 成功 非0 失败,返回错误代码 */ int SDF_CloseDevice( void * hDeviceHandle); /* 功能:获取密码设备能力描述。 参数: hSessionHandle[in] 与设备建立的会话句柄 pstDeviceInfo [out] 设备能力描述信息,内容及格式见设备信息定义 返回值: 0 成功 非0 失败,返回错误代码 */ int SDF_GetDeviceInfo( void * hSessionHandle, DEVICEINFO * pstDeviceInfo); /* 功能:获取指定长度的随机数。 参数:hSessionHandle[in] 与设备建立的会话句柄 uilength[in] 欲获取的随机数长度 pucRandom[out] 缓冲区指针,用于存放获取的随机数 返回值: 0 成功 非0 失败,返回错误代码 */ int SDF_GenerateRandom ( void * hSessionHandle,unsigned int uiLength, unsigned char * pucRandom); #endif

 

sdf.c

#include<stdio.h> # include <stdlib.h> #include<string.h> #include "sdf.h" #include<time.h> #include <openssl/bn.h> int SDF_OpenDevice( void ** phDeviceHandle) { return SDF_OK; } int SDF_CloseDevice( void * hDeviceHandle) { return SDF_OK; } int SDF_GetDeviceInfo(void * hSessionHandle,DEVICEINFO * pstDeviceInfo) { DEVICEINFO di; strcpy(di.IssuerName,"tzjSDF"); strcpy(di.DeviceName,"SDFtzj20191202"); strcpy(di.DeviceSerial,"20220428"); di.DeviceVersion=1; (*pstDeviceInfo)= di; return SDF_OK; } int SDF_GenerateRandom (void * hSessionHandle,unsigned int uiLength,unsigned char * pucRandom) { BIGNUM *bn; int i; bn = BN_new(); //生成一个BIGNUM结构 //int bits = 20; int top = -1; int bottom = 1; BN_rand(bn, uiLength, top, bottom); //生成指定bits的随机数 char *a = BN_bn2hex(bn); //转化成16进制字符串 puts(a); printf("\n"); for(i=0;*(a+i)!='\0';i++) { *(pucRandom+i)=*(a+i); } *(pucRandom+i)='\0'; BN_free(bn); //释放BIGNUM结构 return SDF_OK; }

 

main.c

#include<stdio.h> #include<stdlib.h> #include "sdf.h" int main(){ void **pdh; pdh=(void **)malloc(20); //给pdh分配空间 int ret; ret = SDF_OpenDevice(pdh); //返回handle的指针 if(ret != SDF_OK) { printf("打开设备失败\n"); } else { printf("打开设备成功!\n"); } printf("查看设备信息\n"); DEVICEINFO a; ret = SDF_GetDeviceInfo(*pdh,&a); if(ret !=SDF_OK) printf("查看设备信息失败!\n"); else printf("查看设备信息成功!\n"); printf("设备名字叫做%s\n",a.DeviceName); printf("设备版本号为%d\n",a.DeviceVersion); printf("想要获取的随机数长度为:\n"); int n; scanf("%d",&n); char string[100]; ret = SDF_GenerateRandom(*pdh,n,string); if(ret !=SDF_OK) printf("生成随机数失败!"); else printf("生成的随机数为%s\n",string); ret = SDF_CloseDevice(*pdh); if(ret != SDF_OK) { printf("关闭不成功!\n"); } else { printf("关闭成功!\n"); } }

 

gcc test/main.c src/sdf.c -o bin/test -Iinclude  -lpthread -lcrypto

 

posted @ 2022-05-17 15:34  20191202王皓岩  阅读(225)  评论(0编辑  收藏  举报