我正在尝试使用 openssl api 函数而不是直接系统命令进行解密,我已经使用此通过系统命令进行了加密
openssl enc -aes-256-cbc -pbkdf2 -iter 310000 -md sha256 -salt -in file.run -out encrypted_data.enc -pass pass:Password!
在此之前,我已经创建了我的对称密钥并将其用于上述内容。
这是我用于使用系统命令解密的代码
这些是我的尺码
#define RSA_KEY_SIZE 4096 #define SIGNATURE_SIZE 512 #define KEY_SIZE 512
bool CryptoProcessor::_decryptData(Any &response)
{
String tempPrefix = String("/tmp/aaaa-") + uuid();
std::ifstream input(_inputFile, std::ios::binary); //the input file is the encrypted file which had signature and symetric key on top of it
input.seekg(SIGNATURE_SIZE + KEY_SIZE, std::ios::beg);
String encryptedDataFileName = tempPrefix + ".encrypted-data";
OutputFileStream encryptedDataFile;
encryptedDataFile.open(encryptedDataFileName, std::ios::binary);
char chunk[CHUNK_SIZE];
while (!input.eof())
{
input.read(chunk, CHUNK_SIZE);
int bytesRead = input.gcount();
encryptedDataFile.write(chunk, bytesRead);
}
encryptedDataFile.close();
input.close();
String runFileName = tempPrefix + ".run";
String command = String("openssl enc -aes-256-cbc -d -pbkdf2 -iter 310000 -p -md sha256 -salt -pass pass:") + _symmetricKey + " -in '" + encryptedDataFileName + "' -out '" + runFileName +"'";
//I added -p to understand how the salt , key and iv are there and identify them as coming right or wrong when i use the openssl api
logger(LOG_INFO) << command << endl;
ANY_ASSERT(system(command.c_str()) == 0, "Decryption failed")
return true;
}
我尝试像这样使用api解密它,但代码成功解密了文件,但它给出了错误的文件,即解密没有正确完成,我检查了下面代码中的盐、密钥和IV,我发现这些非常重要不同,不是预期的。
bool CryptoProcessor::_decryptData(Any &response)
{
String tempPrefix = String("/tmp/aaaa-") + uuid();
std::ifstream input(_inputFile, std::ios::binary);
input.seekg(SIGNATURE_SIZE + KEY_SIZE, std::ios::beg);
String encryptedDataFileName = tempPrefix + ".encrypted-data";
OutputFileStream encryptedDataFile;
encryptedDataFile.open(encryptedDataFileName, std::ios::binary);
char chunk[CHUNK_SIZE];
while (!input.eof())
{
input.read(chunk, CHUNK_SIZE);
int bytesRead = input.gcount();
encryptedDataFile.write(chunk, bytesRead);
}
encryptedDataFile.close();
input.close();
String runFileName = tempPrefix + ".run";
// Initialize OpenSSL
OpenSSL_add_all_algorithms();
// Create an OpenSSL BIO object for input and output
BIO *bio_in = BIO_new_file(encryptedDataFileName.c_str(), "rb");
BIO *bio_out = BIO_new_file(runFileName.c_str(), "wb");
if (!bio_in || !bio_out)
{
logger(LOG_ERROR) << "Failed to open input/output BIOs" << std::endl;
return false;
}
// Create an EVP decryption context
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx)
{
BIO_free_all(bio_in);
BIO_free_all(bio_out);
logger(LOG_ERROR) << "Failed to create cipher context" << std::endl;
return false;
}
// Set the AES-256-CBC cipher
if (EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, nullptr, nullptr) != 1)
{
EVP_CIPHER_CTX_free(ctx);
BIO_free_all(bio_in);
BIO_free_all(bio_out);
logger(LOG_ERROR) << "Failed to initialize decryption context" << std::endl;
return false;
}
EVP_CIPHER_CTX_set_padding(ctx, 0); // Disable padding
// Set the symmetric key using PBKDF2
unsigned char derivedKey[32]; // 256 bits for AES-256
int iterCount = 310000;
logger(LOG_INFO) << "Iterations: " << iterCount << std::endl;
const char *passphrase = _symmetricKey.c_str();
logger(LOG_INFO) << "Passphrase: " << _symmetricKey << std::endl;
unsigned char salt[PKCS5_SALT_LEN];
RAND_bytes(salt, sizeof(salt));
logger(LOG_INFO) << "Salt: ";
for (int i = 0; i < sizeof(salt); ++i)
{
logger(LOG_INFO) << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(salt[i]);
}
logger(LOG_INFO) << std::endl;
logger(LOG_INFO) << "Key: ";
for (int i = 0; i < 32; ++i)
{
logger(LOG_INFO) << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(derivedKey[i]);
}
logger(LOG_INFO) << std::endl;
unsigned char iv[16];
RAND_bytes(iv, sizeof(iv));
logger(LOG_INFO) << "IV: ";
for (int i = 0; i < sizeof(iv); ++i)
{
logger(LOG_INFO) << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(iv[i]);
}
logger(LOG_INFO) << std::endl;
if (PKCS5_PBKDF2_HMAC(passphrase, -1, salt, sizeof(salt), iterCount, EVP_sha256(), 32, derivedKey) != 1)
{
EVP_CIPHER_CTX_free(ctx);
BIO_free_all(bio_in);
BIO_free_all(bio_out);
logger(LOG_ERROR) << "Failed to derive encryption key using PBKDF2" << std::endl;
return false;
}
logger(LOG_INFO) << "Derived Key: ";
for (int i = 0; i < 32; ++i)
{
logger(LOG_INFO) << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(derivedKey[i]);
}
logger(LOG_INFO) << std::dec << std::endl;
// Set the key and IV for decryption
if (EVP_DecryptInit_ex(ctx, nullptr, nullptr, derivedKey, nullptr) != 1)
{
EVP_CIPHER_CTX_free(ctx);
BIO_free_all(bio_in);
BIO_free_all(bio_out);
logger(LOG_ERROR) << "Failed to set decryption key and IV" << std::endl;
return false;
}
// Perform the decryption
char inBuf[CHUNK_SIZE];
char outBuf[CHUNK_SIZE];
int outLen;
while (true)
{
int bytesRead = BIO_read(bio_in, inBuf, CHUNK_SIZE);
if (bytesRead <= 0)
break;
if (EVP_DecryptUpdate(ctx, reinterpret_cast<unsigned char *>(outBuf), &outLen, reinterpret_cast<const unsigned char *>(inBuf), bytesRead) != 1)
{
EVP_CIPHER_CTX_free(ctx);
BIO_free_all(bio_in);
BIO_free_all(bio_out);
logger(LOG_ERROR) << "Decryption failed" << std::endl;
return false;
}
BIO_write(bio_out, outBuf, outLen);
}
if (EVP_DecryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(outBuf), &outLen) != 1)
{
EVP_CIPHER_CTX_free(ctx);
BIO_free_all(bio_in);
BIO_free_all(bio_out);
logger(LOG_ERROR) << "Decryption finalization failed" << std::endl;
return false;
}
BIO_write(bio_out, outBuf, outLen);
// Clean up
EVP_CIPHER_CTX_free(ctx);
BIO_free_all(bio_in);
BIO_free_all(bio_out);
logger(LOG_INFO) << "Decryption Done" << std::endl;
return true;
}
帮助我,用 api 编写 openssl 给定系统命令的代码。
解密必须使用与加密相同的盐和 IV 值,但是您正在生成新的随机值,这将以压倒性的概率出现错误。
openssl enc
将盐存储在文件中偏移量 8-15 处(从那里读取),只有偏移量 16-last 实际上是密文(仅解密该部分);它还从密码 + 盐派生出 密钥和 IV(如果模式使用它,则 CBC 会这样做),因此 PBKDF2 调用生成 48 个字节,并使用前 32 个字节作为密钥,后 16 个字节作为 IV。另外,对于像 CBC enc
这样的块模式,默认情况下使用 PKCS5/7 填充,因此通过在解密期间关闭填充,您将在明文中添加一些垃圾字节。
PS:如果您将
inBuf outBuf
声明为 unsigned char
数组(而不仅仅是 char
),则不需要丑陋的强制转换,而且作为奖励,它可以更准确地描述至少加密文件中的内容,并且可能解密后的数据,即实际上不是字符的原始数据。