Расшифровка сгенерированной библиотекой openssl шифра на терминале и наоборот - PullRequest
1 голос
/ 04 июня 2019

Я сделал реализацию, используя библиотеку OpenSSL для шифрования пароля. Я могу успешно зашифровать и расшифровать пароль, используя библиотеку в коде.

Однако, если я пытаюсь расшифровать шифр, сгенерированный библиотекой в ​​системе linux на терминале, дешифрование завершится неудачей.

Шифрование:

openssl enc -aes-256-cbc -base64 -salt -k <passphrase> -in plain.txt -out 
encrypt.txt

дешифрование:

openssl enc -aes-256-cbc -base64 -salt -d -k <passphrase> -in encrypt.txt -out plain.txt

Пожалуйста, помогите.

Я удалил соли, чтобы сделать процесс проще. Я сгенерировал образцы шифров base64 на терминале и попытался расшифровать их с помощью библиотеки, это не удалось. Я попытался сгенерировать образцы шифров base64 с библиотекой и попытался расшифровать их в терминале, это тоже не получается!

size_t init_key_iv(const std::string& pass, const unsigned char* salt, unsigned char* key, unsigned char* iv ) {
size_t derived_key_size = 0;
  const unsigned char * pass_key = reinterpret_cast<const unsigned char*>( pass.c_str() );
  const size_t pass_key_len = pass.size();
  if(salt && key && iv && pass_key && pass_key_len > 0) {
    memset(key, 0, sizeof(key));
    memset( iv, 0, sizeof(iv));
    derived_key_size = EVP_BytesToKey(cipher_type, msg_digest_type, salt, pass_key, pass_key_len, 5, key, iv);
  }
 return derived_key_size;
}

void encrypt(const unsigned char* msg, unsigned char** encrypted_message, const size_t msg_len, const unsigned char *key, unsigned char *iv) {
    AES_KEY enc_key;
    AES_set_encrypt_key(key, 256, &enc_key);
    AES_cbc_encrypt(msg, *encrypted_message, msg_len, &enc_key, iv, AES_ENCRYPT);
}

void decrypt(const unsigned char* cipher, unsigned char** decrypted_msg, const size_t cipher_len, const unsigned char *key, unsigned char *iv ) {
  AES_KEY enc_key;
  AES_set_decrypt_key(key, 256, &enc_key);
  AES_cbc_encrypt(cipher, *decrypted_msg, cipher_len, &enc_key, iv, AES_DECRYPT);
}

int decode(const char* b64_msg, unsigned char** decode_msg, const size_t  decode_msg_len) {
  size_t bytes_decoded = 0;
  bytes_decoded = EVP_DecodeBlock(*decode_msg, (unsigned char *)b64_msg, strlen(b64_msg));
  return bytes_decoded;
}

int encode(const unsigned char* msg, const size_t msg_len, char** b64_msg) {
  size_t bytes_encoded = 0;
  if(msg && msg_len > 0 && b64_msg)  {
    bytes_encoded = EVP_EncodeBlock((unsigned char *) *b64_msg, msg, msg_len);
  }
  return bytes_encoded;
}

const int derived_key_size = init_key_iv(password, salt, key, iv_enc);
encrypt((unsigned char *)msg, &encrypted_message, strlen(msg), key, iv_enc);
const size_t bytes_encoded( encode((const unsigned char*)encrypted_message, strlen(reinterpret_cast<char*>(encrypted_message)), &base64_enc_str) );
const size_t bytes_decoded( CBase64::decode(cipher_base64, &cipher, cipher_len) );
decrypt(cipher, &decrypted_message, cipher_len, key, iv_dec);

Ожидание есть; шифры base64, сгенерированные библиотекой, должны быть расшифрованы в терминале openssl и наоборот.

1 Ответ

3 голосов
/ 05 июня 2019

Ваш код не завершен, и не показаны некоторые вещи, которые могут быть неправильными, но , показанные , которые определенно или, вероятно, неверны:

  • вы звоните EVP_BytesToKey с count = 5, когда в командной строке enc используется count = 1. Кроме того, вы не показываете, что такое cipher_type и msg_digest_type, и они могут ошибаться; в частности, дайджест по умолчанию, используемый для BytesToKey в командной строке enc, варьируется в зависимости от версии OpenSSL, и вы не сказали, какие версии вы или будете использовать или могли бы использовать. Хотя указание -md $hash переопределяет это значение по умолчанию, это более надежное и ясное решение.

  • вы не показываете, откуда взялся открытый текст, и, в частности, указали ли вы, как и каким образом вы его добавили. Командная строка enc по умолчанию использует заполнение PKCS5 / 7 и имеет возможность не использовать заполнение, но в этом случае длина открытого текста всегда должна быть кратна 16 - вы гарантировали это?

  • вы используете strlen(ciphertext) в качестве длины зашифрованного текста (raw = перед base64); это обычно неправильно. Зашифрованный текст - это фактически случайные биты, и он может легко содержать байт со значением 0, что дает слишком малую функцию strlen (), но если этого не произойдет, за ним не обязательно будет следовать или завершаться байт 0, что дает строку strlen. () это слишком велико.

  • вы не включаете в кодировку base64 заголовок файла (он же «магический»), требуемый командной строкой enc при использовании соли. Показанный код не добавляет разрывы строк, требуемые форматом файла enc командной строки, но это может быть сделано в другом месте, и имеет значение только в том случае, если значения, которые вы шифруете (и хотите расшифровать), равны или (когда-либо) могут быть больше 31 байта .

  • Также вы звоните memset (key, 0, sizeof(key)) и тоже самое для iv, когда они указатели; это очищает только размер указателя , 4 или 8 байт в современных системах, а не объект, на который указывает. Но поскольку эти объекты быстро перезаписываются на BytesToKey, эта ошибка не имеет значения.

В любом случае, здесь приведен минимальный код, который завершен и выдает вывод, который можно расшифровать с помощью командной строки enc -aes-256-cbc -d -a -k $password с -md sha256 для версий ниже 1.1.0, где это не является значением по умолчанию. Для удобства я ограничил ввод 80 байтами, но должно быть очевидно, как увеличить его при желании.

/* SO56447374 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>

void err (const char *label){
  fprintf (stderr, "%s:\n", label); ERR_print_errors_fp (stderr); exit (1);
}

int main (int argc, char**argv)
{
  ERR_load_crypto_strings(); 
  //OPENSSL_add_all_algorithms_noconf(); 

  const char * pass = argv[1];
  unsigned char salt [8], key [32], iv [16],
        plain [80], buffer [16+96], *cipher = buffer+16;
  int inlen = fread (plain, 1, 80-1, stdin), pad = 16-inlen%16U;
  AES_KEY aeskey;

  RAND_bytes (salt, 8);
  if( !EVP_BytesToKey (EVP_aes_256_cbc(), EVP_sha256(), salt, 
        (unsigned char*)pass, strlen(pass), 1, key, iv) ) err("BytesToKey");
  AES_set_encrypt_key (key, 256, &aeskey);
  memset (plain+inlen, pad, pad); // PKCS5/7 
  AES_cbc_encrypt (plain, cipher, inlen+pad, &aeskey, iv, AES_ENCRYPT);
  memcpy (buffer+0, "Salted__", 8); memcpy (buffer+8, salt, 8);
  BIO *bio1 = BIO_new (BIO_f_base64()); // does b64 with linebreaks (by default)
  BIO_push (bio1, BIO_new_fp (stdout, BIO_NOCLOSE));
  BIO_write (bio1, buffer, 16+inlen+pad);
  BIO_flush (bio1);
  BIO_free_all (bio1);
  return 0;
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...