intermediate commit

This commit is contained in:
Thomas Fussell 2017-04-23 18:18:35 -04:00
parent 2fc692d694
commit 126f22816b
6 changed files with 168 additions and 235 deletions

View File

@ -27,24 +27,26 @@
#include <cstring>
#include <vector>
#include <xlnt/utils/exceptions.hpp>
namespace xlnt {
namespace detail {
using byte = std::uint8_t;
class byte_reader
class binary_reader
{
public:
byte_reader() = delete;
binary_reader() = delete;
byte_reader(const std::vector<byte> &bytes)
binary_reader(const std::vector<byte> &bytes)
: bytes_(&bytes)
{
}
byte_reader(const byte_reader &other) = default;
binary_reader(const binary_reader &other) = default;
byte_reader &operator=(const byte_reader &other)
binary_reader &operator=(const binary_reader &other)
{
offset_ = other.offset_;
bytes_ = other.bytes_;
@ -52,7 +54,7 @@ public:
return *this;
}
~byte_reader()
~binary_reader()
{
}
@ -89,7 +91,7 @@ public:
template<typename T>
std::vector<T> as_vector_of() const
{
auto result = std::vector<T>(size() / sizeof(T), 0);
auto result = std::vector<T>(size() / sizeof(T), T());
std::memcpy(result.data(), bytes_->data(), size());
return result;
@ -105,108 +107,59 @@ private:
const std::vector<std::uint8_t> *bytes_;
};
class byte_vector
class binary_writer
{
public:
template<typename T>
static byte_vector from(const std::vector<T> &ints)
{
byte_vector result;
result.resize(ints.size() * sizeof(T));
std::memcpy(result.bytes_.data(), ints.data(), result.bytes_.size());
return result;
}
template<typename T>
static byte_vector from(const std::basic_string<T> &string)
{
byte_vector result;
result.resize(string.size() * sizeof(T));
std::memcpy(result.bytes_.data(), string.data(), result.bytes_.size());
return result;
}
byte_vector()
: reader_(bytes_)
binary_writer(std::vector<byte> &bytes)
: bytes_(&bytes)
{
}
byte_vector(std::vector<byte> &bytes)
: bytes_(bytes),
reader_(bytes_)
{
}
template<typename T>
byte_vector(const std::vector<T> &ints)
: byte_vector()
{
bytes_ = from(ints).data();
}
byte_vector(const byte_vector &other)
: byte_vector()
binary_writer(const binary_writer &other)
{
*this = other;
}
~byte_vector()
~binary_writer()
{
}
byte_vector &operator=(const byte_vector &other)
binary_writer &operator=(const binary_writer &other)
{
bytes_ = other.bytes_;
reader_ = byte_reader(bytes_);
offset_ = other.offset_;
return *this;
}
const std::vector<byte> &data() const
template<typename T>
void assign(const std::vector<T> &ints)
{
return bytes_;
resize(ints.size() * sizeof(T));
std::memcpy(bytes_->data(), ints.data(), bytes_->size());
}
std::vector<byte> data()
template<typename T>
void assign(const std::basic_string<T> &string)
{
return bytes_;
resize(string.size() * sizeof(T));
std::memcpy(bytes_->data(), string.data(), bytes_->size());
}
void data(std::vector<byte> &bytes)
void offset(std::size_t new_offset)
{
bytes_ = bytes;
}
void offset(std::size_t offset)
{
reader_.offset(offset);
offset_ = new_offset;
}
std::size_t offset() const
{
return reader_.offset();
return offset_;
}
void reset()
{
reader_.reset();
bytes_.clear();
}
template<typename T>
T read()
{
return reader_.read<T>();
}
template<typename T>
std::vector<T> as_vector_of() const
{
return reader_.as_vector_of<T>();
offset_ = 0;
bytes_->clear();
}
template<typename T>
@ -219,35 +172,47 @@ public:
extend(offset() + num_bytes - size());
}
std::memcpy(bytes_.data() + offset(), &value, num_bytes);
reader_.offset(reader_.offset() + num_bytes);
std::memcpy(bytes_->data() + offset(), &value, num_bytes);
offset_ += num_bytes;
}
std::size_t size() const
{
return bytes_.size();
return bytes_->size();
}
void resize(std::size_t new_size, byte fill = 0)
{
bytes_.resize(new_size, fill);
bytes_->resize(new_size, fill);
}
void extend(std::size_t amount, byte fill = 0)
{
bytes_.resize(size() + amount, fill);
bytes_->resize(size() + amount, fill);
}
std::vector<byte>::iterator iterator()
{
return bytes_.begin() + static_cast<std::ptrdiff_t>(offset());
return bytes_->begin() + static_cast<std::ptrdiff_t>(offset());
}
void append(const std::vector<std::uint8_t> &data, std::size_t offset, std::size_t count)
{
auto end_index = size();
extend(count);
std::memcpy(bytes_.data() + end_index, data.data() + offset, count);
std::memcpy(bytes_->data() + end_index, data.data() + offset, count);
}
void append(const byte *data, const std::size_t data_size, std::size_t offset, std::size_t count)
{
if (offset + count > data_size)
{
throw xlnt::exception("out of bounds read");
}
const auto end_index = size();
extend(count);
std::memcpy(bytes_->data() + end_index, data + offset, count);
}
void append(const std::vector<std::uint8_t> &data)
@ -256,9 +221,19 @@ public:
}
private:
std::vector<byte> bytes_;
byte_reader reader_;
std::vector<byte> *bytes_;
std::size_t offset_ = 0;
};
template<typename T>
std::vector<byte> string_to_bytes(const std::basic_string<T> &string)
{
std::vector<byte> bytes;
binary_writer writer(bytes);
writer.assign(string);
return bytes;
}
} // namespace detail
} // namespace xlnt

View File

@ -31,13 +31,15 @@
#include <string>
#include <vector>
#include <detail/bytes.hpp>
#include <detail/binary.hpp>
#include <detail/cryptography/compound_document.hpp>
#include <xlnt/utils/exceptions.hpp>
namespace {
using xlnt::detail::byte_vector;
using xlnt::detail::byte;
using xlnt::detail::binary_reader;
using xlnt::detail::binary_writer;
using directory_id = std::int32_t;
using sector_id = std::int32_t;
@ -124,14 +126,11 @@ public:
return chain;
}
void load(const byte_vector &data)
void load(std::size_t new_sector_size, const std::vector<byte> &sectors)
{
data_ = data.as_vector_of<sector_id>();
}
byte_vector save() const
{
return byte_vector::from(data_);
sector_size(new_sector_size);
auto reader = binary_reader(sectors);
data_ = reader.as_vector_of<sector_id>();
}
std::size_t sector_size() const
@ -174,14 +173,14 @@ public:
return true;
}
void load(byte_vector &data)
void load(binary_reader &reader)
{
if (data.size() < 512)
if (reader.size() < 512)
{
throw xlnt::exception("bad header");
}
*this = data.read<header>();
*this = reader.read<header>();
if (file_id_ != 0xe11ab1a1e011cfd0)
{
@ -194,14 +193,6 @@ public:
}
}
byte_vector save() const
{
byte_vector out;
out.write(*this);
return out;
}
std::size_t sector_size() const
{
return std::size_t(1) << sector_size_power_;
@ -436,43 +427,17 @@ public:
}
void load(byte_vector &data)
void load(const std::vector<byte> &data)
{
entries.clear();
auto num_entries = data.size() / sizeof(directory_entry);
for (auto i = std::size_t(0); i < num_entries; ++i)
auto reader = binary_reader(data);
entries = reader.as_vector_of<directory_entry>();
auto is_empty = [](const directory_entry &entry)
{
auto e = data.read<directory_entry>();
return entry.type == directory_entry::entry_type::Empty;
};
if (e.type == directory_entry::entry_type::Empty)
{
continue;
}
if ((e.type != directory_entry::entry_type::UserStream)
&& (e.type != directory_entry::entry_type::UserStorage)
&& (e.type != directory_entry::entry_type::RootStorage))
{
throw xlnt::exception("invalid entry");
}
entries.push_back(e);
}
}
byte_vector save() const
{
auto result = byte_vector();
for (auto &entry : entries)
{
result.write(entry);
}
return result;
entries.erase(std::remove_if(entries.begin(), entries.end(), is_empty));
}
directory_entry create_root_entry() const
@ -606,62 +571,72 @@ namespace detail {
class compound_document_reader_impl
{
public:
compound_document_reader_impl(const std::vector<std::uint8_t> &data)
compound_document_reader_impl(const std::vector<byte> &bytes)
: sectors_(bytes.data() + sizeof(header)),
sectors_size_(bytes.size())
{
auto reader = byte_vector(data);
auto reader = binary_reader(bytes);
header_.load(reader);
sector_table_.sector_size(header_.sector_size());
short_sector_table_.sector_size(header_.short_sector_size());
const auto sector_size = header_.sector_size();
const auto master_table_chain = load_master_table();
const auto master_sectors = read(master_table_chain);
sector_table_.load(sector_size, master_sectors);
sectors_.append(data, 512, data.size() - 512);
const auto short_sector_size = header_.short_sector_size();
const auto short_start = header_.short_table_start();
const auto short_table_chain = sector_table_.follow(short_start);
const auto short_sectors = read(short_table_chain);
short_sector_table_.load(short_sector_size, short_sectors);
sector_table_.load(load_sectors(load_msat(reader)));
short_sector_table_.load(load_sectors(sector_table_.follow(header_.short_table_start())));
auto directory_data = load_sectors(sector_table_.follow(header_.directory_start()));
directory_.load(directory_data);
const auto directory_start = header_.directory_start();
const auto directory_chain = sector_table_.follow(directory_start);
const auto directory_sectors = read(directory_chain);
directory_.load(directory_sectors);
auto first_short_sector = directory_.entry(u"/Root Entry", false).first;
short_container_stream_ = sector_table_.follow(first_short_sector);
}
byte_vector load_sectors(const std::vector<sector_id> &sectors) const
std::vector<byte> read(const std::vector<sector_id> &sectors) const
{
auto result = byte_vector();
const auto sector_size = sector_table_.sector_size();
auto result = std::vector<byte>();
auto writer = binary_writer(result);
for (auto sector : sectors)
{
auto position = sector_size * static_cast<std::size_t>(sector);
result.append(sectors_.data(), position, sector_size);
auto position = sizeof(header) + sector_size * static_cast<std::size_t>(sector);
writer.append(sectors_, sectors_size_, position, sector_size);
}
return result;
}
byte_vector load_short_sectors(const std::vector<sector_id> &sectors) const
std::vector<byte> read_short(const std::vector<sector_id> &sectors) const
{
auto result = byte_vector();
const auto short_sector_size = short_sector_table_.sector_size();
const auto sector_size = sector_table_.sector_size();
auto result = std::vector<byte>();
auto writer = binary_writer(result);
for (auto sector : sectors)
{
auto position = short_sector_size * static_cast<std::size_t>(sector);
auto master_allocation_table_index = position / sector_size;
auto sector_data = load_sectors({ short_container_stream_[master_allocation_table_index] });
auto sector_data = read({ short_container_stream_[master_allocation_table_index] });
auto offset = position % sector_size;
result.append(sector_data.data(), offset, short_sector_size);
writer.append(sector_data, offset, short_sector_size);
}
return result;
}
std::vector<sector_id> load_msat(byte_vector &/*data*/)
std::vector<sector_id> load_master_table()
{
const auto sector_size = header_.sector_size();
auto master_sectors = header_.sectors();
if (header_.num_master_sectors() > 109)
@ -670,60 +645,56 @@ public:
for (auto r = std::size_t(0); r < header_.num_master_sectors(); ++r)
{
auto msat = load_sectors({ current_sector });
auto index = sector_id(0);
while (index < static_cast<sector_id>((sector_size - 1) / sizeof(sector_id)))
{
master_sectors.push_back(msat.read<sector_id>());
}
current_sector = msat.read<sector_id>();
auto current_sector_data = read({ current_sector });
auto current_sector_reader = binary_reader(current_sector_data);
auto current_sector_sectors = current_sector_reader.as_vector_of<sector_id>();
current_sector = current_sector_sectors.back();
current_sector_sectors.pop_back();
master_sectors.insert(
current_sector_sectors.begin(),
current_sector_sectors.end(),
master_sectors.end());
}
}
return master_sectors;
}
byte_vector read_stream(const std::u16string &name) const
std::vector<byte> read_stream(const std::u16string &name) const
{
const auto entry = directory_.entry(name);
byte_vector result;
if (entry.size < header_.threshold())
{
result = load_short_sectors(short_sector_table_.follow(entry.first));
result.resize(entry.size);
}
else
{
result = load_sectors(sector_table_.follow(entry.first));
result.resize(entry.size);
}
auto result = entry.size < header_.threshold()
? read_short(short_sector_table_.follow(entry.first))
: read(sector_table_.follow(entry.first));
result.resize(entry.size);
return result;
}
private:
const byte *sectors_;
const std::size_t sectors_size_;
directory_tree directory_;
header header_;
allocation_table sector_table_;
byte_vector sectors_;
allocation_table short_sector_table_;
byte_vector short_sectors_;
std::vector<sector_id> short_container_stream_;
};
class compound_document_writer_impl
{
public:
compound_document_writer_impl(std::vector<std::uint8_t> &data)
compound_document_writer_impl(std::vector<byte> &bytes)
: writer_(bytes)
{
sector_table_.sector_size(header_.sector_size());
short_sector_table_.sector_size(header_.short_sector_size());
}
void write_sectors(const byte_vector &data, directory_entry &/*entry*/)
void write_sectors(const std::vector<byte> &data, directory_entry &/*entry*/)
{
const auto sector_size = sector_table_.sector_size();
const auto num_sectors = data.size() / sector_size;
@ -732,11 +703,11 @@ public:
{
auto position = sector_size * i;
auto current_sector_size = data.size() % sector_size;
sectors_.append(data.data(), position, current_sector_size);
writer_.append(data, position, current_sector_size);
}
}
void write_short_sectors(const byte_vector &data, directory_entry &/*entry*/)
void write_short_sectors(const std::vector<byte> &data, directory_entry &/*entry*/)
{
const auto sector_size = sector_table_.sector_size();
const auto num_sectors = data.size() / sector_size;
@ -745,24 +716,11 @@ public:
{
auto position = sector_size * i;
auto current_sector_size = data.size() % sector_size;
sectors_.append(data.data(), position, current_sector_size);
writer_.append(data, position, current_sector_size);
}
}
byte_vector save() const
{
auto result = byte_vector();
result.append(header_.save().data());
result.append(sector_table_.save().data());
result.append(short_sector_table_.save().data());
result.append(directory_.save().data());
result.append(sectors_.data());
return result;
}
void write_stream(const std::u16string &name, const byte_vector &data)
void write_stream(const std::u16string &name, const std::vector<byte> &data)
{
auto &entry = directory_.entry(name, true);
@ -777,12 +735,11 @@ public:
}
private:
binary_writer writer_;
directory_tree directory_;
header header_;
allocation_table sector_table_;
byte_vector sectors_;
allocation_table short_sector_table_;
byte_vector short_sectors_;
std::vector<sector_id> short_container_stream_;
};
@ -797,7 +754,7 @@ compound_document_reader::~compound_document_reader()
std::vector<std::uint8_t> compound_document_reader::read_stream(const std::u16string &name) const
{
return d_->read_stream(name).data();
return d_->read_stream(name);
}
compound_document_writer::compound_document_writer(std::vector<std::uint8_t> &data)

View File

@ -28,7 +28,7 @@
#include <memory>
#include <string>
#include <detail/bytes.hpp>
#include <detail/binary.hpp>
namespace xlnt {
namespace detail {

View File

@ -23,7 +23,7 @@
#include <array>
#include <detail/bytes.hpp>
#include <detail/binary.hpp>
#include <detail/cryptography/aes.hpp>
#include <detail/cryptography/encryption_info.hpp>
@ -37,7 +37,7 @@ std::vector<std::uint8_t> calculate_standard_key(
{
// H_0 = H(salt + password)
auto salt_plus_password = info.salt;
auto password_bytes = xlnt::detail::byte_vector::from(password).data();
auto password_bytes = xlnt::detail::string_to_bytes(password);
std::copy(password_bytes.begin(),
password_bytes.end(),
std::back_inserter(salt_plus_password));
@ -107,7 +107,7 @@ std::vector<std::uint8_t> calculate_agile_key(
{
// H_0 = H(salt + password)
auto salt_plus_password = info.key_encryptor.salt_value;
auto password_bytes = xlnt::detail::byte_vector::from(password).data();
auto password_bytes = xlnt::detail::string_to_bytes(password);
std::copy(password_bytes.begin(),
password_bytes.end(),
std::back_inserter(salt_plus_password));

View File

@ -25,7 +25,7 @@
#include <cstdint>
#include <vector>
#include <detail/bytes.hpp>
#include <detail/binary.hpp>
#include <detail/constants.hpp>
#include <detail/unicode.hpp>
#include <detail/cryptography/encryption_info.hpp>
@ -42,7 +42,7 @@
namespace {
using xlnt::detail::byte;
using xlnt::detail::byte_vector;
using xlnt::detail::binary_reader;
using xlnt::detail::encryption_info;
std::vector<std::uint8_t> decrypt_xlsx_standard(
@ -51,7 +51,7 @@ std::vector<std::uint8_t> decrypt_xlsx_standard(
{
const auto key = info.calculate_key();
auto reader = xlnt::detail::byte_reader(encrypted_package);
auto reader = binary_reader(encrypted_package);
auto decrypted_size = reader.read<std::uint64_t>();
auto decrypted = xlnt::detail::aes_ecb_decrypt(encrypted_package, key, reader.offset());
decrypted.resize(static_cast<std::size_t>(decrypted_size));
@ -107,7 +107,7 @@ encryption_info::standard_encryption_info read_standard_encryption_info(const st
{
encryption_info::standard_encryption_info result;
auto reader = xlnt::detail::byte_reader(info_bytes);
auto reader = binary_reader(info_bytes);
// skip version info
reader.read<std::uint32_t>();
@ -275,7 +275,7 @@ encryption_info read_encryption_info(const std::vector<std::uint8_t> &info_bytes
info.password = password;
auto reader = xlnt::detail::byte_reader(info_bytes);
auto reader = binary_reader(info_bytes);
auto version_major = reader.read<std::uint16_t>();
auto version_minor = reader.read<std::uint16_t>();

View File

@ -171,40 +171,41 @@ std::vector<std::uint8_t> write_agile_encryption_info(
std::vector<std::uint8_t> write_standard_encryption_info(const encryption_info &info)
{
xlnt::detail::byte_vector result;
auto result = std::vector<std::uint8_t>();
auto writer = xlnt::detail::binary_writer(result);
const auto version_major = std::uint16_t(4);
const auto version_minor = std::uint16_t(2);
const auto encryption_flags = std::uint32_t(0b00010000 & 0b00100000);
result.write(version_major);
result.write(version_minor);
result.write(encryption_flags);
writer.write(version_major);
writer.write(version_minor);
writer.write(encryption_flags);
const auto header_length = std::uint32_t(32); // calculate this!
result.write(header_length);
result.write(std::uint32_t(0)); // skip_flags
result.write(std::uint32_t(0)); // size_extra
result.write(std::uint32_t(0x0000660E));
result.write(std::uint32_t(0x00008004));
result.write(std::uint32_t(info.standard.key_bits));
result.write(std::uint32_t(0x00000018));
result.write(std::uint32_t(0));
result.write(std::uint32_t(0));
writer.write(header_length);
writer.write(std::uint32_t(0)); // skip_flags
writer.write(std::uint32_t(0)); // size_extra
writer.write(std::uint32_t(0x0000660E));
writer.write(std::uint32_t(0x00008004));
writer.write(std::uint32_t(info.standard.key_bits));
writer.write(std::uint32_t(0x00000018));
writer.write(std::uint32_t(0));
writer.write(std::uint32_t(0));
const auto provider = u"Microsoft Enhanced RSA and AES Cryptographic Provider";
result.append(xlnt::detail::byte_vector::from(std::u16string(provider)).data());
const auto provider = std::u16string(u"Microsoft Enhanced RSA and AES Cryptographic Provider");
writer.append(xlnt::detail::string_to_bytes(provider));
result.write(std::uint32_t(info.standard.salt.size()));
result.append(info.standard.salt);
writer.write(std::uint32_t(info.standard.salt.size()));
writer.append(info.standard.salt);
result.append(info.standard.encrypted_verifier);
writer.append(info.standard.encrypted_verifier);
result.write(std::uint32_t(20));
result.append(info.standard.encrypted_verifier_hash);
writer.write(std::uint32_t(20));
writer.append(info.standard.encrypted_verifier_hash);
return result.data();
return result;
}
std::vector<std::uint8_t> encrypt_xlsx_agile(