• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
mankun
博客园    首页    新随笔    联系   管理    订阅  订阅

【C】openssl库中des/3des的EVP接口使用

openssl库中des/3des的EVP接口使用

evp函数介绍

  • EVP_CIPHER_CTX_new
    功能:用于创建和初始化加解密上下文

  • EVP_DecryptInit_ex
    功能:初始化加解密操作

  • EVP_CIPHER_CTX_set_padding
    功能:启用或禁用填充
    参数:

    • 0:禁用填充
    • 1:启用填充,默认是PKCS7方式
  • EVP_DecryptUpdate
    功能:执行加解密

  • EVP_DecryptFinal_ex
    功能:填充额外数据

  • EVP_CIPHER_CTX_free
    功能:释放加解密上下文

代码实现

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/provider.h>

/*
 * 使用指南:
 * 1. 确保已安装OpenSSL 3.6或更高版本,并且包含legacy provider以支持DES算法。
 * 2. 编译命令示例:
 *  gcc des_example.c -o des_example -w -lssl -lcrypto
 * 3. 运行程序:
 *  ./des_example
 */

typedef enum {
    DES_CBC,        // 单DES CBC模式
    DES3_CBC_2KEY,  // 双重DES CBC模式
    DES3_CBC_3KEY   // 三重DES CBC模式
} DesCryptoMode;

typedef enum {
    PADDING_NONE,   // 无填充
    PADDING_PKCS7,  // PKCS7填充
    PADDING_ZERO    // 零填充
} DesPaddingMode;

// 初始化OpenSSL库
int init_openssl()
{
    // 加载遗留provider以支持DES 3DES算法
    if (OSSL_PROVIDER_load(NULL, "legacy") == NULL) {
        fprintf(stderr, "Failed to load legacy provider\n");
        return -1;
    }

    if (OSSL_PROVIDER_load(NULL, "default") == NULL) {
        fprintf(stderr, "Failed to load default provider\n");
        return -1;
    }
    return 0;
}

// 打印十六进制数据
void print_hex(const char *label, const unsigned char *data, int len)
{
    printf("%s: ", label);
    for (int i = 0; i < len; i++) {
        printf("%02X", data[i]);
    }
    printf("\n");
}

EVP_CIPHER *get_cipher(DesCryptoMode mode)
{
    switch (mode) {
        case DES_CBC:
            return EVP_des_cbc();
        case DES3_CBC_2KEY:
            return EVP_des_ede_cbc();
        case DES3_CBC_3KEY:
            return EVP_des_ede3_cbc();
        default:
            return NULL;
    }
}  

// DES加密函数
int des_encrypt(const unsigned char *plaintext, int plaintext_len,
                const unsigned char *key, const unsigned char *iv,
                unsigned char *ciphertext, int *ciphertext_len,
                DesCryptoMode mode, DesPaddingMode padding)
{
    EVP_CIPHER_CTX *ctx = NULL;
    int len = 0;
    int total_len = 0;

    // 检查数据长度是否为8的倍数(DES块大小)
    if (plaintext_len % 8 != 0) {
        fprintf(stderr, "Data length must be multiple of 8 bytes for no padding\n");
        return -1;
    }

    // 创建并初始化加密上下文
    ctx = EVP_CIPHER_CTX_new();
    if (ctx == NULL) {
        fprintf(stderr, "Failed to create cipher context\n");
        return -1;
    }

    EVP_CIPHER *cipher = get_cipher(mode);

    // 初始化DES CBC加密操作
    if (EVP_EncryptInit_ex(ctx, EVP_des_cbc(), NULL, key, iv) != 1) {
        fprintf(stderr, "Failed to initialize encryption\n");
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }

    // 禁用填充
    EVP_CIPHER_CTX_set_padding(ctx, padding == PADDING_NONE ? 0 : 1);

    // 执行加密
    if (EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len) != 1) {
        fprintf(stderr, "Failed to encrypt data\n");
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }

    total_len = len;
    // 对于无填充模式,Final操作通常不会产生额外数据
    if (EVP_EncryptFinal_ex(ctx, ciphertext + len, &len) != 1) {
        fprintf(stderr, "Failed to finalize encryption\n");
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }

    total_len += len;
    *ciphertext_len = total_len;
    EVP_CIPHER_CTX_free(ctx);
    return 0;
}

// DES解密函数
int des_decrypt(const unsigned char *ciphertext, int ciphertext_len,
                const unsigned char *key, const unsigned char *iv,
                unsigned char *plaintext, int *plaintext_len,
                DesCryptoMode mode, DesPaddingMode padding)
{
    EVP_CIPHER_CTX *ctx;
    int len;
    int total_len = 0;

    // 检查数据长度是否为8的倍数
    if (ciphertext_len % 8 != 0) {
        fprintf(stderr, "Ciphertext length must be multiple of 8 bytes\n");
        return -1;
    }

    // 创建并初始化解密上下文
    ctx = EVP_CIPHER_CTX_new();
    if (ctx == NULL) {
        fprintf(stderr, "Failed to create cipher context\n");
        return -1;
    }

    // 初始化DES CBC解密操作
    if (EVP_DecryptInit_ex(ctx, EVP_des_cbc(), NULL, key, iv) != 1) {
        fprintf(stderr, "Failed to initialize decryption\n");
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }

    // 禁用填充
    EVP_CIPHER_CTX_set_padding(ctx, padding == PADDING_NONE ? 0 : 1);

    // 执行解密
    if (EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len) != 1) {
        fprintf(stderr, "Failed to decrypt data\n");
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }

    total_len = len;
    // 对于无填充模式 final操作通常不会产生额外数据
    if (EVP_DecryptFinal_ex(ctx, plaintext + len, &len) != 1) {
        fprintf(stderr, "Failed to finalize decryption\n");
        EVP_CIPHER_CTX_free(ctx);
        return -1;
    }

    total_len += len;
    *plaintext_len = total_len;
    EVP_CIPHER_CTX_free(ctx);
    return 0;
}

int main(void)
{
    // 初始化OpenSSL
    if (init_openssl() != 0) {
        fprintf(stderr, "OpenSSL initialization failed\n");
        return 1;
    }

    // 示例数据
    // 明文数据长度必须是8的倍数(DES块大小)
    unsigned char *plaintext = "12345678";

    // 密钥长度必须大于等于8字节 DES使用前8字节
    unsigned char *key = "123456781234567812345678";

    // 初始向量IV可以为NULL 表示全0初始化向量
    // unsigned char *iv = NULL;
    unsigned char *iv = "00000000";

    DesCryptoMode mode = DES3_CBC_3KEY;
    DesPaddingMode padding = PADDING_NONE;

    unsigned char ciphertext[8];
    unsigned char decrypted[8];
    int ciphertext_len, decrypted_len;
    int plaintext_len = strlen(plaintext);

    printf("=== OpenSSL 3.6 DES CBC 无填充 EVP示例 ===\n");
    printf("明    文: %s\n", plaintext);
    printf("明文长度: %d\n", plaintext_len);
    printf("密    钥: %s\n", plaintext);
    printf("初始向量: %s\n", iv == NULL ? "NULL" : iv);

    // 加密
    printf("\n--- 加密过程 ---\n");
    if (des_encrypt(plaintext, plaintext_len, key, iv, ciphertext, &ciphertext_len, mode, padding) == 0) {
        printf("加密成功\n");
        print_hex("密文", ciphertext, ciphertext_len);

        // 解密
        printf("\n--- 解密过程 ---\n");
        if (des_decrypt(ciphertext, ciphertext_len, key, iv, decrypted, &decrypted_len, mode, padding) == 0) {
            printf("解密成功\n");
            printf("解密数据: %s\n", decrypted);

            // 验证结果
            printf("\n--- 验证结果 ---\n");
            if (memcmp(plaintext, decrypted, plaintext_len) == 0) {
                printf("✓ 加密解密验证成功!\n");
            } else {
                printf("✗ 加密解密验证失败!\n");
            }
        } else {
            printf("解密失败\n");
        }
    } else {
        printf("加密失败\n");
    }

    return 0;
}

posted @ 2025-11-29 20:44  小小船帆  阅读(2)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3