于是月亮的含义不仅仅在是月亮!!!!!!
椭圆曲线密码体制(ECC)
1985 年,N. Koblitz 和 V. Miller 分别独立提出了椭圆曲线密码体制(ECC),其依据就是
定义在椭圆曲线点群上的离散对数问题的难解性。
为了用椭圆曲线构造密码系统,首先需要找到一个单向陷门函数,椭圆曲线上的数量乘
就是这样的单向陷门函数。
椭圆曲线的数量乘是这样定义的:设 E 为域 K 上的椭圆曲线,G 为 E 上的一点,这个
点被一个正整数 k 相乘的乘法定义为 k 个 G 相加,因而有
kG = G + G + … + G (共有 k 个 G)
若存在椭圆曲线上的另一点 N ≠ G,满足方程 kG = N。容易看出,给定 k 和 G,计算
N 相对容易。而给定 N 和 G,计算 k = log G N 相对困难。这就是椭圆曲线离散对数问题。
离散对数求解是非常困难的。椭圆曲线离散对数问题比有限域上的离散对数问题更难求解。对于有理点数有大素数因子的椭圆离散对数问题,目前还没有有效的攻击方法。
下面是一个签名与验签的例子:
在这个例子中,我们使用的openssl版本是1.1.1。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/evp.h>
void write_hex_to_file(const char *filename, const BIGNUM *bn) {
FILE *file = fopen(filename, "w");
if (file == NULL) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
char *hex_str = BN_bn2hex(bn);
fprintf(file, "%s", hex_str);
OPENSSL_free(hex_str);
fclose(file);
}
void sign_and_verify(EC_KEY *ec_key, const char *message) {
//! Sign the message
size_t message_len = strlen(message);
const unsigned char *message_bytes = (const unsigned char *)message;
unsigned char signature[ECDSA_size(ec_key)];
unsigned int signature_len;
if (ECDSA_sign(0, message_bytes, message_len, signature, &signature_len, ec_key) != 1) {
fprintf(stderr, "Error signing the message\n");
exit(EXIT_FAILURE);
}
// Save the signature to a file
FILE *signature_file = fopen("signature.bin", "wb");
if (signature_file == NULL) {
perror("Error opening signature file");
exit(EXIT_FAILURE);
}
fwrite(signature, 1, signature_len, signature_file);
fclose(signature_file);
printf("Message signed successfully.\n");
//! Verify the signature
if (ECDSA_verify(0, message_bytes, message_len, signature, signature_len, ec_key) != 1) {
fprintf(stderr, "Error verifying the signature\n");
exit(EXIT_FAILURE);
}
printf("Signature verified successfully.\n");
}
//! Generate a public key based on a hexadecimal number
int greater_snow_test_public_key()
{
EC_GROUP *test_group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
size_t buf_len;
unsigned char *buf;
int point_len;
if (!test_group) {
fprintf(stderr, "Error creating EC_GROUP.\n");
return EXIT_FAILURE;
}
EC_POINT *test_point = EC_POINT_new(test_group);
if (!test_point) {
fprintf(stderr, "Error creating EC_POINT.\n");
EC_GROUP_free(test_group);
return EXIT_FAILURE;
}
BIGNUM *a = BN_new();
BIGNUM *b = BN_new();
if(!a || !b)
{
fprintf(stderr, "Error creating BIGNUM.\n");
BN_free(a);
BN_free(b);
}
BN_hex2bn(&a, "F2C854E6B68452AEF0DFAF5689AF1AE5AC299ECBB7B32417A036FCB3A35F52AF");
BN_hex2bn(&b, "9EEF7C43BF4773B11FEA36CCEB27B8ED94ACD0724C8974349328DFBAB609306C");
//! Set public key
if (EC_POINT_set_affine_coordinates_GFp(test_group, test_point, a, b, NULL) != 1)
{
fprintf(stderr, "Error setting coordinates for EC_POINT.\n");
EC_POINT_free(test_point);
EC_GROUP_free(test_group);
BN_free(a);
BN_free(b);
return EXIT_FAILURE;
}
buf_len = EC_POINT_point2oct(test_group, test_point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
printf("Greater Snow buf len is %ld\n", buf_len);
buf = (unsigned char *)malloc(buf_len);
point_len = EC_POINT_point2oct(test_group, test_point, POINT_CONVERSION_UNCOMPRESSED, buf, buf_len, NULL);
printf("GreaterSnow point_len is %d\n", point_len);
printf("GreaterSnow Binary representation of the EC_POINT:\n");
for (size_t i = 0; i < buf_len; ++i)
{
printf("%02X", buf[i]);
}
printf("\n");
free(buf);
return 0;
}
int main() {
//! Initialize OpenSSL library
OpenSSL_add_all_algorithms();
unsigned char *buf;
//! Create EC_KEY structure for secp256r1 curve
EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (ec_key == NULL) {
fprintf(stderr, "Error creating EC_KEY structure\n");
exit(EXIT_FAILURE);
}
// Generate ECC key pair
if (EC_KEY_generate_key(ec_key) != 1) {
fprintf(stderr, "Error generating ECC key pair\n");
EC_KEY_free(ec_key);
exit(EXIT_FAILURE);
}
//! Extract private key
const BIGNUM *private_key = EC_KEY_get0_private_key(ec_key);
write_hex_to_file("greater_snow_private_key_hex.txt", private_key);
//! Extract public key
const EC_POINT *public_key_point = EC_KEY_get0_public_key(ec_key);
const EC_GROUP *group = EC_KEY_get0_group(ec_key);
size_t buf_len = EC_POINT_point2oct(group, public_key_point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
printf("buf len is %ld\n", buf_len);
buf = (unsigned char *)malloc(buf_len);
int point_len = EC_POINT_point2oct(group, public_key_point, POINT_CONVERSION_UNCOMPRESSED, buf, buf_len, NULL);
printf("point_len is %d\n", point_len);
printf("Binary representation of the EC_POINT:\n");
for (size_t i = 0; i < buf_len; ++i) {
printf("%02X", buf[i]);
}
printf("\n");
BIGNUM *x = BN_new();
BIGNUM *y = BN_new();
EC_POINT_get_affine_coordinates_GFp(group, public_key_point, x, y, NULL);
write_hex_to_file("greater_snow_public_key_x_hex.txt", x);
write_hex_to_file("greater_snow_public_key_y_hex.txt", y);
//! Sign and verify a message
sign_and_verify(ec_key, "Hello, ECDSA!");
//! Test hex public key
greater_snow_test_public_key();
//! Clean up
free(buf);
BN_free(x);
BN_free(y);
EC_KEY_free(ec_key);
//! Clean up OpenSSL
EVP_cleanup();
return 0;
}
输出的16进制公钥中,第一个字节的04代表未压缩的意思。