实验一-密码引擎-加密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) 在就绪状态下进行的密钥操作,设备操作员应经过密码设备的认证。
GMT 0018-2012
本标准的目标是为公钥密码基础设施应用体系框架下的服务类密码设备制定统一的应用接口标准,通过该接口调用密码设备,向上层提供基础密码服务。为该类密码设备的开发、使用及检测提供标准依据和指导,有利于提高该类密码设备的产品化、标准化和系列化水平。
范围:本标准规定了公钥密码基础设施应用技术体系下服务类密码设备的应用接口标准,适用于服务类密码设备的研制、使用,以及基于该类密码设备的应用开发,也可用于指导该类密码设备的检测。
密码设备应用接口在公钥密码基础设施应用技术体系框架中的位置:在公钥密码基础设施应用技术体系框架中,密码设备服务层由密码机、密码卡、智能密码终瑞等设备组成,通过本标准规定的密码设备应用接口向通用密码服务层提供基础密码服务。
设备管理类函数
打开设备:SDF_OpenDevice
关闭设备:SDF_CloseDevice
创建会话:SDF_OpenSession
关闭会话:SDF_CloseSession
获取设备信息:SDF_GetDeviceInfo
产生随机数:SDF_GenerateRandom
获取私钥使用权限:SDF_GetPrivateKeyAccessRight
释放私钥使用权限:SDF_ReleasePrivateKeyAccessRight
密钥管理类函数
导出 RSA 签名公钥:SDF_ExportSignPublicKey_RSA
导出 RSA 加密公钥:SDF_ExportEncPublicKey_RSA
产生RSA非对称密钥对并输出:SDF_GenerateKeyPair_RSA
生成会话密钥并用内部RSA公钥加密输出:SDF_GenerateKeyWithIPK_RSA
生成会话密钥并用外部RSA公钥加密输出:SDF_GenerateKeyWithEPK_RSA
导人会话密钥并用内部RSA私钥解密:SDF_ImportKeyWithISK_RSA
基于 RSA 算法的数宇信封转换:SDF_ExchangeDigitEnvelopeBaseOnRSA
导出 ECC 签名公钥:SDF_ExportSignPublicKey_ECC
导出 ECC 加密公钥:SDF_ExportEncPublicKey_ECC
产生ECC非对称密钥对并输出:SDF_GenerateKeyPair_ECC
生成会话密钥并用内部ECC公钥加密输岀:SDF_GenerateKeyWithIPK_ECC
生成会话密钥并用外部ECC公钥加密输出:SDF_GenerateKeyWithEPK_ECC
导入会话密钥并用内部ECC私钥解密:SDFJmportKeyWithlSKJECC
生成密钥协商参数并输出:SDF_GenerateAgreementDataWithECC
计算会话密钥:SDF_GenerateKey WithECC
产生协商数据并计算会话密钥:SDF_GenerateAgreementDataAndKeyWithECC
基于 ECC算法的数字信封转换:SDF_ExchangeDigitEnvelopeBaseOnECC
生成会话密钥并用密钥加密密钥加密输出: SDF_GenerateKeyWithKEK
导入会话密钥并用密钥加密密钥解密:SDF_ImportKeyWithKEK
销毁会话密钥:SDF_DestroyKey
非对称算法运算类函数
外部公钥 RSA 运算:SDF_ExternalPublicKeyOperation_RSA
内部公钥 RSA 运算:SDF_InternalPublicKeyOperation_RSA
内部私钥 RSA 运算:SDF_InternalPrivateKeyOperation_RSA
外部密钥 ECC 验证:SDF_ExternalVerify_ECC
内部密钥 ECC 签名:SDF_InternalSign_ECC
内部密钥 ECC 验证:SDF_InternalVerify_ECC
外部密钥 ECC 加密:SDF_ExternalEncrypt_ECC
对称算法运算类函数
对称加密:SDF_Encrypt
对称解密:SDF_Decrypt
计算MAC:SDF_CalculateMAC
杂凑运算类函数
杂凑运算初始化:SDF_HashInit
多包杂凑运算:SDF_HashUpdate
杂凑运算结束:SDF_HashFinal
设备管理中的打开设备,关闭设备,获取设备信息,产生随机数
mkdir sdfproject
cd sdfproject
mkdir src include libs docs test
touch Makefile
touch readme.md
touch compile.shcd docs
mkdir ref
将GMT0018-2012放入ref文件夹下
代码
ECC
导出ECC签名公钥
描述:
参数:
int SDF_ExportSignPublicKey_ECC(
void * hSessionHandle, unsigned int uiKeylndex,
ECCrefPublicKey * pucPublicKey); 导岀密码设备内部存储的指定索引位置的签名公钥。 hSessionHandle[in] uiKeyIndex[in] pucPublicKey[out] 0
与设备建立的会话句柄
密码设备存储的ECC密钥对索引值
ECC公钥结构
返回值: 0成功; 非0失败,返回错误代码
导出ECC加密公钥
原型:
描述: 参数:
int SDF__ExportEncPublicKey_ECC(
void * hSessionHandle,
unsigned int uiKeylndex,
ECCrefPublicKey * pucPublicKey); 导出密码设备内部存储的指定索引位置的加密公钥。 hSessionHandle[in] uiKeyIndex[in] pucPublicKey[out] 0
与设备建立的会话句柄
密码设备存储的ECC密钥对索引值
ECC公钥结构
返回值: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] pucPrivateKey[out] 0
与设备建立的会话句柄 指定算法标识 指定密钥长度
ECC公钥结构
ECC私钥结构
返回值:0 成功; 非0 失败,返回错误代码
设备管理中的打开设备,关闭设备,获取设备信息,产生随机数
//设备管理
/*
功能:打开密码设备
参数:
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
定义与主函数
#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
写main.c,其中调用src里定义的函数
test/main.c
#include
#include
#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");
}
}
sdf.c实现函数
src/sdf.c
#include
# include
#include
#include "sdf.h"
#include
#include
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,"lzySDF");
strcpy(di.DeviceName,"SDFlzy20181309");
strcpy(di.DeviceSerial,"20210425");
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;
}
compile.sh
编译指令:
gcc test/main.c src/sdf.c -o bin/test -Iinclude -lpthread -lcrypto
运行结果