1

我已经使用 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 密码并尝试使用库解密,但失败了。我尝试使用 Library 生成示例 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 终端中解密,反之亦然。

4

1 回答 1

3

您的代码不完整,有几处未显示可能是错误的,但显示的肯定或可能错误的内容是:

  • 当命令行使用 count=1EVP_BytesToKey时,您使用 count=5调用。enc此外,您没有显示什么cipher_typemsg_digest_type是,它们可能是错误的;BytesToKey特别是,命令行中使用的默认摘要enc根据 OpenSSL 的版本而有所不同,并且您没有说明您正在使用、将要使用或可能使用的版本。尽管指定-md $hash会覆盖该默认值,但这是一种更强大、更清晰的解决方案。

  • 你没有显示明文来自哪里,特别是你是否以及如何填充它。默认情况下,命令行使用PKCS5 enc/7 填充,并且可以选择不使用填充,但在这种情况下,明文长度必须始终是 16 的精确倍数——你保证了吗?

  • strlen(ciphertext)用作(原始=base64之前)密文的长度;这通常是错误的。密文实际上是随机位,并且可以很容易地包含一个值为 0 的字节,从而给出一个太小的 strlen(),但如果没有发生这种情况,它不一定会跟随或终止一个 0 字节,给出一个 strlen () 太大了。

  • enc使用 salt 时,您不会在 base64 编码中包含命令行所需的文件头(又名“魔术”) 。显示的代码没有添加命令行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;
}

于 2019-06-05T05:39:32.303 回答