Шифрование и дешифрование сообщения с помощью Blowfish

Вот базовый код шифрования и дешифрования сообщения:

#include <stdio.h>
#include <openssl/blowfish.h>
#include <string.h>

//gcc cryptage.c -o cryptage -lcrypto

int main(){

BF_KEY *key = malloc(sizeof(BF_KEY));

unsigned char *crypt_key = "Key of encryption";
const unsigned char *in = "Message to encrypt";
int len = strlen(crypt_key);
unsigned char *out = malloc(sizeof(char)*len);
unsigned char *result = malloc(sizeof(char)*len);


//Defining encryption key
BF_set_key(key, len, crypt_key);

//Encryption
BF_ecb_encrypt(in, out, key, BF_ENCRYPT);

//Décryption
BF_ecb_encrypt(out, result, key, BF_DECRYPT);

fprintf(stdout,"Result: %s\n",result);

return 0;

}

Моя проблема в том, какой результат я получаю. Это всегда строка из 8 символов, не более. Не могли бы вы помочь мне зашифровать и расшифровать полное сообщение?

Спасибо!


person HaTiMuX    schedule 21.11.2013    source источник
comment
Я начал печатать ответ дважды и пришел к выводу, что слишком много вещей нужно анализировать, поэтому я просто скажу это. Blowfish — это симметричный блочный шифр. Он работает с фрагментами размером с блок. Вы шифруете один блок (размер блока BF по умолчанию равен 8 байтам; 64 бита), а затем расшифровываете эти байты в другой буфер. Таким образом, вы получаете только первые 8 байтов.   -  person WhozCraig    schedule 22.11.2013
comment
Согласно BF_encrypt справочной странице: BF_encrypt() и BF_decrypt() функции самого низкого уровня для шифрования Blowfish. Они шифруют/дешифруют первые 64 бита вектора, на который указывают данные, используя ключевой ключ. Эти функции не следует использовать, если вы не реализуете «режимы» Blowfish. Альтернативой является использование BF_ecb_encrypt(). Если вы все еще хотите использовать эти функции, вы должны знать, что они принимают каждый 32-битный фрагмент в порядке хост-байтов, который является прямым на платформах с прямым порядком байтов и прямым порядком байтов на платформах с прямым порядком байтов .   -  person jww    schedule 31.05.2017


Ответы (1)


Как говорит @WhozCraig, выполняйте действия по 8 байтов за раз.

Шифруемые данные следует рассматривать как массив байтов, а не как строку C.
Итак, рассмотрите строку для шифрования с помощью \0 и дополненную случайными данными, чтобы сформировать массив байтов, который является кратным из 8.
Вызовите шифрование несколько раз, шифруя 8 байтов за итерацию.

Чтобы расшифровать, вызовите расшифровку такое же количество итераций. Обратите внимание, что размер буфера результатов может быть кратен 8.

const unsigned char *in = "Message to encrypt";
size_t InSize = strlen(in) + 1;
int KeyLen = strlen(crypt_key);
size_t OutSize = (InSize + 7) & (~7);
unsigned char *out = malloc(Outsize);
unsigned char *outnext = out;
//Defining encryption key
BF_set_key(key, KeyLen, crypt_key);

//Encryption
while (InSize >= 8) {    
  BF_ecb_encrypt(in, outnext, key, BF_ENCRYPT);
  in += 8;
  outnext += 8;
  InSize -= 8;
}
if (Insize > 0) {  // Cope with non-octal length
  unsigned char buf8[8];
  memcpy(buf8, in, InSize);
  for (i=InSize; i<8; i++) {
    buf8[i] = rand();
  }  
  BF_ecb_encrypt(buf8, outnext, key, BF_ENCRYPT);
}

//Décryption
unsigned char *result = malloc(OutSize);
unsigned char *resultNext = result;
while (OutSize) {
  BF_ecb_encrypt(out, resultNext, key, BF_DECRYPT);
  out += 8;
  resultNext += 8;
  OutSize -= 8;
}

fprintf(stdout,"Result: %s\n",result);
// No need to print the random bytes that were generated.
return 0;
}

Не совсем удобно иметь известный байт (\0), закодированный в последнем блоке. Индикация другой длины может быть разумной.

person chux - Reinstate Monica    schedule 22.11.2013
comment
+1 По иронии судьбы, вы всего в нескольких шагах от того, чтобы сделать эту прокладку PKCS15 совместимой. Если вы установите в памяти завершающие нечетные байты блока со значением байта, которое представляет собой количество неиспользуемых байтов (скажем, у вас было три коротких, это будет 0x03, 0x03, 0x03), tt позволит дешифратору узнать, сколько байтов было в исходном < i>настоящий открытый текст. Примечание: если вы делаете это, вы должны учитывать возможность того, что исходный открытый текст будет точно кратным размеру блока, и в этом случае вы должны добавить один полный блок набивки; вы не можете опускать отступы никогда. хороший ответ. - person WhozCraig; 22.11.2013
comment
@WhozCraig Не трать слишком много на прокладку PKCS15, но почему 0x03, 0x03, 0x03? Почему не Rand(), Rand(), 0x03? Также я предполагаю, что значение пэда от 1 до 8? Интересно, почему не от 0 до 7 с 5 MSBits/байт случайным образом? - person chux - Reinstate Monica; 22.11.2013
comment
Это часть спецификации алгоритма заполнения. Это один из методов проверки. Помогите, я нащупал неправильную спецификацию. на самом деле его 7. см. это описание вместе с множеством других алгоритмов. сори за неточность. и вам действительно не нужны случайные данные, честно говоря, потому что, если бы вы это сделали, этот алгоритм не был бы вашим слабым звеном в первую очередь (и это не так; вызывающий должен использовать режим cbc; ни один здравомыслящий человек не использует ecb больше). - person WhozCraig; 22.11.2013
comment
Спасибо, ребята. Это очень полезно :) Один вопрос: size_t OutSize = (InSize + 7) & (~7); Я не понял, что означает выделенное жирным шрифтом? - person HaTiMuX; 23.11.2013
comment
@HaTiMuX 7 в двоичном формате равен 000...000111, все старшие значащие биты равны 0, кроме 3 младших битов, которые равны 1. ~7 равно 111...111000, все старшие значащие биты равны 1, кроме 3 младших битов, которые равны 1. 0. (~7) просто для ясности порядка оценки. С помощью (InSize + 7) и 111...111000 младшие 3 бита суммы очищаются. Вам может больше понравиться ((InSize + 7)/8)*8 - аналогичный эффект. Существуют и другие формы. - person chux - Reinstate Monica; 23.11.2013
comment
Хорошо, сейчас я понимаю. Большое спасибо :) - person HaTiMuX; 24.11.2013