我已经使用 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 终端中解密,反之亦然。
最佳答案
您的代码不完整,有几处未显示可能是错误的,但显示肯定或可能是错误的是:
当命令行
enc
使用 count=1 时,您使用 count=5 调用EVP_BytesToKey
。此外,您没有显示cipher_type
和msg_digest_type
是什么,它们可能是错误的;特别是,命令行enc
中用于BytesToKey
的默认摘要根据 OpenSSL 的版本而有所不同,并且您没有说明您是或将要或可能正在使用。尽管指定-md $hash
会覆盖该默认值,但这是一个更强大、更清晰的解决方案。您没有显示明文的来源,尤其是您是否以及如何填充它。命令行
enc
默认使用 PKCS5/7 填充,并且可以选择不使用填充,但在那种情况下,明文长度必须始终是 16 的精确倍数——你保证吗?您使用
strlen(ciphertext)
作为(raw = before base64)密文的长度;这通常是错误的。密文实际上是随机位,可以很容易地包含一个值为 0 的字节,给出一个 strlen() 太小,但如果没有发生,它不一定会被 0 字节跟随或终止,给出一个 strlen () 太大了。在使用 salt 时,您不会在 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;
}
关于c - 在终端上解密 openssl 库生成的密码,反之亦然,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56447374/