c++ openssl 使用ECC算法对大文件进行非对称加密和解密示例代码
时间: 2024-01-08 12:02:03 浏览: 260
以下是使用 OpenSSL 的 ECC 算法对大文件进行非对称加密和解密的示例代码:
加密:
```c++
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
int ecc_encrypt(const char *pubkey_file, const char *input_file, const char *output_file) {
EVP_PKEY *pubkey = NULL;
FILE *infile = NULL, *outfile = NULL;
EC_KEY *ec_key = NULL;
int ret = 0;
// 读取公钥
pubkey = EVP_PKEY_new();
if (!pubkey) {
fprintf(stderr, "Failed to create new EVP_PKEY\n");
goto cleanup;
}
infile = fopen(pubkey_file, "rb");
if (!infile) {
fprintf(stderr, "Failed to open pubkey file: %s\n", pubkey_file);
goto cleanup;
}
if (!PEM_read_PUBKEY(infile, &pubkey, NULL, NULL)) {
fprintf(stderr, "Failed to read pubkey from file: %s\n", pubkey_file);
ERR_print_errors_fp(stderr);
goto cleanup;
}
// 生成临时密钥对
ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (!ec_key) {
fprintf(stderr, "Failed to create new EC_KEY\n");
goto cleanup;
}
if (!EC_KEY_generate_key(ec_key)) {
fprintf(stderr, "Failed to generate EC key\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
// 构造密钥交换对象
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pubkey, NULL);
if (!pctx) {
fprintf(stderr, "Failed to create new EVP_PKEY_CTX\n");
goto cleanup;
}
if (EVP_PKEY_derive_init(pctx) <= 0) {
fprintf(stderr, "Failed to initialize EVP_PKEY_CTX\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
if (EVP_PKEY_derive_set_peer(pctx, pubkey) <= 0) {
fprintf(stderr, "Failed to set peer pubkey for EVP_PKEY_CTX\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
size_t len;
if (EVP_PKEY_derive(pctx, NULL, &len) <= 0) {
fprintf(stderr, "Failed to get derived key length\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
unsigned char *key = (unsigned char *) malloc(len);
if (!key) {
fprintf(stderr, "Failed to allocate memory for derived key\n");
goto cleanup;
}
if (EVP_PKEY_derive(pctx, key, &len) <= 0) {
fprintf(stderr, "Failed to derive key\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
EVP_PKEY_CTX_free(pctx);
pctx = NULL;
// 生成随机 IV
unsigned char iv[EVP_MAX_IV_LENGTH];
if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) <= 0) {
fprintf(stderr, "Failed to generate IV\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
// 加密
int block_size = EVP_CIPHER_block_size(EVP_aes_256_cbc());
unsigned char *in_buf = (unsigned char *) malloc(block_size);
unsigned char *out_buf = (unsigned char *) malloc(block_size + EVP_MAX_IV_LENGTH);
if (!in_buf || !out_buf) {
fprintf(stderr, "Failed to allocate memory for read/write buffer\n");
goto cleanup;
}
infile = fopen(input_file, "rb");
if (!infile) {
fprintf(stderr, "Failed to open input file: %s\n", input_file);
goto cleanup;
}
outfile = fopen(output_file, "wb");
if (!outfile) {
fprintf(stderr, "Failed to open output file: %s\n", output_file);
goto cleanup;
}
// 写入 IV 到输出文件
fwrite(iv, 1, EVP_MAX_IV_LENGTH, outfile);
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
fprintf(stderr, "Failed to create new EVP_CIPHER_CTX\n");
goto cleanup;
}
if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) <= 0) {
fprintf(stderr, "Failed to initialize encryption context\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
int bytes_read, bytes_written;
while ((bytes_read = fread(in_buf, 1, block_size, infile)) > 0) {
if (EVP_EncryptUpdate(ctx, out_buf, &bytes_written, in_buf, bytes_read) <= 0) {
fprintf(stderr, "Failed to encrypt data\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
fwrite(out_buf, 1, bytes_written, outfile);
}
if (EVP_EncryptFinal_ex(ctx, out_buf, &bytes_written) <= 0) {
fprintf(stderr, "Failed to finalize encryption\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
fwrite(out_buf, 1, bytes_written, outfile);
ret = 1;
cleanup:
if (pubkey) {
EVP_PKEY_free(pubkey);
}
if (infile) {
fclose(infile);
}
if (outfile) {
fclose(outfile);
}
if (ec_key) {
EC_KEY_free(ec_key);
}
if (pctx) {
EVP_PKEY_CTX_free(pctx);
}
if (key) {
free(key);
}
if (in_buf) {
free(in_buf);
}
if (out_buf) {
free(out_buf);
}
if (ctx) {
EVP_CIPHER_CTX_free(ctx);
}
return ret;
}
```
解密:
```c++
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
int ecc_decrypt(const char *privkey_file, const char *input_file, const char *output_file) {
EVP_PKEY *privkey = NULL;
FILE *infile = NULL, *outfile = NULL;
EC_KEY *ec_key = NULL;
int ret = 0;
// 读取私钥
privkey = EVP_PKEY_new();
if (!privkey) {
fprintf(stderr, "Failed to create new EVP_PKEY\n");
goto cleanup;
}
infile = fopen(privkey_file, "rb");
if (!infile) {
fprintf(stderr, "Failed to open privkey file: %s\n", privkey_file);
goto cleanup;
}
if (!PEM_read_PrivateKey(infile, &privkey, NULL, NULL)) {
fprintf(stderr, "Failed to read privkey from file: %s\n", privkey_file);
ERR_print_errors_fp(stderr);
goto cleanup;
}
// 构造密钥交换对象
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(privkey, NULL);
if (!pctx) {
fprintf(stderr, "Failed to create new EVP_PKEY_CTX\n");
goto cleanup;
}
if (EVP_PKEY_derive_init(pctx) <= 0) {
fprintf(stderr, "Failed to initialize EVP_PKEY_CTX\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
// 读取 IV
unsigned char iv[EVP_MAX_IV_LENGTH];
size_t iv_len = fread(iv, 1, EVP_MAX_IV_LENGTH, infile);
if (EVP_PKEY_derive_set_peer(pctx, EVP_PKEY_get1_EC_KEY(privkey)) <= 0) {
fprintf(stderr, "Failed to set peer pubkey for EVP_PKEY_CTX\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
size_t len;
if (EVP_PKEY_derive(pctx, NULL, &len) <= 0) {
fprintf(stderr, "Failed to get derived key length\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
unsigned char *key = (unsigned char *) malloc(len);
if (!key) {
fprintf(stderr, "Failed to allocate memory for derived key\n");
goto cleanup;
}
if (EVP_PKEY_derive(pctx, key, &len) <= 0) {
fprintf(stderr, "Failed to derive key\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
EVP_PKEY_CTX_free(pctx);
pctx = NULL;
// 解密
int block_size = EVP_CIPHER_block_size(EVP_aes_256_cbc());
unsigned char *in_buf = (unsigned char *) malloc(block_size + EVP_MAX_IV_LENGTH);
unsigned char *out_buf = (unsigned char *) malloc(block_size);
if (!in_buf || !out_buf) {
fprintf(stderr, "Failed to allocate memory for read/write buffer\n");
goto cleanup;
}
infile = fopen(input_file, "rb");
if (!infile) {
fprintf(stderr, "Failed to open input file: %s\n", input_file);
goto cleanup;
}
outfile = fopen(output_file, "wb");
if (!outfile) {
fprintf(stderr, "Failed to open output file: %s\n", output_file);
goto cleanup;
}
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
fprintf(stderr, "Failed to create new EVP_CIPHER_CTX\n");
goto cleanup;
}
if (EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) <= 0) {
fprintf(stderr, "Failed to initialize decryption context\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
int bytes_read, bytes_written;
while ((bytes_read = fread(in_buf, 1, block_size + iv_len, infile)) > 0) {
if (EVP_DecryptUpdate(ctx, out_buf, &bytes_written, in_buf + iv_len, bytes_read - iv_len) <= 0) {
fprintf(stderr, "Failed to decrypt data\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
fwrite(out_buf, 1, bytes_written, outfile);
memmove(iv, in_buf, iv_len);
}
if (EVP_DecryptFinal_ex(ctx, out_buf, &bytes_written) <= 0) {
fprintf(stderr, "Failed to finalize decryption\n");
ERR_print_errors_fp(stderr);
goto cleanup;
}
fwrite(out_buf, 1, bytes_written, outfile);
ret = 1;
cleanup:
if (privkey) {
EVP_PKEY_free(privkey);
}
if (infile) {
fclose(infile);
}
if (outfile) {
fclose(outfile);
}
if (ec_key) {
EC_KEY_free(ec_key);
}
if (pctx) {
EVP_PKEY_CTX_free(pctx);
}
if (key) {
free(key);
}
if (in_buf) {
free(in_buf);
}
if (out_buf) {
free(out_buf);
}
if (ctx) {
EVP_CIPHER_CTX_free(ctx);
}
return ret;
}
```
注意,在上述代码中,我们使用了“密钥交换”的方式来实现加密和解密。具体来说,我们先读取目标方(解密方)的公钥,然后生成一个临时的 ECC 密钥对,使用目标方的公钥和临时密钥对进行密钥交换,得到一个共享密钥,用这个共享密钥对大文件进行加密。解密时,我们读取自己的私钥,并使用共享密钥对大文件进行解密。这样做的好处是,即使黑客截获了加密后的文件和临时密钥对,也无法得到共享密钥,因为共享密钥是在密钥交换的过程中生成的,并不会被传输。
阅读全文