调用 OpenSSL DES_cbc_encrypt() 时堆栈损坏

Stack corruption upon calling OpenSSL DES_cbc_encrypt()

这是使用 DES 加密 struct 的代码,然后在写入 File 后读回:

#include "openssl/des.h"
#include "openssl/conf.h"
#include "openssl/evp.h"
#include "openssl/err.h"
#include <stdio.h>


typedef struct MyStruct_t
{
        char m_Name[32];
        char m_ID[16];
} MyStruct;


uint8_t* __stdcall myStructToBytes(const MyStruct * const iMyStruct)
{
    const size_t len = sizeof(MyStruct;
    uint8_t *buffer = (uint8_t*) malloc(len);

    memcpy(buffer, iMyStruct, len);
    return buffer;
}

const int __stdcall encodeMyStructToFile(const char *sOutputFilename,
                                                         const char *sKey, const MyStruct *iStruct)
{
    DES_cblock key, iv;
    DES_key_schedule schedule;
    unsigned char *data = myStructToBytes((const MyStruct * const)iStruct);
    long len = sizeof(MyStruct);
    int ret = 0;

    memcpy(key, &sKey[0], 8);
    memcpy(iv, &sKey[0], 8);
    DES_set_odd_parity(&key);
    ret = DES_set_key_checked(&key, &schedule);

    if(ret == 0) {
        FILE *write_ptr;
        unsigned char *encrypted = (unsigned char *)malloc(len);
        DES_cbc_encrypt(data, encrypted, len, &schedule, &iv, DES_ENCRYPT);

        // Write encrypted data to file...
        fopen_s(&write_ptr, sOutputFilename, "wb");
        fwrite(encrypted, len, 1, write_ptr);
        fclose(write_ptr);
        free(encrypted);
    }
    free(data);

    return ret;
}


const int __stdcall decodeMyStructFromFile(const char *sInputFilename,
           const char *sKey, MyStruct *oStruct)
{
    int ret = 0;
    DES_cblock key, iv;
    DES_key_schedule schedule;
    FILE *read_ptr;
    long len = 0;
    unsigned char *encrypted = NULL;

    // Read encrypted data from file...
    fopen_s(&read_ptr, sInputFilename, "rb");
    ret = fseek(read_ptr, 0L, SEEK_END);
    len = ftell(read_ptr);
    rewind(read_ptr);
    encrypted = (unsigned char *)malloc(len);
    fread(encrypted, len, 1, read_ptr);
    fclose(read_ptr);

    // Perform decryption...
    memcpy(key, &sKey[0], 8);
    memcpy(iv, &sKey[0], 8);
    DES_set_odd_parity(&key);
    ret = DES_set_key_checked(&key, &schedule);

    if(ret == 0) {
        DES_cbc_encrypt(encrypted, (unsigned char *)oStruct, len, &schedule, &iv, DES_DECRYPT);
    }
    free(encrypted);

    return ret;
}

int main() {
    MyStruct tMyStruct;
    MyStruct tMyStruct1;
    char outputFilename[] = "abcd.bin";
    char key[] = "key_to_file";

    memset(&tMyStruct, 0, sizeof(MyStruct));
    memcpy_s(tMyStruct.m_Name, 256, "Hello", 5);
    memcpy_s(tMyStruct.m_ID, 32, "1234567890", 10);

    encodeMyStructToFile((const char *)outputFilename, (const char *)key, (const MyStruct * const)&tMyStruct);

    decodeLicenseStructFromFile(outputFilename, key, &tMyStruct1);


    return 0;
}

不知何故,我在调试器中遇到加密和解密函数的堆栈损坏错误。我追查了 DES_cbc_encrypt() 附近的问题。我究竟做错了什么?我正在为 OpenSSL 使用已编译的二进制文件:openssl-1.1.0e-vs2012 on 64-bit.

我之所以回到这里,是因为我注意到(虽然不能从示例代码中产生),DES_cbc_encrypt()DES_cbc_decrypt() 函数都需要 8-byte aligned 输入。因此在不幸的情况下,如果这里的结构体的大小不是 8 的倍数,DES_cbc_encrypt() 将写入超过缓冲区的末尾,因此明显的堆栈损坏。虽然,当未明确禁用填充时,sizeof() 仍然是 returns 成员大小的总和,所以我理解这种情况是应用程序程序员的任务。也许有人可以对此进行更多阐述。