使用openssl api而不是系统命令进行解密

问题描述 投票:0回答:1

我正在尝试使用 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 给定系统命令的代码。

encryption openssl rsa
1个回答
0
投票

解密必须使用与加密相同的盐和 IV 值,但是您正在生成新的随机值,这将以压倒性的概率出现错误。

openssl enc
将盐存储在文件中偏移量 8-15 处(从那里读取),只有偏移量 16-last 实际上是密文(仅解密该部分);它还从密码 + 盐派生出 密钥和 IV(如果模式使用它,则 CBC 会这样做),因此 PBKDF2 调用生成 48 个字节,并使用前 32 个字节作为密钥,后 16 个字节作为 IV。另外,对于像 CBC
enc
这样的块模式,默认情况下使用 PKCS5/7 填充,因此通过在解密期间关闭填充,您将在明文中添加一些垃圾字节。

PS:如果您将

inBuf outBuf
声明为
unsigned char
数组(而不仅仅是
char
),则不需要丑陋的强制转换,而且作为奖励,它可以更准确地描述至少加密文件中的内容,并且可能解密后的数据,即实际上不是字符的原始数据。

© www.soinside.com 2019 - 2024. All rights reserved.