Migrating to unique_ptr from a dynamic array and failing to convert to std::span

  c++, c++20, unique-ptr, vector

I’m trying to encrypt and decrypt a file, basically exercising std::span and std::unique_ptr. The issues are commented in the code.

  1. 2nd parameter of rc4 is std::span but my parameters are vector<uint8_t> for the encryption and unique_ptr<uint8_t> for the decryption, which I’m unable to convert to.
  2. *output++ = elem ^ s[(s[i] + s[j]) % 256]; cannot be done with unique_ptr.
const auto log_data = read_log_file(log_path);
const auto log_size = static_cast<std::size_t>(std::filesystem::file_size(log_path));

// Generate a random key
std::uint8_t key[32];
generate_random_key(key);

// Encrypt
const auto result = std::make_unique<std::uint8_t>(log_size);

rc4_context context{};
rc4(&context, log_data, key, std::move(result)); // TODO: log_data: Cannot convert lvalue of type const std::vector<uint8_t> to parameter type const std::span<uint8_t>

// Decrypt
const auto result2 = std::make_unique<std::uint8_t>(log_size);
rc4(&context, std::move(result), key, std::move(result2)); // TODO: Again the second parameter cannot be casted from unique_ptr<unsigned char> to span<uint8_t>
std::vector<std::uint8_t> read_log_file(const std::wstring& path)
{
    std::ifstream ifs(path, std::ios::binary | std::ios::ate);

    if (!ifs)
        throw std::runtime_error("Could not load file.");

    const auto end = ifs.tellg();
    ifs.seekg(0, std::ios::beg);

    const auto size = static_cast<std::size_t>(end - ifs.tellg());

    if (size == 0)
        return {};

    std::vector<std::uint8_t> buffer(size);

    if (!ifs.read(reinterpret_cast<char*>(buffer.data()), buffer.size()))
        throw std::runtime_error("Could not read file.");

    return buffer;
}

int rc4(rc4_context* context, const std::span<std::uint8_t>& data, const std::span<std::uint8_t>& key, const std::unique_ptr<std::uint8_t>& output)
{
    // INITIALIZATION
    std::uint32_t i, j;

    // Check parameters
    if (!context || !key.empty())
        return ERROR_INVALID_PARAMETER;

    // Clear context
    context->i = 0;
    context->j = 0;

    // Initialize the S array with identity permutation
    for (i = 0; i < 256; i++)
    {
        context->s[i] = static_cast<std::uint8_t>(i);
    }

    // S is then processed for 256 iterations
    for (i = 0, j = 0; i < 256; i++)
    {
        // Randomize the permutations using the supplied key
        j = (j + context->s[i] + key[i % key.size()]) % 256;

        // Swap the values of S[i] and S[j]
        const auto temp = context->s[i];
        context->s[i] = context->s[j];
        context->s[j] = temp;
    }

    // MAIN LOGIC PART
    // Restore context
    i = context->i;
    j = context->j;
    auto* s = context->s;
    
    // Encryption loop
    for (auto elem : data)
    {
        // Adjust indices
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;

        // Swap the values of S[i] and S[j]
        std::swap(s[i], s[j]);

        // Valid output?
        if (output)
        {
            // XOR the input data with the RC4 stream
            *output++ = elem ^ s[(s[i] + s[j]) % 256]; // TODO: error happens here, because of *output++
        }
    }

    // Save context
    context->i = i;
    context->j = j;

    return NO_ERROR;
}

Source: Windows Questions C++

LEAVE A COMMENT