.. _program_listing_file_libspookyaction_include_desfire_data.hpp: Program Listing for File data.hpp ================================= |exhale_lsh| :ref:`Return to documentation for file ` (``libspookyaction/include/desfire/data.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // // Created by Pietro Saccardi on 03/01/2021. // #ifndef DESFIRE_DATA_HPP #define DESFIRE_DATA_HPP #include #include #include #include #include #include #include namespace desfire { struct app_id_tag {}; using app_id = mlab::tagged_array; static constexpr app_id root_app{0x0, 0x0, 0x0}; using file_id = std::uint8_t; enum struct error : std::uint8_t { out_of_eeprom = static_cast(bits::status::out_of_eeprom), illegal_command = static_cast(bits::status::illegal_command), integrity_error = static_cast(bits::status::integrity_error), no_such_key = static_cast(bits::status::no_such_key), length_error = static_cast(bits::status::length_error), permission_denied = static_cast(bits::status::permission_denied), parameter_error = static_cast(bits::status::parameter_error), app_not_found = static_cast(bits::status::app_not_found), app_integrity_error = static_cast(bits::status::app_integrity_error), authentication_error = static_cast(bits::status::authentication_error), boundary_error = static_cast(bits::status::boundary_error), picc_integrity_error = static_cast(bits::status::picc_integrity_error), command_aborted = static_cast(bits::status::command_aborted), picc_disabled_error = static_cast(bits::status::picc_disabled_error), count_error = static_cast(bits::status::count_error), duplicate_error = static_cast(bits::status::duplicate_error), eeprom_error = static_cast(bits::status::eeprom_error), file_not_found = static_cast(bits::status::file_not_found), file_integrity_error = static_cast(bits::status::file_integrity_error), controller_error, malformed, crypto_error }; [[nodiscard]] error error_from_status(bits::status s); struct same_key_t {}; static constexpr same_key_t same_key{}; struct key_rights { key_actor allowed_to_change_keys{same_key}; bool master_key_changeable = true; bool dir_access_without_auth = true; bool create_delete_without_master_key = false; bool config_changeable = true; [[nodiscard]] inline bool operator==(desfire::key_rights const &other) const; [[nodiscard]] inline bool operator!=(desfire::key_rights const &other) const; constexpr key_rights() = default; constexpr key_rights(key_actor allowed_to_change_keys_, bool master_key_changeable_, bool dir_access_without_auth_, bool create_delete_without_master_key_, bool config_changeable_) : allowed_to_change_keys{allowed_to_change_keys_}, master_key_changeable{master_key_changeable_}, dir_access_without_auth{dir_access_without_auth_}, create_delete_without_master_key{create_delete_without_master_key_}, config_changeable{config_changeable_} {} }; struct free_access_t {}; static constexpr free_access_t free_access{}; enum struct file_access { change, read, write }; struct file_access_rights { key_actor change; key_actor read_write; key_actor write; key_actor read; constexpr file_access_rights() = default; constexpr file_access_rights(no_key_t); constexpr file_access_rights(free_access_t); constexpr explicit file_access_rights(std::uint8_t single_key); explicit file_access_rights(bool) = delete; constexpr file_access_rights(key_actor rw, key_actor chg); constexpr file_access_rights(key_actor rw, key_actor chg, key_actor r, key_actor w); inline void set_word(std::uint16_t v); [[nodiscard]] inline std::uint16_t get_word() const; [[nodiscard]] inline static file_access_rights from_word(std::uint16_t word); [[nodiscard]] bool is_free(file_access access) const; [[nodiscard]] inline bool operator==(file_access_rights const &other) const; [[nodiscard]] inline bool operator!=(file_access_rights const &other) const; }; struct common_file_settings { file_security security = file_security::none; file_access_rights rights; constexpr common_file_settings() = default; constexpr common_file_settings(file_security security_, file_access_rights rights_); }; struct data_file_settings { std::uint32_t size = 0; constexpr data_file_settings() = default; explicit constexpr data_file_settings(std::uint32_t size_) : size{size_} {} }; struct value_file_settings { std::int32_t lower_limit = 0; std::int32_t upper_limit = 0; std::int32_t value = 0; bool limited_credit_enabled = false; constexpr value_file_settings() = default; constexpr value_file_settings(std::int32_t lowlim, std::int32_t uplim, std::int32_t v, bool enable_lim_credit = false) : lower_limit{lowlim}, upper_limit{uplim}, value{v}, limited_credit_enabled{enable_lim_credit} {} }; struct record_file_settings { std::uint32_t record_size = 0; std::uint32_t max_record_count = 0; std::uint32_t record_count = 0; constexpr record_file_settings() = default; constexpr record_file_settings(std::uint32_t rec_size, std::uint32_t max_rec_count, std::uint32_t rec_count = 0) : record_size{rec_size}, max_record_count{max_rec_count}, record_count{rec_count} {} }; template struct file_settings {}; template <> struct file_settings : public common_file_settings, public data_file_settings { using specific_file_settings = data_file_settings; constexpr file_settings() : common_file_settings{}, data_file_settings{} {} constexpr file_settings(common_file_settings generic, data_file_settings specific) : common_file_settings{generic}, data_file_settings{specific} {} constexpr file_settings(file_security security, file_access_rights rights, std::uint32_t size) : common_file_settings{security, rights}, data_file_settings{size} {} constexpr file_settings(common_file_settings generic, std::uint32_t size) : common_file_settings{generic}, data_file_settings{size} {} constexpr file_settings(file_security security, file_access_rights rights, data_file_settings specific) : common_file_settings{security, rights}, data_file_settings{specific} {} }; template <> struct file_settings : public common_file_settings, public data_file_settings { using specific_file_settings = data_file_settings; constexpr file_settings() : common_file_settings{}, data_file_settings{} {} constexpr file_settings(common_file_settings generic, data_file_settings specific) : common_file_settings{generic}, data_file_settings{specific} {} constexpr file_settings(file_security security, file_access_rights rights, std::uint32_t size) : common_file_settings{security, rights}, data_file_settings{size} {} constexpr file_settings(common_file_settings generic, std::uint32_t size) : common_file_settings{generic}, data_file_settings{size} {} constexpr file_settings(file_security security, file_access_rights rights, data_file_settings specific) : common_file_settings{security, rights}, data_file_settings{specific} {} }; template <> struct file_settings : public common_file_settings, public value_file_settings { using specific_file_settings = value_file_settings; constexpr file_settings() : common_file_settings{}, value_file_settings{0, 0, 0, false} {} constexpr file_settings(common_file_settings generic, value_file_settings specific) : common_file_settings{generic}, value_file_settings{specific} {} constexpr file_settings(file_security security, file_access_rights rights, std::int32_t lowlim, std::int32_t uplim, std::int32_t v, bool enable_lim_credit = false) : common_file_settings{security, rights}, value_file_settings{lowlim, uplim, v, enable_lim_credit} {} constexpr file_settings(common_file_settings generic, std::int32_t lowlim, std::int32_t uplim, std::int32_t v, bool enable_lim_credit = false) : common_file_settings{generic}, value_file_settings{lowlim, uplim, v, enable_lim_credit} {} constexpr file_settings(file_security security, file_access_rights rights, value_file_settings specific) : common_file_settings{security, rights}, value_file_settings{specific} {} }; template <> struct file_settings : public common_file_settings, public record_file_settings { using specific_file_settings = record_file_settings; constexpr file_settings() : common_file_settings{}, record_file_settings{0, 0, 0} {} constexpr file_settings(common_file_settings generic, record_file_settings specific) : common_file_settings{generic}, record_file_settings{specific} {} constexpr file_settings(file_security security, file_access_rights rights, std::uint32_t rec_size, std::uint32_t max_rec_count, std::uint32_t rec_count = 0) : common_file_settings{security, rights}, record_file_settings{rec_size, max_rec_count, rec_count} {} constexpr file_settings(common_file_settings generic, std::uint32_t rec_size, std::uint32_t max_rec_count, std::uint32_t rec_count = 0) : common_file_settings{generic}, record_file_settings{rec_size, max_rec_count, rec_count} {} constexpr file_settings(file_security security, file_access_rights rights, record_file_settings specific) : common_file_settings{security, rights}, record_file_settings{specific} {} }; template <> struct file_settings : public common_file_settings, public record_file_settings { using specific_file_settings = record_file_settings; constexpr file_settings() : common_file_settings{}, record_file_settings{0, 0, 0} {} constexpr file_settings(common_file_settings generic, record_file_settings specific) : common_file_settings{generic}, record_file_settings{specific} {} constexpr file_settings(file_security security, file_access_rights rights, std::uint32_t rec_size, std::uint32_t max_rec_count, std::uint32_t rec_count = 0) : common_file_settings{security, rights}, record_file_settings{rec_size, max_rec_count, rec_count} {} constexpr file_settings(common_file_settings generic, std::uint32_t rec_size, std::uint32_t max_rec_count, std::uint32_t rec_count = 0) : common_file_settings{generic}, record_file_settings{rec_size, max_rec_count, rec_count} {} constexpr file_settings(file_security security, file_access_rights rights, record_file_settings specific) : common_file_settings{security, rights}, record_file_settings{specific} {} }; class any_file_settings : public mlab::any_of { public: using mlab::any_of::any_of; [[nodiscard]] common_file_settings const &common_settings() const; [[nodiscard]] data_file_settings const &data_settings() const; [[nodiscard]] record_file_settings const &record_settings() const; [[nodiscard]] value_file_settings const &value_settings() const; [[nodiscard]] common_file_settings &common_settings(); [[nodiscard]] data_file_settings &data_settings(); [[nodiscard]] record_file_settings &record_settings(); [[nodiscard]] value_file_settings &value_settings(); }; struct app_settings { key_rights rights; std::uint8_t max_num_keys; app_crypto crypto; constexpr explicit app_settings(app_crypto crypto_ = app_crypto::legacy_des_2k3des, key_rights rights_ = key_rights{}, std::uint8_t max_num_keys_ = bits::max_keys_per_app); constexpr explicit app_settings(cipher_type cipher, key_rights rights_ = key_rights{}, std::uint8_t max_num_keys_ = bits::max_keys_per_app); }; class storage_size { std::uint8_t _flag; [[nodiscard]] inline unsigned exponent() const; [[nodiscard]] inline bool approx() const; public: explicit storage_size(std::size_t nbytes = 0); [[nodiscard]] inline std::size_t bytes_lower_bound() const; [[nodiscard]] inline std::size_t bytes_upper_bound() const; mlab::bin_stream &operator>>(mlab::bin_stream &s); mlab::bin_data &operator<<(mlab::bin_data &s) const; }; struct ware_info { std::uint8_t vendor_id = 0; std::uint8_t type = 0; std::uint8_t subtype = 0; std::uint8_t version_major = 0; std::uint8_t version_minor = 0; storage_size size; std::uint8_t comm_protocol_type = 0; }; struct manufacturing_info { ware_info hardware; ware_info software; std::array serial_no{}; std::array batch_no{}; std::uint8_t production_week = 0; std::uint8_t production_year = 0; }; }// namespace desfire namespace mlab { #ifndef DOXYGEN_SHOULD_SKIP_THIS bin_stream &operator>>(bin_stream &s, desfire::key_rights &kr); bin_stream &operator>>(bin_stream &s, desfire::app_settings &ks); bin_stream &operator>>(bin_stream &s, std::vector &ids); bin_stream &operator>>(bin_stream &s, desfire::ware_info &wi); bin_stream &operator>>(bin_stream &s, desfire::manufacturing_info &mi); bin_stream &operator>>(bin_stream &s, desfire::file_access_rights &ar); bin_stream &operator>>(bin_stream &s, desfire::common_file_settings &fs); bin_stream &operator>>(bin_stream &s, desfire::data_file_settings &fs); bin_stream &operator>>(bin_stream &s, desfire::value_file_settings &fs); bin_stream &operator>>(bin_stream &s, desfire::record_file_settings &fs); bin_stream &operator>>(bin_stream &s, desfire::any_file_settings &fs); template bin_stream &operator>>(bin_stream &s, desfire::file_settings &fs); bin_data &operator<<(bin_data &bd, desfire::key_rights const &kr); bin_data &operator<<(bin_data &bd, desfire::app_settings const &ks); bin_data &operator<<(bin_data &bd, desfire::file_access_rights const &ar); bin_data &operator<<(bin_data &bd, desfire::common_file_settings const &fs); bin_data &operator<<(bin_data &bd, desfire::data_file_settings const &fs); bin_data &operator<<(bin_data &bd, desfire::value_file_settings const &fs); bin_data &operator<<(bin_data &bd, desfire::record_file_settings const &fs); bin_data &operator<<(bin_data &bd, desfire::any_file_settings const &fs); template bin_data &operator<<(bin_data &bd, desfire::file_settings const &fs); #endif }// namespace mlab namespace desfire { constexpr app_settings::app_settings(app_crypto crypto_, key_rights rights_, std::uint8_t max_num_keys_) : rights{rights_}, max_num_keys{max_num_keys_}, crypto{crypto_} {} constexpr app_settings::app_settings(cipher_type cipher, key_rights rights_, std::uint8_t max_num_keys_) : rights{rights_}, max_num_keys{max_num_keys_}, crypto{app_crypto_from_cipher(cipher)} {} unsigned storage_size::exponent() const { return _flag >> bits::storage_size_exponent_shift; } bool storage_size::approx() const { return 0 != (_flag & bits::storage_size_approx_bit); } std::size_t storage_size::bytes_lower_bound() const { return 1 << exponent(); } std::size_t storage_size::bytes_upper_bound() const { return 1 << (approx() ? exponent() + 1 : exponent()); } constexpr file_access_rights::file_access_rights(std::uint8_t single_key) : change{single_key}, read_write{single_key}, write{single_key}, read{single_key} { // TODO: when C++20 is enabled, used is_constant_evaluated to issue a warning if single_key is out of range } constexpr file_access_rights::file_access_rights(no_key_t) : change{no_key}, read_write{no_key}, write{no_key}, read{no_key} {} constexpr file_access_rights::file_access_rights(free_access_t) : change{free_access}, read_write{free_access}, write{free_access}, read{free_access} {} constexpr file_access_rights::file_access_rights(key_actor rw, key_actor chg) : file_access_rights{no_key} { read_write = rw; change = chg; } constexpr file_access_rights::file_access_rights(key_actor rw, key_actor chg, key_actor r, key_actor w) : file_access_rights{no_key} { read_write = rw; change = chg; read = r; write = w; } std::uint16_t file_access_rights::get_word() const { return (std::uint16_t(read_write.get_nibble()) << bits::file_access_rights_read_write_shift) | (std::uint16_t(change.get_nibble()) << bits::file_access_rights_change_shift) | (std::uint16_t(read.get_nibble()) << bits::file_access_rights_read_shift) | (std::uint16_t(write.get_nibble()) << bits::file_access_rights_write_shift); } void file_access_rights::set_word(std::uint16_t v) { read_write.set_nibble(std::uint8_t((v >> bits::file_access_rights_read_write_shift) & 0b1111)); change.set_nibble(std::uint8_t((v >> bits::file_access_rights_change_shift) & 0b1111)); read.set_nibble(std::uint8_t((v >> bits::file_access_rights_read_shift) & 0b1111)); write.set_nibble(std::uint8_t((v >> bits::file_access_rights_write_shift) & 0b1111)); } file_access_rights file_access_rights::from_word(std::uint16_t word) { file_access_rights retval; retval.set_word(word); return retval; } bool file_access_rights::operator==(file_access_rights const &other) const { return change == other.change and read_write == other.read_write and write == other.write and read == other.read; } bool file_access_rights::operator!=(file_access_rights const &other) const { return change != other.change or read_write != other.read_write or write != other.write or read != other.read; } constexpr common_file_settings::common_file_settings(file_security security_, file_access_rights rights_) : security{security_}, rights{rights_} {} bool desfire::key_rights::operator==(desfire::key_rights const &other) const { return other.allowed_to_change_keys == allowed_to_change_keys and other.create_delete_without_master_key == create_delete_without_master_key and other.dir_access_without_auth == dir_access_without_auth and other.config_changeable == config_changeable and other.master_key_changeable == master_key_changeable; } bool desfire::key_rights::operator!=(desfire::key_rights const &other) const { return not operator==(other); } }// namespace desfire namespace mlab { template bin_stream &operator>>(bin_stream &s, desfire::file_settings &fs) { if (not s.bad()) { s >> static_cast(fs); } if (not s.bad()) { s >> static_cast::specific_file_settings &>(fs); } return s; } template bin_data &operator<<(bin_data &bd, desfire::file_settings const &fs) { return bd << static_cast(fs) << static_cast::specific_file_settings const &>(fs); } }// namespace mlab #endif//DESFIRE_DATA_HPP