Linux Unified Key Setup (LUKS) is a format specification for storing disk encryption parameters and up to 8 user keys (which can unlock the master key).
This page hosts a formal specification of Linux Unified Key Setup using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
All parsing code for C++11/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.
For C++, the easiest way is to clone the runtime library sources and build them along with your project.
Using Kaitai Struct in C++/STL usually consists of 3 steps.
std::istream
). One can open local file for that, or use existing std::string
or char*
buffer.
#include <fstream>
std::ifstream is("path/to/local/file.bin", std::ifstream::binary);
#include <sstream>
std::istringstream is(str);
#include <sstream>
const char buf[] = { ... };
std::string str(buf, sizeof buf);
std::istringstream is(str);
#include "kaitai/kaitaistream.h"
kaitai::kstream ks(&is);
luks_t data(&ks);
After that, one can get various attributes from the structure by invoking getter methods like:
data.partition_header() // => get partition header
#pragma once
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <memory>
#include <vector>
#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
/**
* Linux Unified Key Setup (LUKS) is a format specification for storing disk
* encryption parameters and up to 8 user keys (which can unlock the master key).
* \sa https://gitlab.com/cryptsetup/cryptsetup/-/wikis/LUKS-standard/on-disk-format.pdf Source
*/
class luks_t : public kaitai::kstruct {
public:
class partition_header_t;
luks_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, luks_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~luks_t();
class partition_header_t : public kaitai::kstruct {
public:
class key_slot_t;
partition_header_t(kaitai::kstream* p__io, luks_t* p__parent = nullptr, luks_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~partition_header_t();
class key_slot_t : public kaitai::kstruct {
public:
enum key_slot_states_t {
KEY_SLOT_STATES_DISABLED_KEY_SLOT = 57005,
KEY_SLOT_STATES_ENABLED_KEY_SLOT = 11301363
};
key_slot_t(kaitai::kstream* p__io, luks_t::partition_header_t* p__parent = nullptr, luks_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~key_slot_t();
private:
bool f_key_material;
std::string m_key_material;
public:
std::string key_material();
private:
key_slot_states_t m_state_of_key_slot;
uint32_t m_iteration_parameter;
std::string m_salt_parameter;
uint32_t m_start_sector_of_key_material;
uint32_t m_number_of_anti_forensic_stripes;
luks_t* m__root;
luks_t::partition_header_t* m__parent;
public:
key_slot_states_t state_of_key_slot() const { return m_state_of_key_slot; }
uint32_t iteration_parameter() const { return m_iteration_parameter; }
std::string salt_parameter() const { return m_salt_parameter; }
uint32_t start_sector_of_key_material() const { return m_start_sector_of_key_material; }
uint32_t number_of_anti_forensic_stripes() const { return m_number_of_anti_forensic_stripes; }
luks_t* _root() const { return m__root; }
luks_t::partition_header_t* _parent() const { return m__parent; }
};
private:
std::string m_magic;
std::string m_version;
std::string m_cipher_name_specification;
std::string m_cipher_mode_specification;
std::string m_hash_specification;
uint32_t m_payload_offset;
uint32_t m_number_of_key_bytes;
std::string m_master_key_checksum;
std::string m_master_key_salt_parameter;
uint32_t m_master_key_iterations_parameter;
std::string m_uuid;
std::unique_ptr<std::vector<std::unique_ptr<key_slot_t>>> m_key_slots;
luks_t* m__root;
luks_t* m__parent;
public:
std::string magic() const { return m_magic; }
std::string version() const { return m_version; }
std::string cipher_name_specification() const { return m_cipher_name_specification; }
std::string cipher_mode_specification() const { return m_cipher_mode_specification; }
std::string hash_specification() const { return m_hash_specification; }
uint32_t payload_offset() const { return m_payload_offset; }
uint32_t number_of_key_bytes() const { return m_number_of_key_bytes; }
std::string master_key_checksum() const { return m_master_key_checksum; }
std::string master_key_salt_parameter() const { return m_master_key_salt_parameter; }
uint32_t master_key_iterations_parameter() const { return m_master_key_iterations_parameter; }
std::string uuid() const { return m_uuid; }
std::vector<std::unique_ptr<key_slot_t>>* key_slots() const { return m_key_slots.get(); }
luks_t* _root() const { return m__root; }
luks_t* _parent() const { return m__parent; }
};
private:
bool f_payload;
std::string m_payload;
public:
std::string payload();
private:
std::unique_ptr<partition_header_t> m_partition_header;
luks_t* m__root;
kaitai::kstruct* m__parent;
public:
partition_header_t* partition_header() const { return m_partition_header.get(); }
luks_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
};
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "luks.h"
#include "kaitai/exceptions.h"
luks_t::luks_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, luks_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = this;
m_partition_header = nullptr;
f_payload = false;
_read();
}
void luks_t::_read() {
m_partition_header = std::unique_ptr<partition_header_t>(new partition_header_t(m__io, this, m__root));
}
luks_t::~luks_t() {
_clean_up();
}
void luks_t::_clean_up() {
if (f_payload) {
}
}
luks_t::partition_header_t::partition_header_t(kaitai::kstream* p__io, luks_t* p__parent, luks_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_key_slots = nullptr;
_read();
}
void luks_t::partition_header_t::_read() {
m_magic = m__io->read_bytes(6);
if (!(magic() == std::string("\x4C\x55\x4B\x53\xBA\xBE", 6))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\x4C\x55\x4B\x53\xBA\xBE", 6), magic(), _io(), std::string("/types/partition_header/seq/0"));
}
m_version = m__io->read_bytes(2);
if (!(version() == std::string("\x00\x01", 2))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\x00\x01", 2), version(), _io(), std::string("/types/partition_header/seq/1"));
}
m_cipher_name_specification = kaitai::kstream::bytes_to_str(m__io->read_bytes(32), std::string("ASCII"));
m_cipher_mode_specification = kaitai::kstream::bytes_to_str(m__io->read_bytes(32), std::string("ASCII"));
m_hash_specification = kaitai::kstream::bytes_to_str(m__io->read_bytes(32), std::string("ASCII"));
m_payload_offset = m__io->read_u4be();
m_number_of_key_bytes = m__io->read_u4be();
m_master_key_checksum = m__io->read_bytes(20);
m_master_key_salt_parameter = m__io->read_bytes(32);
m_master_key_iterations_parameter = m__io->read_u4be();
m_uuid = kaitai::kstream::bytes_to_str(m__io->read_bytes(40), std::string("ASCII"));
m_key_slots = std::unique_ptr<std::vector<std::unique_ptr<key_slot_t>>>(new std::vector<std::unique_ptr<key_slot_t>>());
const int l_key_slots = 8;
for (int i = 0; i < l_key_slots; i++) {
m_key_slots->push_back(std::move(std::unique_ptr<key_slot_t>(new key_slot_t(m__io, this, m__root))));
}
}
luks_t::partition_header_t::~partition_header_t() {
_clean_up();
}
void luks_t::partition_header_t::_clean_up() {
}
luks_t::partition_header_t::key_slot_t::key_slot_t(kaitai::kstream* p__io, luks_t::partition_header_t* p__parent, luks_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
f_key_material = false;
_read();
}
void luks_t::partition_header_t::key_slot_t::_read() {
m_state_of_key_slot = static_cast<luks_t::partition_header_t::key_slot_t::key_slot_states_t>(m__io->read_u4be());
m_iteration_parameter = m__io->read_u4be();
m_salt_parameter = m__io->read_bytes(32);
m_start_sector_of_key_material = m__io->read_u4be();
m_number_of_anti_forensic_stripes = m__io->read_u4be();
}
luks_t::partition_header_t::key_slot_t::~key_slot_t() {
_clean_up();
}
void luks_t::partition_header_t::key_slot_t::_clean_up() {
if (f_key_material) {
}
}
std::string luks_t::partition_header_t::key_slot_t::key_material() {
if (f_key_material)
return m_key_material;
std::streampos _pos = m__io->pos();
m__io->seek((start_sector_of_key_material() * 512));
m_key_material = m__io->read_bytes((_parent()->number_of_key_bytes() * number_of_anti_forensic_stripes()));
m__io->seek(_pos);
f_key_material = true;
return m_key_material;
}
std::string luks_t::payload() {
if (f_payload)
return m_payload;
std::streampos _pos = m__io->pos();
m__io->seek((partition_header()->payload_offset() * 512));
m_payload = m__io->read_bytes_full();
m__io->seek(_pos);
f_payload = true;
return m_payload;
}