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

C语言基于OpenSSL手动实现DES CBC模式输出异常与填充问题求助

问题修复方案

以下是针对你代码中现存问题的直接修复方案,覆盖输出不匹配、填充缺失、逻辑错误等所有核心问题:

现存致命问题列表

  • IV未正确初始化与传递:你在循环内定义roundOutput变量,既没有初始化为预设的IV值,每次加密后更新的也是局部变量,下一轮加密时上一轮的密文输出完全丢失,不符合CBC模式链式加密的要求
  • append函数逻辑完全错误:调用时传入的size参数为1,导致eight_bits数组只能存入1个字符,后续字符全部追加失败;且二进制数据不能用strlen计算长度,该函数完全不适用当前场景
  • feof接口误用:feof仅在读完文件最后一个字符后才会返回真,会导致你多读取一次EOF值存入缓冲区,引入无效字节
  • 填充逻辑缺失:最后不足8字节的块没有按照标准规则填充,导致加密块长度不一致,是输出不匹配的核心原因
  • 代码语法错误:doCBCenc函数的roundOutput参数为const类型,无法被修改更新;缺失printvalueOfDES_LONG函数定义,会导致链接失败
  • 缓冲区未初始化:eight_bits数组未初始化,首次调用strlen时返回值随机,进一步导致字符追加逻辑异常
修复后完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/des.h>
#include <sys/time.h>
#include <unistd.h>

#define ENC 1
#define DEC 0
#define BLOCK_SIZE 8

DES_key_schedule key;

// 调试用打印函数,可按需删除
void printvalueOfDES_LONG(DES_LONG *data) {
    for(int i=0; i<2; i++) {
        printf("%08lx ", data[i]);
    }
}

// 改为按字节异或,避免大小端兼容问题
void doBitwiseXor(unsigned char *xorValue, const unsigned char *data, const unsigned char *roundOutput) {
    for(int i=0; i<BLOCK_SIZE; i++) {
        xorValue[i] = data[i] ^ roundOutput[i];
    }
}

void doCBCenc(const unsigned char *data, unsigned char *roundOutput, FILE *outFile) {
    unsigned char in[BLOCK_SIZE];
    doBitwiseXor(in, data, roundOutput);

    DES_encrypt1((DES_LONG*)in, &key, ENC);

    printf("ENCRYPTED: ");
    printvalueOfDES_LONG((DES_LONG*)in);
    printf("\n");
    fwrite(in, BLOCK_SIZE, 1, outFile);

    memcpy(roundOutput, in, BLOCK_SIZE);
}

int main(int argc, char** argv)
{
    const_DES_cblock cbc_key = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
    const_DES_cblock IV = {0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
    // 保存上一轮加密输出,初始化为IV
    unsigned char last_block[BLOCK_SIZE];
    memcpy(last_block, IV, BLOCK_SIZE);

    struct timeval start, end;
    gettimeofday(&start, NULL);

    int l;
    if ((l = DES_set_key_checked(&cbc_key,&key)) != 0) {
        printf("\nkey error\n");
        return -1;
    }

    FILE *inpFile;
    FILE *outFile;
    // 二进制模式打开文件,避免换行符转换导致内容异常
    inpFile = fopen("test.txt", "rb");
    outFile = fopen("test_results.txt", "wb");

    if(inpFile && outFile) {
        unsigned char eight_bits[BLOCK_SIZE] = {0};
        int count = 0;
        int ch;

        while((ch = fgetc(inpFile)) != EOF) {
            printf("%c", (unsigned char)ch);
            eight_bits[count] = (unsigned char)ch;
            count++;

            if(count == BLOCK_SIZE) {
                printf("\n");
                doCBCenc(eight_bits, last_block, outFile);
                count = 0;
                memset(eight_bits, 0, BLOCK_SIZE);
            }
        }

        // PKCS#7填充逻辑,保证所有块大小为8字节
        int pad_len = BLOCK_SIZE - count;
        for(int i=count; i<BLOCK_SIZE; i++) {
            eight_bits[i] = pad_len;
        }
        doCBCenc(eight_bits, last_block, outFile);

    } else {
        printf("Error in opening file\n");
        return -1;
    }

    fclose(inpFile);
    fclose(outFile);

    gettimeofday(&end, NULL);
    long seconds = (end.tv_sec - start.tv_sec);
    long micros = ((seconds * 1000000) + end.tv_usec) - (start.tv_usec);
    printf("The elapsed time is %ld seconds and %ld microseconds\n", seconds, micros);

    return 0;
}
关键实现说明
  • 填充采用标准PKCS#7规则:若最后一个块剩余N个空位(1<=N<=8),则填充N个值为N的字节;若最后一个块刚好满8字节,则额外填充8个值为0x08的字节,解密时只要取最后一个字节的值,减去对应数量的填充字节即可还原原始内容
  • CBC模式链式逻辑已修复:上一轮加密的密文会作为下一轮的异或输入,首次加密使用预设IV做异或
  • 所有长度计数不再依赖字符串函数,直接通过count变量统计,兼容二进制内容加密

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 11:36:01