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 <cstring>
#include <vector> #include <vector>
#include <xlnt/utils/exceptions.hpp>
namespace xlnt { namespace xlnt {
namespace detail { namespace detail {
using byte = std::uint8_t; using byte = std::uint8_t;
class byte_reader class binary_reader
{ {
public: public:
byte_reader() = delete; binary_reader() = delete;
byte_reader(const std::vector<byte> &bytes) binary_reader(const std::vector<byte> &bytes)
: bytes_(&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_; offset_ = other.offset_;
bytes_ = other.bytes_; bytes_ = other.bytes_;
@ -52,7 +54,7 @@ public:
return *this; return *this;
} }
~byte_reader() ~binary_reader()
{ {
} }
@ -89,7 +91,7 @@ public:
template<typename T> template<typename T>
std::vector<T> as_vector_of() const 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()); std::memcpy(result.data(), bytes_->data(), size());
return result; return result;
@ -105,108 +107,59 @@ private:
const std::vector<std::uint8_t> *bytes_; const std::vector<std::uint8_t> *bytes_;
}; };
class byte_vector class binary_writer
{ {
public: public:
template<typename T> binary_writer(std::vector<byte> &bytes)
static byte_vector from(const std::vector<T> &ints) : bytes_(&bytes)
{
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_)
{ {
} }
byte_vector(std::vector<byte> &bytes) binary_writer(const binary_writer &other)
: 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()
{ {
*this = other; *this = other;
} }
~byte_vector() ~binary_writer()
{ {
} }
byte_vector &operator=(const byte_vector &other) binary_writer &operator=(const binary_writer &other)
{ {
bytes_ = other.bytes_; bytes_ = other.bytes_;
reader_ = byte_reader(bytes_); offset_ = other.offset_;
return *this; 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; offset_ = new_offset;
}
void offset(std::size_t offset)
{
reader_.offset(offset);
} }
std::size_t offset() const std::size_t offset() const
{ {
return reader_.offset(); return offset_;
} }
void reset() void reset()
{ {
reader_.reset(); offset_ = 0;
bytes_.clear(); 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>();
} }
template<typename T> template<typename T>
@ -219,35 +172,47 @@ public:
extend(offset() + num_bytes - size()); extend(offset() + num_bytes - size());
} }
std::memcpy(bytes_.data() + offset(), &value, num_bytes); std::memcpy(bytes_->data() + offset(), &value, num_bytes);
reader_.offset(reader_.offset() + num_bytes); offset_ += num_bytes;
} }
std::size_t size() const std::size_t size() const
{ {
return bytes_.size(); return bytes_->size();
} }
void resize(std::size_t new_size, byte fill = 0) 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) void extend(std::size_t amount, byte fill = 0)
{ {
bytes_.resize(size() + amount, fill); bytes_->resize(size() + amount, fill);
} }
std::vector<byte>::iterator iterator() 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) void append(const std::vector<std::uint8_t> &data, std::size_t offset, std::size_t count)
{ {
auto end_index = size(); auto end_index = size();
extend(count); 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) void append(const std::vector<std::uint8_t> &data)
@ -256,9 +221,19 @@ public:
} }
private: private:
std::vector<byte> bytes_; std::vector<byte> *bytes_;
byte_reader reader_; 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 detail
} // namespace xlnt } // namespace xlnt

View File

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

View File

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

View File

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

View File

@ -25,7 +25,7 @@
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#include <detail/bytes.hpp> #include <detail/binary.hpp>
#include <detail/constants.hpp> #include <detail/constants.hpp>
#include <detail/unicode.hpp> #include <detail/unicode.hpp>
#include <detail/cryptography/encryption_info.hpp> #include <detail/cryptography/encryption_info.hpp>
@ -42,7 +42,7 @@
namespace { namespace {
using xlnt::detail::byte; using xlnt::detail::byte;
using xlnt::detail::byte_vector; using xlnt::detail::binary_reader;
using xlnt::detail::encryption_info; using xlnt::detail::encryption_info;
std::vector<std::uint8_t> decrypt_xlsx_standard( 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(); 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_size = reader.read<std::uint64_t>();
auto decrypted = xlnt::detail::aes_ecb_decrypt(encrypted_package, key, reader.offset()); auto decrypted = xlnt::detail::aes_ecb_decrypt(encrypted_package, key, reader.offset());
decrypted.resize(static_cast<std::size_t>(decrypted_size)); 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; encryption_info::standard_encryption_info result;
auto reader = xlnt::detail::byte_reader(info_bytes); auto reader = binary_reader(info_bytes);
// skip version info // skip version info
reader.read<std::uint32_t>(); 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; 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_major = reader.read<std::uint16_t>();
auto version_minor = 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) 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_major = std::uint16_t(4);
const auto version_minor = std::uint16_t(2); const auto version_minor = std::uint16_t(2);
const auto encryption_flags = std::uint32_t(0b00010000 & 0b00100000); const auto encryption_flags = std::uint32_t(0b00010000 & 0b00100000);
result.write(version_major); writer.write(version_major);
result.write(version_minor); writer.write(version_minor);
result.write(encryption_flags); writer.write(encryption_flags);
const auto header_length = std::uint32_t(32); // calculate this! const auto header_length = std::uint32_t(32); // calculate this!
result.write(header_length); writer.write(header_length);
result.write(std::uint32_t(0)); // skip_flags writer.write(std::uint32_t(0)); // skip_flags
result.write(std::uint32_t(0)); // size_extra writer.write(std::uint32_t(0)); // size_extra
result.write(std::uint32_t(0x0000660E)); writer.write(std::uint32_t(0x0000660E));
result.write(std::uint32_t(0x00008004)); writer.write(std::uint32_t(0x00008004));
result.write(std::uint32_t(info.standard.key_bits)); writer.write(std::uint32_t(info.standard.key_bits));
result.write(std::uint32_t(0x00000018)); writer.write(std::uint32_t(0x00000018));
result.write(std::uint32_t(0)); writer.write(std::uint32_t(0));
result.write(std::uint32_t(0)); writer.write(std::uint32_t(0));
const auto provider = u"Microsoft Enhanced RSA and AES Cryptographic Provider"; const auto provider = std::u16string(u"Microsoft Enhanced RSA and AES Cryptographic Provider");
result.append(xlnt::detail::byte_vector::from(std::u16string(provider)).data()); writer.append(xlnt::detail::string_to_bytes(provider));
result.write(std::uint32_t(info.standard.salt.size())); writer.write(std::uint32_t(info.standard.salt.size()));
result.append(info.standard.salt); writer.append(info.standard.salt);
result.append(info.standard.encrypted_verifier); writer.append(info.standard.encrypted_verifier);
result.write(std::uint32_t(20)); writer.write(std::uint32_t(20));
result.append(info.standard.encrypted_verifier_hash); writer.append(info.standard.encrypted_verifier_hash);
return result.data(); return result;
} }
std::vector<std::uint8_t> encrypt_xlsx_agile( std::vector<std::uint8_t> encrypt_xlsx_agile(