程序中指针缺陷不清楚

时间:2014-06-06 09:21:57

标签: c++ gcc openssl des

我试图在openssl上构建使用DES CBC EDE的修改示例。我在ubuntu 10.04上使用gcc版本4.4.6(Buildroot 2012.02)编译arm(不是我的编译器选择)。这是一个问题:当指针声明被取消注释时 - 一切正常。测试消息解密。但是当指针声明被注释时 - 测试消息在解密后只显示2个第一个字母。我只是无法理解什么可以做一个未使用指针的声明。这是代码:

#include <openssl/des.h>
#include <cstring>

#define BUFSIZE 512

using namespace std;

int main(int argc, char *argv[]) {


    unsigned char in[BUFSIZE] = {};
    unsigned char out[BUFSIZE] = {};
    unsigned char back[BUFSIZE] = {};
    unsigned char *strangePointer = &out[0];  // what is wrong with it?
    int len;

    DES_cblock key1, key2, key3;
    DES_cblock ivsetup = {0xE1, 0xE2, 0xE3, 0xD4, 0xD5, 0xC6, 0xC7, 0xA8};
    DES_cblock ivecLocal;
    DES_key_schedule ks1, ks2, ks3;

    const char* key = "0A0A0B0B0C0C0A0A0B0B0C0C";

    memcpy(&key1,key,8);
    memcpy(&key2,key + 8,8);
    memcpy(&key2,key + 16,8);

    DES_set_odd_parity(&key1);
    DES_set_odd_parity(&key2);
    DES_set_odd_parity(&key3);

    DES_set_key((C_Block *)key1, &ks1);
    DES_set_key((C_Block *)key2, &ks2);
    DES_set_key((C_Block *)key3, &ks3);

    const char* message = "Now is the time for all men to stand up and be counted";
    /* 64 bytes of plaintext */
    len = strlen(message);
    memcpy(in,message,len);

    printf("Plaintext: [%s]\n", in);

    memcpy(ivecLocal, ivsetup, sizeof(ivsetup));
    DES_ede3_cbc_encrypt(in, out, len, &ks1, &ks2, &ks3, &ivecLocal, DES_ENCRYPT);

    int lenout = 0;
    while(out[lenout] != '\0') ++lenout;

    memcpy(ivecLocal, ivsetup, sizeof(ivsetup));
    DES_ede3_cbc_encrypt(out, back, lenout, &ks1, &ks2, &ks3, &ivecLocal, DES_DECRYPT);

    printf("Decrypted Text: [%s]\n", back);

    return 0;
}

2 个答案:

答案 0 :(得分:3)

您的代码中有几个不正确的内容。我先从简单的答案开始:

您的第三个密钥甚至没有填充关键数据。它是本地激活堆栈上的随机数据。

memcpy(&key1,key,8);
memcpy(&key2,key + 8,8);
memcpy(&key2,key + 16,8); // <<=== NOTE still key2

哦,复制粘贴,你们是一个残酷而无情的笨蛋。无论如何,通过删除你要注释的变量,这个键在内存中向上移动(或向下,取决于你的实现)堆栈,结果是一个不同的值。但最重要的是,你正在使用第三把钥匙的不确定数据。

但这不是整个问题。密钥的这种变化暴露了另一个问题,你是输出长度计算,这也是错误的。这样:

int lenout = 0;
while(out[lenout] != '\0') ++lenout;

假设通过搜索0字节可以找到输出密码的长度。 DES算法可以轻松地在加密块中的任何地方发送字节。这是完全错误的。 DES_ede3_cbc_encrypt加密操作的输出大小始终是块大小的倍数,对于DES是8个字节(不一定是DES_cblock的大小),输出缓冲区的正确计算大小是:

int lenout = ((len + sizeof(DES_cblock) - 1)/sizeof(DES_cblock))*sizeof(DES_cblock);

这可能看起来像一个helluva很多,但最后这一切都是四舍五入到块长度的最接近的倍数。此外,您甚至不需要 input缓冲区。如果您只是传递输入数据消息及其真实长度,API将为您进行计算。但是我留给你完成(提示:只需删除input并传递message)。

结果是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/des.h>

#define BUFSIZE 512

int main(int argc, char *argv[])
{
    unsigned char in[BUFSIZE] = {};
    unsigned char out[BUFSIZE] = {};
    unsigned char back[BUFSIZE] = {};
    int len;

    DES_cblock key1, key2, key3;
    DES_cblock ivsetup = {0xE1, 0xE2, 0xE3, 0xD4, 0xD5, 0xC6, 0xC7, 0xA8};
    DES_cblock ivecLocal;
    DES_key_schedule ks1, ks2, ks3;

    const char* key = "0A0A0B0B0C0C0A0A0B0B0C0C";

    memcpy(&key1,key,8);
    memcpy(&key2,key + 8,8);
    memcpy(&key3,key + 16,8);

    DES_set_odd_parity(&key1);
    DES_set_odd_parity(&key2);
    DES_set_odd_parity(&key3);

    DES_set_key(&key1, &ks1);
    DES_set_key(&key2, &ks2);
    DES_set_key(&key3, &ks3);

    const char* message = "Now is the time for all men to stand up and be counted";
    len = strlen(message);
    memcpy(in,message,len);

    printf("Plaintext: [%s]\n", in);

    memcpy(ivecLocal, ivsetup, sizeof(ivsetup));
    DES_ede3_cbc_encrypt(in, out, len, &ks1, &ks2, &ks3, &ivecLocal, DES_ENCRYPT);

    int lenout = ((len + sizeof(DES_cblock) - 1)/sizeof(DES_cblock))*sizeof(DES_cblock);

    memcpy(ivecLocal, ivsetup, sizeof(ivsetup));
    DES_ede3_cbc_encrypt(out, back, lenout, &ks1, &ks2, &ks3, &ivecLocal, DES_DECRYPT);

    printf("Decrypted Text: [%s]\n", back);

    return 0;
}

<强>输出

Plaintext: [Now is the time for all men to stand up and be counted]
Decrypted Text: [Now is the time for all men to stand up and be counted]

答案 1 :(得分:0)

您很可能遇到缓冲区溢出。 len的声明出现在堆栈上的back之后。如果back溢出,则len将被覆盖。在中间添加另一个变量(strangePointer)会在堆栈上添加一个间隙,阻止len被覆盖。

可能会增加BUFSIZE来解决您的问题。