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

使用OpenSSL库AES-128-CBC加密118字节私钥存为PEM格式遇异常

解决AES-128-CBC加密EC私钥后PEM内容过短的问题

从你给出的PEM输出来看,加密后的私钥内容只有nTrb9AN15PVFbZfqPdwKAQ==,Base64解码后仅18字节,这显然和118字节原始私钥的加密预期长度不符。核心问题是你没有正确传入完整的私钥数据进行加密,以下是具体分析和解决步骤:

问题根源拆解

正常情况下,118字节的EC私钥(SEC1格式DER编码)经过AES-128-CBC加密(PKCS#7填充)后,密文长度应为128字节(118字节+10字节填充),Base64编码后会生成约172个字符的内容(分3行,每行64字符)。而你的输出仅对应18字节密文,说明:

  • 待加密的数据不是完整的118字节私钥,仅传入了16-18字节的片段(比如错误截取了私钥的某部分,或误传了IV值)
  • 可能存在代码中数据截断、指针错误,或未正确封装私钥ASN.1结构的问题
  • PEM结尾的\xad是多余字符,属于字符串处理时的内存溢出或拼接错误

正确的加密流程(命令行+代码两种方式)

方式1:用OpenSSL命令行快速验证

如果是用命令行处理原始118字节私钥,直接执行以下命令即可生成标准加密PEM:

# 假设你的原始私钥是raw_ec.key(118字节DER格式)
openssl ec -in raw_ec.key -inform der -out encrypted.pem -aes-128-cbc

这个命令会自动完成:私钥ASN.1结构验证→PKCS#8封装→AES-128-CBC加密(带PKCS#7填充)→Base64编码→PEM格式封装,生成的PEM内容长度会符合预期。

方式2:C语言代码实现(基于OpenSSL库)

如果是自己写代码实现,务必确保传入完整的私钥数据,并利用OpenSSL的封装API避免手动加密出错:

#include <openssl/ec.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <stdio.h>
#include <string.h>

int encrypt_ec_key(const unsigned char *raw_der, size_t raw_len, const char *pass, char **pem_buf, size_t *pem_len) {
    // 1. 解析原始SEC1格式私钥为EC_KEY对象
    EC_KEY *ec_key = d2i_ECPrivateKey(NULL, &raw_der, raw_len);
    if (!ec_key) {
        fprintf(stderr, "Failed to parse EC private key\n");
        return -1;
    }

    // 2. 生成AES-128-CBC所需的16字节随机IV
    unsigned char iv[16];
    if (!RAND_bytes(iv, sizeof(iv))) {
        EC_KEY_free(ec_key);
        fprintf(stderr, "Failed to generate IV\n");
        return -1;
    }

    // 3. 自动完成PKCS#8封装+AES加密,生成加密后的DER数据
    unsigned char *encrypted_der = NULL;
    int der_len = i2d_PKCS8PrivateKeyInfo(
        ec_key, &encrypted_der,
        pass, strlen(pass),
        NULL, NULL // 默认用PKCS#5 v2.0密码推导,AES-128-CBC加密
    );
    EC_KEY_free(ec_key);
    if (der_len <= 0) {
        fprintf(stderr, "Failed to encrypt private key\n");
        return -1;
    }

    // 4. 构造标准PEM格式内容
    BIO *bio = BIO_new(BIO_s_mem());
    if (!bio) {
        OPENSSL_free(encrypted_der);
        return -1;
    }

    // 写入PEM头部
    BIO_printf(bio, "-----BEGIN EC PRIVATE KEY-----\n");
    BIO_printf(bio, "Proc-Type: 4,ENCRYPTED\n");
    char iv_hex[33] = {0};
    for (int i = 0; i < 16; i++) {
        sprintf(iv_hex + 2*i, "%02X", iv[i]);
    }
    BIO_printf(bio, "DEK-Info: AES-128-CBC,%s\n\n", iv_hex);

    // Base64编码加密后的DER数据(每行64字符)
    BIO *b64 = BIO_new(BIO_f_base64());
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); // 手动控制换行
    bio = BIO_push(b64, bio);
    
    const int line_len = 64;
    size_t remaining = der_len;
    const unsigned char *ptr = encrypted_der;
    while (remaining > 0) {
        size_t write_len = remaining > line_len ? line_len : remaining;
        BIO_write(bio, ptr, write_len);
        BIO_write(bio, "\n", 1);
        ptr += write_len;
        remaining -= write_len;
    }
    BIO_flush(bio);
    BIO_pop(b64);
    BIO_free(b64);

    // 写入PEM尾部
    BIO_printf(bio, "-----END EC PRIVATE KEY-----");

    // 提取PEM内容到内存
    *pem_len = BIO_get_mem_data(bio, pem_buf);
    char *tmp = OPENSSL_malloc(*pem_len + 1);
    memcpy(tmp, *pem_buf, *pem_len);
    tmp[*pem_len] = '\0';
    *pem_buf = tmp;

    // 清理资源
    BIO_free(bio);
    OPENSSL_free(encrypted_der);
    return 0;
}

关键排查点

  1. 验证原始私钥格式:用openssl ec -in raw_ec.key -inform der -text检查118字节私钥是否为合法的SEC1格式DER编码,确保结构完整。
  2. 检查待加密数据长度:代码中务必确认传入加密函数的是完整的118字节私钥(或封装后的PKCS#8 DER数据),避免指针偏移、数组越界导致的数据截断。
  3. 移除多余字符:PEM结尾的\xad是无效字符,需检查字符串拼接或内存拷贝逻辑,确保只写入标准PEM头部、Base64内容和尾部。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:34:47