Linux openssl ecc prime256v1签名与验签(可以输出16进制公钥)

本文介绍了椭圆曲线密码体制(ECC)的基础概念,离散对数问题的应用,以及如何使用OpenSSL进行ECDSA签名和验证。文章通过代码示例展示了如何生成和操作ECC密钥对。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

于是月亮的含义不仅仅在是月亮!!!!!!

椭圆曲线密码体制(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代表未压缩的意思。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值