如何从DER或PEM格式的ECC私钥文件中提取OCTET STRING的字符数组或字节数组
Hey there! I’ve worked with OpenSSL’s ECC APIs quite a bit, so let’s break down how to grab that OCTET STRING value you need from your ECC private key file.
First, let’s clarify what that OCTET STRING represents: it’s the raw private key value for your ECC curve (in your case, secp256r1, since the OID 1.2.840.10045.3.1.7 maps directly to this curve). When you use PEM_read_ECPrivateKey or d2i_ECPrivateKey, OpenSSL parses the DER/PEM into an EC_KEY struct, and we can extract the raw private key straight from there.
Step 1: Load the DER/PEM file into an EC_KEY structure
First, we need to get your key file into OpenSSL’s native EC_KEY type. Here’s how to handle both formats:
For PEM files:
#include <openssl/ec.h> #include <openssl/pem.h> #include <openssl/bn.h> EC_KEY *load_pem_ecc_key(const char *file_path) { FILE *fp = fopen(file_path, "r"); if (!fp) return NULL; EC_KEY *key = PEM_read_ECPrivateKey(fp, NULL, NULL, NULL); fclose(fp); return key; }
For DER files:
EC_KEY *load_der_ecc_key(const char *file_path) { FILE *fp = fopen(file_path, "rb"); if (!fp) return NULL; EC_KEY *key = d2i_ECPrivateKey_fp(fp, NULL); fclose(fp); return key; }
Step 2: Extract the raw private key (OCTET STRING) from EC_KEY
The private key is stored as a BIGNUM inside the EC_KEY struct. We can grab a pointer to it with EC_KEY_get0_private_key(), then convert it to either a hex string or byte array as you need.
Option 1: Get the private key as a hex string (matches your first output format)
char *get_ecc_private_key_hex(EC_KEY *key) { if (!key) return NULL; const BIGNUM *priv_key = EC_KEY_get0_private_key(key); if (!priv_key) return NULL; // Convert BIGNUM to a hex string (matches your ASN.1 OCTET STRING value) char *hex_str = BN_bn2hex(priv_key); return hex_str; // Don't forget to free this with OPENSSL_free() later! }
Option 2: Get the private key as a byte array (matches your second output format)
unsigned char *get_ecc_private_key_bytes(EC_KEY *key, size_t *out_len) { if (!key || !out_len) return NULL; const BIGNUM *priv_key = EC_KEY_get0_private_key(key); if (!priv_key) return NULL; // Calculate the required length for the byte array int key_len = BN_num_bytes(priv_key); if (key_len <= 0) return NULL; unsigned char *key_bytes = OPENSSL_malloc(key_len); if (!key_bytes) return NULL; // Write the BIGNUM to the byte array in big-endian order (standard for ECC) BN_bn2bin(priv_key, key_bytes); *out_len = key_len; return key_bytes; // Remember to free this with OPENSSL_free()! }
Step 3: Full Working Example
Here’s a complete snippet that loads a DER file, extracts both formats, and prints them out:
#include <stdio.h> #include <openssl/ec.h> #include <openssl/pem.h> #include <openssl/bn.h> #include <openssl/crypto.h> int main() { const char *der_file = "your_private_key.der"; EC_KEY *key = load_der_ecc_key(der_file); if (!key) { printf("Failed to load DER key\n"); return 1; } // Print hex string format char *hex_key = get_ecc_private_key_hex(key); if (hex_key) { printf("// Hex string format\n"); printf("privatekey = \"%s\";\n", hex_key); OPENSSL_free(hex_key); } // Print byte array format size_t byte_len; unsigned char *byte_key = get_ecc_private_key_bytes(key, &byte_len); if (byte_key) { printf("\n// Byte array format\n"); printf("privatekey = {"); for (size_t i = 0; i < byte_len; i++) { if (i > 0) printf(","); printf("0x%02X", byte_key[i]); } printf("};\n"); OPENSSL_free(byte_key); } EC_KEY_free(key); return 0; }
Key Notes:
- The hex string from
BN_bn2hex()will match exactly the OCTET STRING value from your ASN.1 decoder (in your case,61300E611C121ECBE7C2D49DA8FCD99571DF00296F51C3A9EC02DFF3063DBD3E). - The byte array uses big-endian order, which is the standard format for ECC private keys and works seamlessly with PKCS#11 imports later.
- Always clean up allocated memory with
OPENSSL_free()andEC_KEY_free()to avoid leaks.
内容的提问来源于stack exchange,提问作者danielsun

