当前位置:   article > 正文

ECC算法与ECDSA签名、SM2签名、SM2加密、ElGamal加密的C/C++实现_c++ 怎么生成sm2秘钥

c++ 怎么生成sm2秘钥

一、原理

ECDSA

SM2

ElGamal

二、C/C++实现

头文件

POperation.h

  1. #ifndef POPERATION_H
  2. #define POPERATION_H
  3. // 定义点的结构
  4. typedef struct {
  5. long long x;
  6. long long y;
  7. } Point;
  8. // 定义椭圆曲线的结构
  9. typedef struct {
  10. long long a, b; // 曲线参数 y^2 = x^3 + ax + b
  11. long long p; // 有限域的素数
  12. } EllipticCurve;
  13. // 模逆运算的函数声明
  14. long long mod_inverse(long long a, long long m);
  15. // 点加运算的函数声明
  16. Point point_add(Point P, Point Q, EllipticCurve ec);
  17. // 点乘运算的函数声明
  18. Point point_multiply(long long scalar, Point P, EllipticCurve ec);
  19. #endif // POPERATION_H

ECDSA.h

  1. #ifndef ECDSA_H
  2. #define ECDSA_H
  3. #include "POperation.h" // 包含 EllipticCurve 和 Point 结构的定义
  4. // ECDSA签名函数声明
  5. void ecdsa_sign(char* message, long long d, EllipticCurve ec, Point G, long long n, long long* r, long long* s);
  6. // ECDSA验证函数声明
  7. int ecdsa_verify(char* message, Point Q, EllipticCurve ec, Point G, long long n, long long r, long long s);
  8. // 简单哈希函数声明
  9. long long simple_hash(char* message);
  10. #endif // ECDSA_H

ElGamal.h

  1. #ifndef ELGAMAL_H
  2. #define ELGAMAL_H
  3. #include <gmpxx.h>
  4. #include <vector>
  5. #include <iostream>
  6. // 检测原根
  7. bool is_primitive_root(const mpz_class& g, const mpz_class& p);
  8. // 生成大质数和其原根
  9. void generate_prime_and_primitive_root(mpz_class& p, mpz_class& g);
  10. // 生成公钥和私钥
  11. void generate_keys(mpz_class& p, mpz_class& g, mpz_class& y, mpz_class& x);
  12. // 加密
  13. void encrypt(const mpz_class& p, const mpz_class& g, const mpz_class& y, const mpz_class& m, mpz_class& c1, mpz_class& c2);
  14. // 解密
  15. void decrypt(const mpz_class& p, const mpz_class& x, const mpz_class& c1, const mpz_class& c2, mpz_class& m);
  16. #endif // ELGAMAL_H

SM2.h

  1. #pragma once
  2. #ifndef SM2_H
  3. #define SM2_H
  4. #include <openssl/evp.h>
  5. #include <openssl/ec.h>
  6. #include <openssl/pem.h>
  7. #include <openssl/err.h>
  8. #include <iostream>
  9. #include <cstring>
  10. // 错误处理函数
  11. void handleOpenSSLErrors();
  12. // 生成SM2密钥对
  13. EVP_PKEY* generateSM2KeyPair();
  14. // SM2签名
  15. bool sm2Sign(EVP_PKEY* pkey, const unsigned char* data, size_t dataLen, unsigned char** sig, size_t* sigLen);
  16. #endif // SM2_H

源文件

POperation.cpp

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "POperation.h"
  4. //typedef struct {
  5. // long long x;
  6. // long long y;
  7. //} Point;
  8. //
  9. //typedef struct {
  10. // long long a, b; // 曲线参数 y^2 = x^3 + ax + b
  11. // long long p; // 有限域的素数
  12. //} EllipticCurve;
  13. // 模逆运算
  14. long long mod_inverse(long long a, long long m) {
  15. long long m0 = m, t, q;
  16. long long x0 = 0, x1 = 1;
  17. if (m == 1) {
  18. return 0;
  19. }
  20. while (a > 1) {
  21. q = a / m;
  22. t = m;
  23. m = a % m, a = t;
  24. t = x0;
  25. x0 = x1 - q * x0;
  26. x1 = t;
  27. }
  28. if (x1 < 0) {
  29. x1 += m0;
  30. }
  31. return x1;
  32. }
  33. // 点加运算
  34. Point point_add(Point P, Point Q, EllipticCurve ec) {
  35. Point R;
  36. if (P.x == Q.x && P.y == Q.y) { // 点倍运算
  37. if (P.y == 0) {
  38. R.x = 0;
  39. R.y = 0;
  40. return R;
  41. }
  42. long long s = (3 * P.x * P.x + ec.a) * mod_inverse(2 * P.y, ec.p) % ec.p;
  43. R.x = (s * s - 2 * P.x) % ec.p;
  44. R.y = (s * (P.x - R.x) - P.y) % ec.p;
  45. }
  46. else { // 一般点加运算
  47. if (P.x == Q.x) {
  48. R.x = 0;
  49. R.y = 0;
  50. return R;
  51. }
  52. long long s = (Q.y - P.y) * mod_inverse(Q.x - P.x, ec.p) % ec.p;
  53. R.x = (s * s - P.x - Q.x) % ec.p;
  54. R.y = (s * (P.x - R.x) - P.y) % ec.p;
  55. }
  56. R.x = (R.x + ec.p) % ec.p;
  57. R.y = (R.y + ec.p) % ec.p;
  58. return R;
  59. }
  60. // 点乘运算
  61. Point point_multiply(long long scalar, Point P, EllipticCurve ec) {
  62. Point result = { 0, 0 }; // 无穷远点
  63. Point temp = P;
  64. while (scalar != 0) {
  65. if (scalar % 2 != 0) {
  66. if (result.x == 0 && result.y == 0) {
  67. result = temp;
  68. }
  69. else {
  70. result = point_add(result, temp, ec);
  71. }
  72. }
  73. temp = point_add(temp, temp, ec);
  74. scalar /= 2;
  75. }
  76. return result;
  77. }

ECDSA.cpp

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "POperation.h" // 假设之前定义的椭圆曲线结构和函数在这个头文件中
  5. #include "ECDSA.h"
  6. // 简单的哈希函数(仅用于示例)
  7. long long simple_hash(char* message) {
  8. long long hash = 0;
  9. while (*message) {
  10. hash = (hash * 31 + *message) % LONG_MAX;
  11. message++;
  12. }
  13. return hash;
  14. }
  15. void ecdsa_sign(char* message, long long d, EllipticCurve ec, Point G, long long n, long long* r, long long* s) {
  16. long long z = simple_hash(message); // 获取消息的哈希值
  17. long long k, x1, y1;
  18. do {
  19. k = rand() % (n - 1) + 1; // 随机数 k
  20. Point kG = point_multiply(k, G, ec); // 计算 k * G
  21. x1 = kG.x; y1 = kG.y;
  22. *r = x1 % n;
  23. } while (*r == 0);
  24. long long k_inv = mod_inverse(k, n);
  25. *s = (k_inv * (z + *r * d)) % n;
  26. if (*s == 0) {
  27. ecdsa_sign(message, d, ec, G, n, r, s); // 如果 s 为 0,则重新签名
  28. }
  29. }
  30. int ecdsa_verify(char* message, Point Q, EllipticCurve ec, Point G, long long n, long long r, long long s) {
  31. if (r <= 0 || r >= n || s <= 0 || s >= n) {
  32. return 0; // 验证 r 和 s 是否在合法范围内
  33. }
  34. long long z = simple_hash(message); // 获取消息的哈希值
  35. long long w = mod_inverse(s, n);
  36. long long u1 = (z * w) % n;
  37. long long u2 = (r * w) % n;
  38. Point u1G = point_multiply(u1, G, ec);
  39. Point u2Q = point_multiply(u2, Q, ec);
  40. Point P = point_add(u1G, u2Q, ec);
  41. if (P.x == LONG_MAX && P.y == LONG_MAX) {
  42. return 0; // 如果 P 是无穷远点
  43. }
  44. return (P.x % n == r); // 验证 r 是否等于 P.x mod n
  45. }

ElGamal.cpp

  1. #include <gmpxx.h>
  2. #include <cstdlib>
  3. #include <ctime>
  4. #include <vector>
  5. #include <iostream>
  6. #include "ElGamal.h"
  7. using namespace std;
  8. // 检测原根
  9. bool is_primitive_root(const mpz_class& g, const mpz_class& p) {
  10. vector<mpz_class> factors;
  11. mpz_class phi = p - 1;
  12. mpz_class n = phi;
  13. // 计算p - 1的所有质因数
  14. for (mpz_class i = 2; i * i <= n; ++i) {
  15. if (n % i == 0) {
  16. factors.push_back(i);
  17. while (n % i == 0)
  18. n /= i;
  19. }
  20. }
  21. if (n > 1)
  22. factors.push_back(n);
  23. for (mpz_class factor : factors) {
  24. mpz_class res;
  25. mpz_powm(res.get_mpz_t(), g.get_mpz_t(), mpz_class(phi / factor).get_mpz_t(), p.get_mpz_t());
  26. if (res == 1)
  27. return false;
  28. }
  29. return true;
  30. }
  31. // 生成大质数和其原根
  32. void generate_prime_and_primitive_root(mpz_class& p, mpz_class& g) {
  33. // 生成大质数
  34. gmp_randclass rr(gmp_randinit_default);
  35. rr.seed(time(NULL));
  36. p = rr.get_z_bits(512);
  37. mpz_nextprime(p.get_mpz_t(), p.get_mpz_t());
  38. // 寻找原根
  39. g = 2;
  40. while (!is_primitive_root(g, p))
  41. g += 1;
  42. }
  43. // 生成公钥和私钥
  44. void generate_keys(mpz_class& p, mpz_class& g, mpz_class& y, mpz_class& x) {
  45. // 随机生成大质数p和其原根g
  46. // 由于寻找原根的效率问题,这里简化为固定的质数和原根
  47. p = 23; // 实际应用中应该是大质数
  48. g = 5; // 实际应用中应该是p的原根
  49. // 随机选择私钥x
  50. x = rand() % (p - 2) + 1;
  51. // 计算公钥y
  52. mpz_powm(y.get_mpz_t(), g.get_mpz_t(), x.get_mpz_t(), p.get_mpz_t());
  53. }
  54. // 加密
  55. void encrypt(const mpz_class& p, const mpz_class& g, const mpz_class& y, const mpz_class& m, mpz_class& c1, mpz_class& c2) {
  56. mpz_class k = rand() % (p - 1) + 1; // 随机选择k
  57. mpz_class s;
  58. // 计算c1
  59. mpz_powm(c1.get_mpz_t(), g.get_mpz_t(), k.get_mpz_t(), p.get_mpz_t());
  60. // 计算s (共享密钥)
  61. mpz_powm(s.get_mpz_t(), y.get_mpz_t(), k.get_mpz_t(), p.get_mpz_t());
  62. // 计算c2
  63. c2 = (m * s) % p;
  64. }
  65. // 解密
  66. void decrypt(const mpz_class& p, const mpz_class& x, const mpz_class& c1, const mpz_class& c2, mpz_class& m) {
  67. mpz_class s, s_inv;
  68. // 计算s (共享密钥)
  69. mpz_powm(s.get_mpz_t(), c1.get_mpz_t(), x.get_mpz_t(), p.get_mpz_t());
  70. // 计算s的逆
  71. mpz_invert(s_inv.get_mpz_t(), s.get_mpz_t(), p.get_mpz_t());
  72. // 解密消息
  73. m = (c2 * s_inv) % p;
  74. }

SM2.cpp

  1. #include "openssl/evp.h"
  2. #include "openssl/ec.h"
  3. #include "openssl/pem.h"
  4. #include <iostream>
  5. #include <cstring>
  6. #include "SM2.h"
  7. // 错误处理
  8. void handleOpenSSLErrors() {
  9. ERR_print_errors_fp(stderr);
  10. abort
  11. ();
  12. }
  13. // 生成SM2密钥对
  14. EVP_PKEY* generateSM2KeyPair() {
  15. EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
  16. EVP_PKEY* pkey = nullptr;
  17. if (EVP_PKEY_keygen_init(pctx) <= 0) {
  18. handleOpenSSLErrors();
  19. }
  20. if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_sm2) <= 0) {
  21. handleOpenSSLErrors();
  22. }
  23. if (EVP_PKEY_keygen(pctx, &pkey) <= 0) {
  24. handleOpenSSLErrors();
  25. }
  26. EVP_PKEY_CTX_free(pctx);
  27. return pkey;
  28. }
  29. // SM2签名
  30. bool sm2Sign(EVP_PKEY* pkey, const unsigned char* data, size_t dataLen, unsigned char** sig, size_t* sigLen) {
  31. EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
  32. EVP_PKEY_CTX* pctx = nullptr;
  33. bool result = false;
  34. if (EVP_DigestSignInit(mdctx, &pctx, EVP_sm3(), nullptr, pkey) <= 0) {
  35. handleOpenSSLErrors();
  36. }
  37. if (EVP_DigestSign(mdctx, nullptr, sigLen, data, dataLen) <= 0) {
  38. handleOpenSSLErrors();
  39. }
  40. *sig = (unsigned char*)OPENSSL_malloc(*sigLen);
  41. if (EVP_DigestSign(mdctx, *sig, sigLen, data, dataLen) <= 0) {
  42. handleOpenSSLErrors();
  43. }
  44. else {
  45. result = true;
  46. }
  47. EVP_MD_CTX_free(mdctx);
  48. return result;
  49. }

ECCtest.cpp

  1. main.c
  2. //#include "ecc.h"
  3. //#include <stdio.h>
  4. //
  5. //int main() {
  6. // EllipticCurve ec = {/* 初始化曲线参数 */ };
  7. // Point p = {/* 初始化点 */ };
  8. //
  9. // // 测试点乘
  10. // Point result = point_multiply(2, p, ec);
  11. // printf("Result of Point Multiply: (%lld, %lld)\n", result.x, result.y);
  12. //
  13. // // 测试ECDSA签名和验证
  14. //
  15. // return 0;
  16. //}
  17. #include<cstdio>
  18. #include <gmp.h>
  19. #include <time.h>
  20. //#include "openssl/ec.h"
  21. //#include "openssl/evp.h"
  22. #include "POperation.h"
  23. #include "SM2.h"
  24. #include "ECDSA.h"
  25. #include "ElGamal.h"
  26. #define P "23"
  27. #define G "5"
  28. int main() {
  29. 示例:定义椭圆曲线参数和点
  30. //EllipticCurve ec = { 1, 6, 11 }; // 曲线 y² = x³ + x + 6 (mod 11)
  31. //Point P = { 2, 4 }; // 初始点
  32. 执行点乘运算
  33. //Point Q = point_multiply(3, P, ec);
  34. //printf("3P = (%lld, %lld)\n", Q.x, Q.y);
  35. 执行点加运算
  36. //Point R = point_add(P, Q, ec);
  37. //printf("P + 3P = (%lld, %lld)\n", R.x, R.y);
  38. //auto key = EC_KEY_new_by_curve_name(NID_secp256k1);
  39. //EC_KEY_generate_key(key);
  40. //unsigned char* pub_key = nullptr;
  41. //auto size = i2o_ECPublicKey(key, &pub_key);
  42. //for (int i = 0; i < size; ++i) {
  43. // std::printf("%02x", pub_key[i]);
  44. //}
  45. // EC_KEY_free(key);
  46. ECDSA sign and verify
  47. // // 定义椭圆曲线参数(简化版secp256k1)
  48. //EllipticCurve ec = { 0, 7, 17 }; // y^2 = x^3 + 7 (mod 17)
  49. //Point G = { 1, 1 }; // 基点G
  50. //long long n = 19; // 基点的阶
  51. 定义私钥(随机选取,但必须小于n)
  52. //long long d = 13; // 私钥
  53. 计算公钥
  54. //Point Q = point_multiply(d, G, ec);
  55. 要签名的消息
  56. //char message[] = "Hello, ECDSA!";
  57. 签名
  58. //long long r, s;
  59. //ecdsa_sign(message, d, ec, G, n, &r, &s);
  60. //printf("Signature:\n");
  61. //printf("r: %lld\n", r);
  62. //printf("s: %lld\n", s);
  63. 验证
  64. //int valid = ecdsa_verify(message, Q, ec, G, n, r, s);
  65. //if (valid) {
  66. // printf("Signature is valid.\n");
  67. //}
  68. //else {
  69. // printf("Signature is invalid.\n");
  70. //}
  71. SM2加密和签名
  72. //OpenSSL_add_all_algorithms();
  73. //ERR_load_crypto_strings();
  74. 生成密钥对
  75. //EVP_PKEY* pkey = generateSM2KeyPair();
  76. 要签名的数据
  77. //const char* data = "Hello, SM2!";
  78. //unsigned char* sig = nullptr;
  79. //size_t sigLen = 0;
  80. 签名
  81. //if (sm2Sign(pkey, (const unsigned char*)data, strlen(data), &sig, &sigLen)) {
  82. // std::cout << "Signature successful!" << std::endl;
  83. //}
  84. //else {
  85. // std::cout << "Signature failed!" << std::endl;
  86. //}
  87. 清理
  88. //OPENSSL_free(sig);
  89. //EVP_PKEY_free(pkey);
  90. //EVP_cleanup();
  91. //ERR_free_strings();
  92. //ElGamal测试
  93. mpz_t p, g, x, y, m, c1, c2, decrypted_m;
  94. mpz_inits(p, g, x, y, m, c1, c2, decrypted_m, NULL);
  95. // 设置p和g
  96. mpz_set_str(p, P, 10);
  97. mpz_set_str(g, G, 10);
  98. // 生成密钥
  99. generate_keys(p, g, x, y);
  100. gmp_printf("Public Key (y): %Zd\n", y);
  101. gmp_printf("Private Key (x): %Zd\n", x);
  102. // 设置消息m
  103. mpz_set_ui(m, 13); // 设置一个示例消息
  104. // 加密消息
  105. encrypt(p, g, y, m, c1, c2);
  106. gmp_printf("Encrypted Message (c1, c2): (%Zd, %Zd)\n", c1, c2);
  107. // 解密消息
  108. decrypt(p, x, c1, c2, decrypted_m);
  109. gmp_printf("Decrypted Message: %Zd\n", decrypted_m);
  110. mpz_clears(p, g, x, y, m, c1, c2, decrypted_m, NULL);
  111. return 0;
  112. }

三、运行结果

POperation测试

SM2测试

ECDSA测试

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

闽ICP备14008679号