You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用C++和openssl库实现ES256算法加密数据

前置说明

首先明确:ES256是ECDSA签名算法的一种实现,基于P-256(secp256r1)椭圆曲线配合SHA256哈希,核心能力是对数据做签名/验签,实现防篡改、身份校验,不属于加密算法,无法直接用于数据加密解密。

实现步骤

1. 环境依赖

  • 安装OpenSSL 1.1.1及以上版本(低版本对EC算法API兼容性较差)
  • 编译时需要链接OpenSSL的crypto库,参数为 -lcrypto

2. 核心实现流程

2.1 生成P-256密钥对

首先需要生成ES256对应的EC密钥对,你可以选择直接用OpenSSL命令行生成pem文件,也可以代码动态生成:

命令行生成密钥对的方法:
生成私钥:openssl ecparam -name prime256v1 -genkey -noout -out ec_private.pem
导出公钥:openssl ec -in ec_private.pem -pubout -out ec_public.pem

2.2 数据签名流程

  • 加载P-256私钥
  • 对原始数据做SHA256哈希计算
  • 用私钥对哈希结果做ECDSA签名,输出DER编码或者raw(R+S)格式的签名结果

2.3 签名验证流程

  • 加载P-256公钥
  • 对原始数据做SHA256哈希计算
  • 用公钥验证哈希和收到的签名是否匹配
完整代码示例
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/sha.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <iostream>
#include <vector>
#include <cstring>

// 加载PEM格式的私钥
EC_KEY* load_private_key(const char* key_path) {
    FILE* fp = fopen(key_path, "r");
    if (!fp) return nullptr;
    EC_KEY* ec_key = PEM_read_ECPrivateKey(fp, nullptr, nullptr, nullptr);
    fclose(fp);
    return ec_key;
}

// 加载PEM格式的公钥
EC_KEY* load_public_key(const char* key_path) {
    FILE* fp = fopen(key_path, "r");
    if (!fp) return nullptr;
    EC_KEY* ec_key = PEM_read_EC_PUBKEY(fp, nullptr, nullptr, nullptr);
    fclose(fp);
    return ec_key;
}

// ES256签名
std::vector<unsigned char> es256_sign(EC_KEY* private_key, const unsigned char* data, size_t data_len) {
    std::vector<unsigned char> signature;
    if (!private_key || !data || data_len == 0) return signature;

    // 计算SHA256哈希
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256(data, data_len, hash);

    // 签名
    signature.resize(ECDSA_size(private_key));
    unsigned int sig_len = 0;
    if (ECDSA_sign(0, hash, SHA256_DIGEST_LENGTH, signature.data(), &sig_len, private_key) != 1) {
        signature.clear();
        return signature;
    }
    signature.resize(sig_len);
    return signature;
}

// ES256验签
bool es256_verify(EC_KEY* public_key, const unsigned char* data, size_t data_len, const unsigned char* sig, size_t sig_len) {
    if (!public_key || !data || data_len == 0 || !sig || sig_len == 0) return false;

    // 计算SHA256哈希
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256(data, data_len, hash);

    // 验签
    return ECDSA_verify(0, hash, SHA256_DIGEST_LENGTH, sig, sig_len, public_key) == 1;
}

int main() {
    // 初始化OpenSSL错误栈
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();

    // 测试数据
    const char* test_data = "Hello ES256 with OpenSSL!";
    size_t data_len = strlen(test_data);

    // 加载密钥
    EC_KEY* priv_key = load_private_key("ec_private.pem");
    EC_KEY* pub_key = load_public_key("ec_public.pem");
    if (!priv_key || !pub_key) {
        std::cerr << "Load key failed" << std::endl;
        return 1;
    }

    // 签名
    auto sig = es256_sign(priv_key, (const unsigned char*)test_data, data_len);
    if (sig.empty()) {
        std::cerr << "Sign failed" << std::endl;
        return 1;
    }
    std::cout << "Signature length: " << sig.size() << std::endl;

    // 验签
    bool verify_result = es256_verify(pub_key, (const unsigned char*)test_data, data_len, sig.data(), sig.size());
    std::cout << "Verify result: " << (verify_result ? "Success" : "Failed") << std::endl;

    // 释放资源
    EC_KEY_free(priv_key);
    EC_KEY_free(pub_key);
    EVP_cleanup();
    ERR_free_strings();

    return 0;
}

3. 编译与测试

  • 编译命令:g++ es256_demo.cpp -o es256_demo -lcrypto
  • 先按之前的OpenSSL命令生成公私钥文件放在同一目录,再运行编译后的二进制即可测试

4. 注意事项

  • 如果需要输出JWT规范里的raw格式签名(64字节,R占32字节+S占32字节),需要对DER编码的签名做解析,提取R和S字段拼接即可,不需要额外填充
  • 密钥加载的时候也可以直接加载内存里的密钥字符串,不需要读写文件,只需要把PEM_read_ECPrivateKey的FILE参数替换成BIO即可
  • 生产环境注意私钥的存储安全,禁止明文硬编码到代码或者配置文件里

内容的提问来源于stack exchange,提问作者Denis Butuzov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 22:51:01