当前位置:   article > 正文

基于OpenSSL,实现C语言SM2的PKCS8的公私钥编码_在线sm2私钥pkcs8转换工具

在线sm2私钥pkcs8转换工具

基于OpenSSL, 实现算法的 Engine专栏

基于OpenSSL, 实现数据编码转换专栏

本专栏订阅后可查看以下文章 

基于OpenSSL,实现C语言RSA的PKCS10的证书请求

基于OpenSSL,实现C语言SM2的PKCS10的证书请求 

基于OpenSSL,实现C语言RSA的PKCS8的公私钥编码

在日常工作中使用密码,就一定会接触到OpenSSL,这个算法库带给我们的东西太多太多,不管是密码算法层面,还有代码框架和使用技巧上更是值得我们去学习和专研。

在接触密码学中,就会涉及到证书,我们在虚拟网络中产生信任,就要有一个信任源,而在密码层面,信任源就是颁布证书的认证中心,从而,证书就是我们可以相信的虚拟对象。

在自己的学习过程中,可以参考网络中,自己创建一个CA中心,自己产生一个证书请求,自己用CA中心颁发一个自签名的证书,这样在验证过程中,就可以验证此证书了。这里的证书请求就是PKCS10,简称为P10。下面我将给出针对C语言产生P10的实例。

主要函数如下:

  1. // 获得内存中公钥的PKCS8编码字符串
  2. // 调用者需要释放ppucDer变量的内存
  3. int lbxx_pkcs8_i2d_sm2_memory_prikey(unsigned char *pucPrikey, unsigned int uiKeylen, unsigned char **ppucDer, unsigned int *puiLen);
  4. // 获得内存中公钥的PKCS8编码字符串
  5. // 调用者需要释放ppucDer变量的内存
  6. int lbxx_pkcs8_i2d_sm2_memory_pubkey(unsigned char *pucPubkey, unsigned int uiKeylen, unsigned char **ppucDer, unsigned int *puiLen);
  7. // 从PKCS8编码中获得私钥
  8. int lbxx_pkcs8_d2i_sm2_prikey(unsigned char *pucDer, unsigned int puiLen, unsigned char *pucPrikey, unsigned int *uiKeylen);
  9. // 从PKCS8编码中获得公钥
  10. int lbxx_pkcs8_d2i_sm2_pubkey(unsigned char *pucDer, unsigned int puiLen, unsigned char *pucPubkey, unsigned int *uiKeylen);
  11. // 获得新密钥私钥的PKCS8编码字符串
  12. // 调用者需要释放ppucDer变量的内存
  13. int lbxx_pkcs8_i2d_sm2_generate_prikey(unsigned char **ppucDer, unsigned int *puiLen);
  14. // 获得新密钥公钥的PKCS8编码字符串
  15. // 调用者需要释放ppucDer变量的内存
  16. int lbxx_pkcs8_i2d_sm2_generate_pubkey(unsigned char **ppucDer, unsigned int *puiLen);

具体调用方式如下,我添加了一些注释,便于理解,这里需要使用带有国密算法SM2/3/4的OpenSSL库编译,否则会报错误。

  1. /****************************************************************
  2. * FileName: pkcs8_sm2.c
  3. * Author: labixiaoxin1849
  4. * Date: 2023-04-23
  5. * Description: SM2 key for pkcs8 algorithm call of OpenSSL
  6. ****************************************************************/
  7. #include <string.h>
  8. #include <openssl/ec.h>
  9. #include <openssl/evp.h>
  10. #include <openssl/x509.h>
  11. static unsigned char sPrikey[] = {
  12. 0xfc, 0x0b, 0xe0, 0x52, 0x8b, 0x6e, 0xab, 0x7c, 0xf8, 0x92, 0xf0, 0x5c, 0xc2, 0xfe, 0x94, 0xa0,
  13. 0x47, 0x1a, 0x12, 0x8b, 0x29, 0xb5, 0xcb, 0xb8, 0x92, 0x99, 0x0c, 0x7f, 0x4c, 0x2a, 0x2b, 0x7b
  14. };
  15. static unsigned int sPrikeyLen = 32;
  16. static unsigned char sPubkey[] = {
  17. 0x04, 0x90, 0x0b, 0x0d, 0x87, 0xc0, 0xbd, 0x5d, 0x57, 0x60, 0x7a, 0x2a, 0xe1, 0x43, 0x14, 0x4d,
  18. 0xa4, 0xe1, 0x2f, 0xe5, 0x9d, 0xbd, 0x02, 0x2c, 0xc3, 0x97, 0x8a, 0x71, 0xb1, 0x52, 0xc6, 0xf2,
  19. 0xb4, 0x52, 0x14, 0xaa, 0x1e, 0xee, 0x78, 0x5f, 0x1f, 0xe8, 0x5b, 0x44, 0x63, 0x68, 0x2b, 0x6e,
  20. 0x07, 0x80, 0x7a, 0xfd, 0x61, 0x9e, 0xca, 0x94, 0xcb, 0x41, 0x7d, 0xe7, 0xe4, 0x49, 0xbf, 0x3c,
  21. 0xda,
  22. };
  23. static unsigned int sPubkeyLen = 65;
  24. // 获得内存中公钥的PKCS8编码字符串
  25. // 调用者需要释放ppucDer变量的内存
  26. int lbxx_pkcs8_i2d_sm2_memory_prikey(unsigned char *pucPrikey, unsigned int uiKeylen, unsigned char **ppucDer, unsigned int *puiLen)
  27. {
  28. int ret = -1;
  29. EC_KEY *pSM2 = NULL;
  30. EVP_PKEY *pKey = NULL;
  31. PKCS8_PRIV_KEY_INFO *p8 = NULL;
  32. do{
  33. /* 根据nid创建EC_KEY */
  34. pSM2 = EC_KEY_new_by_curve_name(EVP_PKEY_SM2);
  35. if (!pSM2) {
  36. break;
  37. }
  38. /* 从内存设置私钥 */
  39. ret = EC_KEY_oct2priv(pSM2, pucPrikey, uiKeylen);
  40. if (ret != 1) {
  41. break;
  42. }
  43. const EC_GROUP *ecGroup = EC_KEY_get0_group(pSM2);
  44. EC_POINT *ecPubPoint = EC_POINT_new(ecGroup);
  45. const BIGNUM *ecPriKey = EC_KEY_get0_private_key(pSM2);
  46. ret = EC_POINT_mul(ecGroup, ecPubPoint, ecPriKey, NULL, NULL, NULL);
  47. if (ret) {
  48. EC_KEY_set_public_key(pSM2, ecPubPoint);
  49. }
  50. EC_POINT_free(ecPubPoint);
  51. /* 创建EVP_PKEY并设置密钥 */
  52. pKey = EVP_PKEY_new();
  53. if (!pKey) {
  54. break;
  55. }
  56. if (!EVP_PKEY_set1_EC_KEY(pKey, pSM2)){
  57. break;
  58. }
  59. /* EVP_PKEY转为PKCS8 */
  60. p8 = EVP_PKEY2PKCS8(pKey);
  61. if (!p8) {
  62. break;
  63. }
  64. *puiLen = i2d_PKCS8_PRIV_KEY_INFO(p8, ppucDer);
  65. ret = 0;
  66. }while(0);
  67. EC_KEY_free(pSM2);
  68. EVP_PKEY_free(pKey);
  69. PKCS8_PRIV_KEY_INFO_free(p8);
  70. return ret;
  71. }
  72. // 获得内存中公钥的PKCS8编码字符串
  73. // 调用者需要释放ppucDer变量的内存
  74. int lbxx_pkcs8_i2d_sm2_memory_pubkey(unsigned char *pucPubkey, unsigned int uiKeylen, unsigned char **ppucDer, unsigned int *puiLen)
  75. {
  76. int ret = -1;
  77. EC_KEY *pSM2 = NULL;
  78. EVP_PKEY *pKey = NULL;
  79. do{
  80. /* 根据nid创建EC_KEY */
  81. pSM2 = EC_KEY_new_by_curve_name(EVP_PKEY_SM2);
  82. if (!pSM2) {
  83. break;
  84. }
  85. /* 从内存设置公钥 */
  86. const unsigned char *pp = pucPubkey;
  87. if (!o2i_ECPublicKey(&pSM2, &pp, (long)uiKeylen)) {
  88. break;
  89. }
  90. /* 创建EVP_PKEY并设置密钥 */
  91. pKey = EVP_PKEY_new();
  92. if (!pKey) {
  93. break;
  94. }
  95. if (!EVP_PKEY_set1_EC_KEY(pKey, pSM2)){
  96. break;
  97. }
  98. /* EVP_PKEY转为PKCS8 */
  99. *puiLen = i2d_PUBKEY(pKey, ppucDer);
  100. ret = 0;
  101. }while(0);
  102. EC_KEY_free(pSM2);
  103. EVP_PKEY_free(pKey);
  104. return ret;
  105. }
  106. // 从PKCS8编码中获得私钥
  107. int lbxx_pkcs8_d2i_sm2_prikey(unsigned char *pucDer, unsigned int puiLen, unsigned char *pucPrikey, unsigned int *uiKeylen)
  108. {
  109. EC_KEY *pSM2 = NULL;
  110. EVP_PKEY *pKey = NULL;
  111. unsigned char *buf = NULL;
  112. unsigned int len = 0;
  113. pKey = d2i_AutoPrivateKey(NULL, (const unsigned char **)&pucDer, puiLen);
  114. if(!pKey) {
  115. return 1;
  116. }
  117. if (EVP_PKEY_id(pKey) != EVP_PKEY_EC && EVP_PKEY_id(pKey) != EVP_PKEY_SM2){
  118. return 1;
  119. }
  120. pSM2 = (EC_KEY *)EVP_PKEY_get0(pKey);
  121. if(!pSM2) {
  122. return 1;
  123. }
  124. len = EC_KEY_priv2buf(pSM2, &buf);
  125. if(*uiKeylen < len) {
  126. return 1;
  127. }
  128. memcpy(pucPrikey, buf, len);
  129. *uiKeylen = len;
  130. return 0;
  131. }
  132. // 从PKCS8编码中获得公钥
  133. int lbxx_pkcs8_d2i_sm2_pubkey(unsigned char *pucDer, unsigned int puiLen, unsigned char *pucPubkey, unsigned int *uiKeylen)
  134. {
  135. int len = 0;
  136. unsigned char *buf = NULL;
  137. EVP_PKEY *pKey = NULL;
  138. pKey = d2i_PUBKEY(NULL, (const unsigned char **)&pucDer, puiLen);
  139. if(!pKey) {
  140. return 1;
  141. }
  142. len = i2o_ECPublicKey((EC_KEY *)EVP_PKEY_get0(pKey), &buf);
  143. if(*uiKeylen < len) {
  144. return 1;
  145. }
  146. memcpy(pucPubkey, buf, len);
  147. *uiKeylen = len;
  148. return 0;
  149. }
  150. // 获得新密钥私钥的PKCS8编码字符串
  151. // 调用者需要释放ppucDer变量的内存
  152. int lbxx_pkcs8_i2d_sm2_generate_prikey(unsigned char **ppucDer, unsigned int *puiLen)
  153. {
  154. int ret = -1;
  155. EVP_PKEY *pKey = NULL;
  156. EVP_PKEY_CTX *pkey_ctx = NULL;
  157. PKCS8_PRIV_KEY_INFO *p8 = NULL;
  158. do{
  159. /*
  160. * 创建ECC类型的EVP用于生成SM2密钥对
  161. * 使用ECC类型是因为SM2操作函数中并没有提供生成算法
  162. * 在生成密钥对时,设置group同样可以产生SM2类型密钥对
  163. */
  164. pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
  165. if (!pkey_ctx) {
  166. break;
  167. }
  168. /* 必须调用init,内部设置操作类型 */
  169. if (EVP_PKEY_keygen_init(pkey_ctx) <= 0){
  170. break;
  171. }
  172. /* 设置SM2类型GROUP */
  173. EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx, EVP_PKEY_SM2);
  174. /* 获取密钥对,结果存放于pKey中 */
  175. if (EVP_PKEY_keygen(pkey_ctx, &pKey) <= 0) {
  176. break;
  177. }
  178. /* EVP_PKEY转为PKCS8 */
  179. p8 = EVP_PKEY2PKCS8(pKey);
  180. if (!p8) {
  181. break;
  182. }
  183. *puiLen = i2d_PKCS8_PRIV_KEY_INFO(p8, ppucDer);
  184. ret = 0;
  185. }while(0);
  186. EVP_PKEY_free(pKey);
  187. EVP_PKEY_CTX_free(pkey_ctx);
  188. PKCS8_PRIV_KEY_INFO_free(p8);
  189. return ret;
  190. }
  191. // 获得新密钥公钥的PKCS8编码字符串
  192. // 调用者需要释放ppucDer变量的内存
  193. int lbxx_pkcs8_i2d_sm2_generate_pubkey(unsigned char **ppucDer, unsigned int *puiLen)
  194. {
  195. int ret = -1;
  196. EVP_PKEY *pKey = NULL;
  197. EVP_PKEY_CTX *pkey_ctx = NULL;
  198. do{
  199. /*
  200. * 创建ECC类型的EVP用于生成SM2密钥对
  201. * 使用ECC类型是因为SM2操作函数中并没有提供生成算法
  202. * 在生成密钥对时,设置group同样可以产生SM2类型密钥对
  203. */
  204. pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
  205. if (!pkey_ctx) {
  206. break;
  207. }
  208. /* 必须调用init,内部设置操作类型 */
  209. if (EVP_PKEY_keygen_init(pkey_ctx) <= 0){
  210. break;
  211. }
  212. /* 设置SM2类型GROUP */
  213. EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx, EVP_PKEY_SM2);
  214. /* 获取密钥对,结果存放于pKey中 */
  215. if (EVP_PKEY_keygen(pkey_ctx, &pKey) <= 0) {
  216. break;
  217. }
  218. /* EVP_PKEY转为PKCS8 */
  219. *puiLen = i2d_PUBKEY(pKey, ppucDer);
  220. ret = 0;
  221. }while(0);
  222. EVP_PKEY_free(pKey);
  223. EVP_PKEY_CTX_free(pkey_ctx);
  224. return ret;
  225. }
  226. int main(int argc, char *argv[])
  227. {
  228. int ret = 0;
  229. // 必须为NULL
  230. unsigned char *pucDer = NULL;
  231. unsigned int uiDerlen = 0;
  232. unsigned char buf[128] = { 0 };
  233. unsigned int len = sizeof(buf);
  234. ret = lbxx_pkcs8_i2d_sm2_generate_prikey(&pucDer, &uiDerlen);
  235. if(ret != 0) {
  236. printf("call lbxx_pkcs8_i2d_sm2_generate_prikey() error\n");
  237. return 1;
  238. }
  239. OPENSSL_free(pucDer);
  240. pucDer = NULL;
  241. ret = lbxx_pkcs8_i2d_sm2_generate_pubkey(&pucDer, &uiDerlen);
  242. if(ret != 0) {
  243. printf("call lbxx_pkcs8_i2d_sm2_generate_pubkey() error\n");
  244. return 1;
  245. }
  246. OPENSSL_free(pucDer);
  247. pucDer = NULL;
  248. ret = lbxx_pkcs8_i2d_sm2_memory_prikey(sPrikey, sPrikeyLen, &pucDer, &uiDerlen);
  249. if(ret != 0) {
  250. printf("call lbxx_pkcs8_i2d_sm2_memory_prikey() error\n");
  251. return 1;
  252. }
  253. ret = lbxx_pkcs8_d2i_sm2_prikey(pucDer, uiDerlen, buf, &len);
  254. if(ret != 0) {
  255. printf("call lbxx_pkcs8_d2i_sm2_prikey() error\n");
  256. return 1;
  257. }
  258. if(sPrikeyLen != len || memcmp(sPrikey, buf, len) != 0) {
  259. printf("sm2 pkcs8 private key encode or decode error!!!!\n");
  260. return 1;
  261. }
  262. OPENSSL_free(pucDer);
  263. pucDer = NULL;
  264. memset(buf, 0x00, sizeof(buf));
  265. len = sizeof(buf);
  266. ret = lbxx_pkcs8_i2d_sm2_memory_pubkey(sPubkey, sPubkeyLen, &pucDer, &uiDerlen);
  267. if(ret != 0) {
  268. printf("call lbxx_pkcs8_i2d_sm2_memory_pubkey() error\n");
  269. return 1;
  270. }
  271. ret = lbxx_pkcs8_d2i_sm2_pubkey(pucDer, uiDerlen, buf, &len);
  272. if(ret != 0) {
  273. printf("call lbxx_pkcs8_d2i_sm2_pubkey() error\n");
  274. return 1;
  275. }
  276. if(sPubkeyLen != len || memcmp(sPubkey, buf, len) != 0) {
  277. printf("sm2 pkcs8 public key encode or decode error!!!!\n");
  278. return 1;
  279. }
  280. OPENSSL_free(pucDer);
  281. pucDer = NULL;
  282. printf("sm2 pkcs8 test success!!!\n");
  283. return 0;
  284. }

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/363208
推荐阅读
相关标签
  

闽ICP备14008679号