Я пытаюсь построить модифицированный пример использования DES CBC EDE на openssl. Я использую gcc версии 4.4.6 (Buildroot 2012.02) для компиляции arm (не мой выбор компилятора) в ubuntu 10.04. Вот проблема: когда объявление указателя не закомментировано — все нормально. Тестовое сообщение расшифровывается. Но когда объявление указателя комментируется — тестовое сообщение показывает только 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;
}
В вашем коде есть несколько неверных вещей. Сначала я начну с простого ответа:
Ваш третий ключ даже не заполнен ключевыми данными. Это случайные данные в локальном стеке активации.
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);
что может показаться чертовски большим, но в итоге все это округляется до ближайшего кратного длины блока. Кроме того, вы даже не необходимость 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]
Вы, скорее всего, испытываете переполнение буфера. Декларация len
идет после back
в стеке. Если back
переполняет, затем len
будет перезаписано Добавление другой переменной (strangePointer
) между ними добавляет пробел в стеке, который останавливает перезапись len.
Вероятно, увеличивается BUFSIZE
должен решить вашу проблему.