赞
踩
Command Line Elliptic Curve Operations
图解公钥与私钥,加密解密、签名验签流程,什么是 CA 证书
因工作需要,正在研究 openssl 的使用,在 bootloader 中需要对应用程序 bin 文件进行签名,防止 bin 文件被篡改或者传输错误,使用非对称加密的 ECC 算法,椭圆曲线是 secp256r1 ,在 openssl 中使用命令 ecparam -list_curves 无法查看到该曲线,查阅资料后发现在 openssl 中名称有更改 (prime256v1)。
openssl(1.1.0.b) is not support secp256r1?(openssl ecparam - list_curves)
prime192v1 and the secp256r1 curve was referred to as prime256v1.
下载源码编译安装即可,比较简单。主要是为了研究一下生成私钥公钥、签名验签的过程,通过查看命令的文档找到使用的命令后,可以根据这些命令的源代码查看如何掉用 openssl 的库函数,最终在 widows 上使用。
需要指定下面这个环境变量:
export LD_LIBRARY_PATH=/home/xhr/Downloads/openssl-1.1.1e/opt/lib
常用命令:
1. 查看支持的曲线 openssl ecparam -list_curves 2. 生成 ecc 私钥 openssl ecparam -out privkey.pem -name prime256v1 -genkey openssl ecparam -out privkey.pem -name prime256v1 -param_enc explicit -genkey 3. 查看私钥 openssl ecparam -in privkey.pem -text 4. 验证 EC 参数 openssl ecparam -in privkey.pem -check 5. 生成公钥 openssl ec -in privkey.pem -out pubkey.pem -pubout -text 6. 签名 openssl pkeyutl -sign -in test.txt -out test.sign -inkey privkey.pem 7. 验证 openssl pkeyutl -verify -in test.txt -sigfile test.sign -inkey pubkey.pem -pubin 8. 签发 ECC 证书 (没有验证) openssl ecparam -out EccCA.key -name prime256v1 -genkey openssl req -config openssl.cnf -key EccCA.key -new -out EccCA.req openssl x509 -req -in EccCA.req -signkey EccCA.key -out EccCA.pem openssl ecparam -out EccSite.key -name prime256v1 -genkey openssl req -config openssl.cnf -key EccSite.key -new -out EccSite.req openssl x509 -req -in EccSite.req -CA EccCA.pem -CAkey EccCA.key -out EccSite.pem -CAcreateserial
= =|| 1.1.1e 版本愣是没能在 windows 上正常编译使用,下面都用的是 1.0.1g 版本的 dll。
这里用的是主要使用 libeay32.lib 和 libssl32.dll 两个文件。
#ifndef _ECC_API_H_ #define _ECC_API_H_ #ifdef _ECC_API_EXPORTS_ #define ECCAPI extern "C" __declspec(dllexport) #else #define ECCAPI extern "C" __declspec(dllimport) #endif typedef unsigned char uchar; #define KEY_TYPE_PRIVATE (0x1234) #define KEY_TYPE_PUBLIC (0x4321) #define KEY_FORMAT_DER (0xABCD) #define KEY_FORMAT_PEM (0xDCBA) /* 生成 EC 私钥 /privKey 生成的私钥 /maxLen 私钥 buff 最大长度 /curve_name 生成私钥所用的曲线名称 /return 成功返回正数代表私钥长度,失败返回负数 */ ECCAPI int GenEcPrivKey(uchar* privKey, int maxLen, const char* curve_name); /* 通过已有的私钥生成对应的公钥 /privKey 私钥 HEX 格式数据 /privLen 私钥长度 /pubKey 生成的公钥 /maxLen 公钥 buff 最大长度 /return 成功返回正数代表公钥长度,失败返回负数 */ ECCAPI int GenEcPubKey(const uchar* privKey, int privLen, uchar* pubKey, int maxLen); /* 保存钥匙到文件 /file 保存路径 /key 密钥 HEX 码 /keyLen 密钥长度 /keyType 公钥、私钥 /keyFormat 保存格式:DER、PEM /password 文件密码 /return 成功返回 0 */ ECCAPI int SavekEeyToFile(const char* file, const uchar* privKey, int privLen, int outKeyType, int outKeyFormat, const char* password); /* 从文件中读取密钥 /infile 输入文件 /keyType 公钥、私钥 /keyFormat 文件格式 /outKey 密钥 HEX (输出) /maxLen 输出密钥 buff 的最大长度 /password 文件密码 /return 负数表示错误编号,正数表示输出字节码的长度 */ ECCAPI int LoadKeyFormFile(const char* infile, const int keyType, const int keyFormat, uchar* outKey, const int maxLen, void* password); /* 对buf使用key进行签名 /sig 存放输出的签名 /maxlen 签名的最大长度 /buf 需要进行签名的内容 /buflen 需要进行签名的内容长度 /key 密钥 HEX /keyType 公钥、私钥 /keylen 密钥长度 /curve 如果提供的是公钥,必须提供曲线 /return 负数表示错误编号,正数表示签名的长度 */ ECCAPI int Sign(uchar* sig, const int maxlen, const uchar* buf, int buflen, const uchar* key, const int keyType, const int keylen, const char* curve); /* 验证签名是否正确 /sig 签名 /siglen 签名长度 /buf 验签内容 /buflen 验签内容长度 /key 密钥 HEX /kenlen 密钥长度 /keyType 公钥、私钥 /curve 提供公钥时必须提供该参数,曲线名称 /return 发生错误返回负数,验证失败返回 0,验证成功返回 1 */ ECCAPI int Verify( const uchar* sig, const int siglen, const uchar* buf, const int buflen, const uchar* key, const int keylen, const int keyType, const char* curve); #endif // !_ECC_API_H_
#include "pch.h" #include <EccAlgorithmApi.h> #include <string> #include <openssl\ec.h> #include <openssl\ec.h> #include <openssl\obj_mac.h> #include <openssl\bio.h> #include <openssl\pem.h> #pragma comment(lib, "libeay32") #define goto_fault(x) \ {\ ret_val = -x;\ goto FAULT_##x;\ } /* 通过名称获取曲线代号 */ static int GetNIDbyCurveName(const char* curve_name) { int nid; /* workaround for the SECG curve names secp192r1 * and secp256r1 (which are the same as the curves * prime192v1 and prime256v1 defined in X9.62) */ if (!strcmp(curve_name, "secp192r1")) { printf("using curve name prime192v1 instead of secp192r1\n"); nid = NID_X9_62_prime192v1; } else if (!strcmp(curve_name, "secp256r1")) { printf("using curve name prime256v1 instead of secp256r1\n"); nid = NID_X9_62_prime256v1; } else nid = OBJ_sn2nid(curve_name); if (nid == 0) { printf("unknown curve name (%s)\n", curve_name); } return nid; } /* 生成 EC 私钥 /privKey 生成的私钥 /maxLen 私钥 buff 最大长度 /curve_name 生成私钥所用的曲线名称 /return 成功返回正数代表私钥长度,失败返回负数 */ ECCAPI int GenEcPrivKey(uchar* privKey, int maxLen, const char* curve_name) { EC_KEY* ecKey; EC_GROUP* ecGroup; uchar* pp = privKey; int ret_val; if (NULL == (ecKey = EC_KEY_new())) goto_fault(1); if (NULL == (ecGroup = EC_GROUP_new_by_curve_name(GetNIDbyCurveName(curve_name)))) goto_fault(2); if (EC_KEY_set_group(ecKey, ecGroup) != 1) goto_fault(3); if (!EC_KEY_generate_key(ecKey)) goto_fault(3); ret_val = i2d_ECPrivateKey(ecKey, &pp); if (!ret_val || ret_val > maxLen) ret_val = -4; FAULT_3: EC_GROUP_free(ecGroup); FAULT_2: EC_KEY_free(ecKey); FAULT_1: return ret_val; } /* 通过已有的私钥生成对应的公钥 /privKey 私钥 HEX 格式数据 /privLen 私钥长度 /pubKey 生成的公钥 /maxLen 公钥 buff 最大长度 /return 返回负数表示失败,正数表示公钥的长度 /return 成功返回正数代表公钥长度,失败返回负数 */ ECCAPI int GenEcPubKey(const uchar* privKey, int privLen, uchar* pubKey, int maxLen) { int ret_val; EC_KEY* eckey; uchar* pp = (uchar*)privKey; eckey = d2i_ECPrivateKey(NULL, (const uchar**)&pp, privLen); if (!eckey) goto_fault(1); pp = pubKey; ret_val = i2o_ECPublicKey(eckey, &pp); if (!ret_val) ret_val = -2; EC_KEY_free(eckey); FAULT_1: return ret_val; } /* 保存密钥 /eckey 需要保存的密钥 /file 文件路径 /keyType 公钥、私钥 /keyFormat 保存格式:DER、PEM /password 文件密码 /return 成功返回 true */ static bool DoSavingKey(EC_KEY* eckey, const char* file, int keyType, int keyFormat, const char* password) { (void)password; int ret_val = 0; BIO* out; if (file == NULL) goto_fault(1); out = BIO_new(BIO_s_file()); if (!out) goto_fault(1); if (0 >= BIO_write_filename(out, (void*)file)) goto_fault(2); if (keyType == KEY_TYPE_PRIVATE) { if (keyFormat == KEY_FORMAT_DER) { ret_val = i2d_ECPrivateKey_bio(out, eckey); if (!ret_val) goto_fault(2); } else if (keyFormat == KEY_FORMAT_PEM) { ret_val = PEM_write_bio_ECPrivateKey(out,eckey, NULL, NULL, 0, NULL, NULL); if(!ret_val) goto_fault(2); } else goto_fault(2); } else if (keyType == KEY_TYPE_PUBLIC) { if (keyFormat == KEY_FORMAT_DER) { ret_val = i2d_EC_PUBKEY_bio(out, eckey); if (!ret_val) goto_fault(2); } else if (keyFormat == KEY_FORMAT_PEM) { ret_val = PEM_write_bio_EC_PUBKEY(out, eckey); if (!ret_val) goto_fault(2); } else goto_fault(2); } else ret_val = -100; FAULT_2: BIO_free_all(out); FAULT_1: return ret_val < 0 ? false : true; } /* 保存钥匙到文件 /file 保存路径 /key 密钥 HEX 码 /keyLen 密钥长度 /keyType 公钥、私钥 /keyFormat 保存格式:DER、PEM /password 文件密码 /return 成功返回 0 */ ECCAPI int SavekEeyToFile(const char* file, const uchar* privKey, int privLen, int outKeyType, int outKeyFormat, const char* password) { (void)password; int ret_val = 0; EC_KEY* eckey; const uchar* pp = privKey; /*switch (keyType) { case KEY_TYPE_PRIVATE: if(!(eckey = d2i_ECPrivateKey(NULL, &pp, keyLen))) goto_fault(1); break; case KEY_TYPE_PUBLIC: if (!(eckey = o2i_ECPublicKey(NULL, &pp, keyLen))) goto_fault(1); break; default: goto_fault(1); }*/ if (!(eckey = d2i_ECPrivateKey(NULL, &pp, privLen))) goto_fault(1); if (!DoSavingKey(eckey, file, outKeyType, outKeyFormat, password)) goto_fault(2); FAULT_2: EC_KEY_free(eckey); FAULT_1: return ret_val; } /* 从文件中读取密钥 /infile 输入文件 /keyType 公钥、私钥 /keyFormat 文件格式 /outKey 密钥 HEX (输出) /maxLen 输出密钥 buff 的最大长度 /password 文件密码 /return 负数表示错误编号,正数表示输出字节码的长度 */ ECCAPI int LoadKeyFormFile(const char* infile,const int keyType, const int keyFormat, uchar* outKey, const int maxLen, void* password) { int ret_val = 0; BIO* in; EC_KEY* eckey; uchar* pp = outKey; in = BIO_new(BIO_s_file()); if (in == NULL) goto_fault(1); if (0 >= BIO_read_filename(in, infile)) goto_fault(2); if (keyFormat == KEY_FORMAT_DER) { if (keyType == KEY_TYPE_PUBLIC) { eckey = d2i_EC_PUBKEY_bio(in, NULL); } else if (keyType == KEY_TYPE_PRIVATE) { eckey = d2i_ECPrivateKey_bio(in, NULL); } else goto_fault(2); } else if (keyFormat == KEY_FORMAT_PEM) { if (keyType == KEY_TYPE_PUBLIC) { eckey = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL); } else if (keyType == KEY_TYPE_PRIVATE) { eckey = PEM_read_bio_ECPrivateKey(in, NULL, NULL, password); } else goto_fault(2); } else goto_fault(2); if(eckey == NULL) goto_fault(3); if (keyType == KEY_TYPE_PRIVATE) { ret_val = i2d_ECPrivateKey(eckey, &pp); } else if (keyType == KEY_TYPE_PUBLIC) { ret_val = i2o_ECPublicKey(eckey, &pp); } else goto_fault(4); if (!ret_val || ret_val > maxLen) ret_val = -5; FAULT_4: EC_KEY_free(eckey); FAULT_3: FAULT_2: BIO_free(in); FAULT_1: return ret_val; } /* 对buf使用key进行签名 /sig 存放输出的签名 /maxlen 签名的最大长度 /buf 需要进行签名的内容 /buflen 需要进行签名的内容长度 /key 密钥 HEX /keyType 公钥、私钥 /keylen 密钥长度 /curve 如果提供的是公钥,必须提供曲线 /return 负数表示错误编号,正数表示签名的长度 */ ECCAPI int Sign(uchar* sig, const int maxlen, const uchar* buf, int buflen, const uchar* key, const int keyType, const int keylen, const char* curve) { (void)curve; unsigned int siglen = maxlen; int ret_val = 0; EC_KEY* eckey; const unsigned char* pp = key; if (keyType == KEY_TYPE_PRIVATE) { if(NULL == (eckey = d2i_ECPrivateKey(NULL, &pp, keylen))) goto_fault(1); } else if (keyType == KEY_TYPE_PUBLIC) { goto_fault(1); } else { goto_fault(1); } if (ECDSA_sign(0, buf, buflen, sig, &siglen, eckey)) { ret_val = (int)siglen; if (siglen > maxlen || siglen <= 0) ret_val = -3; } else ret_val = -2; EC_KEY_free(eckey); FAULT_1: return ret_val; } /* 获得合法的 ecKey 对象,返回非空需要调用方释放 /key 密钥 HEX /kenlen 密钥长度 /keyType 公钥、私钥 /curve 提供公钥时必须提供该参数,曲线名称 /return 没有合法的对象返回空,非空需要调用方释放 */ static EC_KEY* GetValidEcKey(const uchar* key, const int keylen, const int keyType, const char* curve) { EC_KEY* ret; EC_KEY* eckey = NULL; EC_GROUP* ecgroup = NULL; int ret_val = 0; const unsigned char* pp = key; if (keyType == KEY_TYPE_PRIVATE) { if (NULL == (eckey = d2i_ECPrivateKey(NULL, &pp, keylen))) goto_fault(1); } else if (keyType == KEY_TYPE_PUBLIC) { if(curve == NULL) goto_fault(1); if(!(eckey = EC_KEY_new())) goto_fault(1); if(!(ecgroup = EC_GROUP_new_by_curve_name(GetNIDbyCurveName(curve)))) goto_fault(1); (void)EC_KEY_set_group(eckey, ecgroup); // 该函数会复制一份 group 对象,所以应该释放 ret = o2i_ECPublicKey(&eckey, &pp, keylen); if(ret != eckey) goto_fault(1); } else goto_fault(1); FAULT_1: if (ret_val) if (eckey) { EC_KEY_free(eckey); eckey = NULL; } if (ecgroup) EC_GROUP_free(ecgroup); return eckey; } /* 验证签名是否正确 /sig 签名 /siglen 签名长度 /buf 验签内容 /buflen 验签内容长度 /key 密钥 HEX /kenlen 密钥长度 /keyType 公钥、私钥 /curve 提供公钥时必须提供该参数,曲线名称 /return 发生错误返回负数,验证失败返回 0,验证成功返回 1 */ ECCAPI int Verify( const uchar* sig, const int siglen, const uchar* buf, const int buflen, const uchar* key, const int keylen, const int keyType, const char* curve) { int ret_val = 0; EC_KEY* eckey = GetValidEcKey(key, keylen, keyType, curve); if (eckey == NULL) goto_fault(1); ret_val = ECDSA_verify(0, buf, buflen, sig, siglen, eckey); EC_KEY_free(eckey); FAULT_1: return ret_val; }
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.IO; namespace EccAlgorithmCs { /// <summary> /// 公钥、私钥 /// </summary> public enum KeyType : int { Private = 0x1234, Public = 0x4321, } /// <summary> /// DER、PEM /// </summary> public enum KeyFormat : int { DER = 0xABCD, PEM = 0xDCBA, } /// <summary> /// 公私钥 /// </summary> public class EcKey { // ---------- internal class ------------------------------------ /// <summary> /// 调用cpp库函数 /// </summary> private static class CPP { /// <summary> /// 生成 EC 私钥 /// </summary> /// <param name="privKey">生成的私钥</param> /// <param name="maxLen">私钥 buff 最大长度</param> /// <param name="curve_name">生成私钥所用的曲线名称</param> /// <returns>成功返回正数代表私钥长度,失败返回负数</returns> [DllImport("EccAlgorithmCpp.dll", CallingConvention = CallingConvention.Cdecl)] public extern static int GenEcPrivKey(byte[] privKey, int maxLen, byte[] curve_name); /// <summary> /// 通过已有的私钥生成对应的公钥 /// </summary> /// <param name="privKey">私钥 HEX 格式数据</param> /// <param name="privLen">私钥长度</param> /// <param name="pubKey">生成的公钥</param> /// <param name="maxLen">公钥 buff 最大长度</param> /// <returns>成功返回正数代表公钥长度,失败返回负数</returns> [DllImport("EccAlgorithmCpp.dll", CallingConvention = CallingConvention.Cdecl)] public extern static int GenEcPubKey(byte[] privKey, int privLen, byte[] pubKey, int maxLen); /// <summary> /// 保存钥匙到文件 /// </summary> /// <param name="file">保存路径</param> /// <param name="key">密钥 HEX 码</param> /// <param name="keyLen">密钥长度</param> /// <param name="keyType">公钥、私钥</param> /// <param name="keyFormat">保存格式:DER、PEM</param> /// <param name="password">文件密码</param> /// <returns>成功返回 0</returns> [DllImport("EccAlgorithmCpp.dll", CallingConvention = CallingConvention.Cdecl)] public extern static int SavekEeyToFile(byte[] file, byte[] privKey, int privLen, int outKeyType, int outKeyFormat, byte[] password); /// <summary> /// 从文件中读取密钥 /// </summary> /// <param name="infile">输入文件</param> /// <param name="keyType">公钥、私钥</param> /// <param name="keyFormat">文件格式</param> /// <param name="outKey">密钥 HEX (输出)</param> /// <param name="maxLen">输出密钥 buff 的最大长度</param> /// <param name="password">文件密码</param> /// <returns>负数表示错误编号,正数表示输出字节码的长度</returns> [DllImport("EccAlgorithmCpp.dll", CallingConvention = CallingConvention.Cdecl)] public extern static int LoadKeyFormFile(byte[] infile, int keyType, int keyFormat, byte[] outKey, int maxLen, byte[] password); /// <summary> /// 对buf使用key进行签名 /// </summary> /// <param name="sig">存放输出的签名</param> /// <param name="maxlen">签名的最大长度</param> /// <param name="buf">需要进行签名的内容</param> /// <param name="buflen">需要进行签名的内容长度</param> /// <param name="key">密钥 HEX</param> /// <param name="keyType">公钥、私钥</param> /// <param name="keylen">密钥长度</param> /// <param name="curve">如果提供的是公钥,必须提供曲线</param> /// <returns>负数表示错误编号,正数表示签名的长度</returns> [DllImport("EccAlgorithmCpp.dll", CallingConvention = CallingConvention.Cdecl)] public extern static int Sign(byte[] sig, int maxlen, byte[] buf, int buflen, byte[] key, int keyType, int keylen, byte[] curve); /// <summary> /// 验证签名是否正确,发生错误返回负数,验证失败返回 0,验证成功返回 1 /// </summary> /// <param name="sig">签名</param> /// <param name="siglen">签名长度</param> /// <param name="buf">验签内容</param> /// <param name="buflen">验签内容长度</param> /// <param name="key">密钥 HEX</param> /// <param name="keylen">密钥长度</param> /// <param name="keyType">公钥、私钥</param> /// <param name="curve">提供公钥时必须提供该参数,曲线名称</param> /// <returns>发生错误返回负数,验证失败返回 0,验证成功返回 1</returns> [DllImport("EccAlgorithmCpp.dll", CallingConvention = CallingConvention.Cdecl)] public extern static int Verify(byte[] sig, int siglen, byte[] buf, int buflen, byte[] key, int keylen, int keyType, byte[] curve); } /// <summary> /// 密钥信息 /// </summary> private class KeyInfo { public KeyInfo(byte[] hex, int len) { Hex = new byte[len]; Len = len; for (int i = 0; i < len; i++) { Hex[i] = hex[i]; } } public byte[] Hex { get; private set; } public int Len { get; private set; } } // ---------- field ---------------------------------------------- /// <summary> /// 私钥 /// </summary> private KeyInfo PrivKey; /// <summary> /// 公钥 /// </summary> private KeyInfo PubKey; // ---------- public attrib --------------------------------------- /// <summary> /// 最后一次发生错误的原因 /// </summary> public string TheLastErrorInfo { get; private set; } // ---------- public method --------------------------------------- /// <summary> /// 通过文件导入钥匙 /// </summary> /// <param name="file">文件路径</param> /// <param name="type">公钥、私钥</param> /// <param name="format">文件格式</param> /// <returns>成功返回true</returns> public bool ImportEcKey(string file, KeyType type, KeyFormat format) { return ImportEcKey(file, type, format, null); } /// <summary> /// 通过文件导入钥匙,需要输入文件密码 /// </summary> /// <param name="file">文件路径</param> /// <param name="type">公钥、私钥</param> /// <param name="format">文件格式</param> /// <param name="password">文件密码</param> /// <returns>成功返回true</returns> private bool ImportEcKey(string file, KeyType type, KeyFormat format, string password) { const int maxLen = 1024; byte[] infile = Encoding.Default.GetBytes(file); byte[] key = new byte[maxLen]; int len = CPP.LoadKeyFormFile(infile, (int)type, (int)format, key, maxLen, null); if(len <= 0) { TheLastErrorInfo = "LoadKeyFormFile fault code = " + len; if(type == KeyType.Public && format == KeyFormat.PEM) { TheLastErrorInfo += " 不支持导入 PEM 格式的公钥"; } goto FAULT; } switch (type) { case KeyType.Private: PrivKey = new KeyInfo(key, len); len = CPP.GenEcPubKey(PrivKey.Hex, PrivKey.Len, key, maxLen); if (len <= 0) { TheLastErrorInfo = "Auto GenEcPubKey fault code = " + len; goto FAULT; } PubKey = new KeyInfo(key, len); break; case KeyType.Public: PubKey = new KeyInfo(key, len); break; default: TheLastErrorInfo = "No Such KeyType!"; goto FAULT; } return true; FAULT: PrivKey = null; PubKey = null; return false; } /// <summary> /// 通过 HEX 导入密钥 /// </summary> /// <param name="keyHex">密钥</param> /// <param name="type">公钥、私钥</param> /// <returns>成功返回true</returns> private bool ImportEcKey(byte[] keyHex, KeyType type) { throw new NotImplementedException(); } /// <summary> /// 导出密钥 /// </summary> /// <param name="file">文件路径</param> /// <param name="type">公钥、私钥</param> /// <param name="format">文件格式</param> /// <returns>成功返回true</returns> private bool ExportEcKey(string file, KeyType type, KeyFormat format) { return ExportEcKey(file, type, format, null); } /// <summary> /// 导出密钥 /// </summary> /// <param name="file">文件路径</param> /// <param name="type">公钥、私钥</param> /// <param name="format">文件格式</param> /// <param name="password">文件密码</param> /// <returns>成功返回true</returns> private bool ExportEcKey(string file, KeyType type, KeyFormat format, string password) { byte[] xfile = Encoding.Default.GetBytes(file); KeyInfo key = PrivKey; //switch (type) //{ // case KeyType.Private: // key = PrivKey; // break; // case KeyType.Public: // key = PubKey; // break; //} if (key == null) { TheLastErrorInfo = "不存在私钥,无法导出"; return false; } int ret = CPP.SavekEeyToFile(xfile, key.Hex, key.Len, (int)type, (int)format, null); return ret < 0 ? false : true; } /// <summary> /// 导出私钥 /// </summary> /// <param name="file">文件路径</param> /// <param name="format">保存格式</param> /// <returns>成功返回true</returns> public bool ExportPrivKey(string file, KeyFormat format) { return ExportEcKey(file, KeyType.Private, format); } /// <summary> /// 导出公钥 /// </summary> /// <param name="file">文件路径</param> /// <param name="format">保存格式</param> /// <returns>成功返回true</returns> public bool ExportPubKey(string file, KeyFormat format) { return ExportEcKey(file, KeyType.Public, format); } /// <summary> /// 通过曲线名称生成密钥 /// </summary> /// <param name="curveName">曲线名称</param> /// <returns>成功返回true</returns> public bool GenerateEcKey(string curveName) { const int maxLen = 1024; byte[] key = new byte[maxLen]; byte[] curve = Encoding.Default.GetBytes(curveName.ToLower()); int len; len = CPP.GenEcPrivKey(key, maxLen, curve); if (len < 0) goto FAULT; PrivKey = new KeyInfo(key, len); len = CPP.GenEcPubKey(PrivKey.Hex, PrivKey.Len, key, maxLen); if (len < 0) goto FAULT; PubKey = new KeyInfo(key, len); return true; FAULT: PrivKey = null; PubKey = null; return false; } /// <summary> /// 对文件进行签名 /// </summary> /// <param name="file">文件路径</param> /// <returns>成功返回签名,失败返回null</returns> public byte[] Sign(string file) { return Sign(GetFileBytes(file)); } /// <summary> /// 对字节码进行签名 /// </summary> /// <param name="article">需要签名的内容</param> /// <returns>签名,失败返回 null</returns> public byte[] Sign(byte[] article) { if (article == null) { TheLastErrorInfo = "CS.Sign 中 article 参数不能为空"; return null; } const int maxlen = 1024; byte[] tmp = new byte[maxlen]; int len = CPP.Sign(tmp, maxlen, article, article.Length, PrivKey.Hex, (int)KeyType.Private, PrivKey.Len, null); if(len < 0 || len > maxlen) { TheLastErrorInfo = "CPP.Sign fault code = " + len; return null; } byte[] sig = new byte[len]; for (int i = 0; i < len; i++) { sig[i] = tmp[i]; } return sig; } /// <summary> /// 验证签名是否被篡改 /// </summary> /// <param name="article">需要验证的内容</param> /// <param name="signature">签名</param> /// <param name="curve">曲线名称</param> /// <returns>验证成功返回true</returns> public bool Verify(byte[] article, byte[] signature, string curve) { if (article == null || signature == null) { TheLastErrorInfo = "CS.Verify 中参数不能为 null"; return false; } int ret = CPP.Verify(signature, signature.Length, article, article.Length, PubKey.Hex, PubKey.Len, (int)KeyType.Public, Encoding.Default.GetBytes(curve.ToLower())); if (ret < 0) { TheLastErrorInfo = "验证过程发生错误 CPP.Verify fault code = " + ret; return false; } else if (ret == 0) { TheLastErrorInfo = "验证失败"; return false; } else return true; } /// <summary> /// 获取文件的二进制内容 /// </summary> /// <param name="file">需要读取的文件</param> /// <returns>失败返回空</returns> public byte[] GetFileBytes(string file) { const int limit = int.MaxValue; byte[] buf = null; try { FileStream fs = new FileStream(file, FileMode.Open); int len; if (fs.Length > limit) len = limit; else len = (int)fs.Length; buf = new byte[len]; fs.Read(buf, 0, len); fs.Close(); } catch (Exception ex) { TheLastErrorInfo = ex.Message; return null; } return buf; } } }
EcKey ec = new EcKey();
byte[] digest = ec.GetFileBytes("digest.txt");
ec.GenerateEcKey("secp256r1");
ec.ExportPrivKey(@"\privKey.der", KeyFormat.DER);
ec.ImportEcKey(@"\privKey.der", KeyType.Private, KeyFormat.DER);
byte[] sig = ec.Sign(digest);
ec.Verify(digest, sig, "secp256r1");
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。