Program Listing for File key_actor.hpp

Return to documentation for file (libspookyaction/include/desfire/key_actor.hpp)

//
// Created by Pietro Saccardi on 20/01/2021.
//

#ifndef DESFIRE_KEY_ACTOR_HPP
#define DESFIRE_KEY_ACTOR_HPP

#include <desfire/bits.hpp>
#include <desfire/log.h>

namespace desfire {

    struct no_key_t {};

    static constexpr no_key_t no_key{};

    template <class SpecialT>
    class key_actor {
        static constexpr std::uint8_t max_key_index = 0xd;
        static constexpr std::uint8_t special_value = 0xe;
        static constexpr std::uint8_t no_key_value = 0xf;

        static_assert(bits::max_keys_per_app == max_key_index + 1, "Implementation uses 0xE and 0xF for special purposes.");

        unsigned _repr : 4;

    public:
        inline void set_nibble(std::uint8_t v);
        [[nodiscard]] inline std::uint8_t get_nibble() const;

        constexpr key_actor();

        constexpr key_actor(std::uint8_t key_index);

        key_actor(bool) = delete;

        constexpr key_actor(SpecialT);

        constexpr key_actor(no_key_t);

        inline key_actor &operator=(std::uint8_t key_index);
        key_actor &operator=(bool) = delete;
        inline key_actor &operator=(SpecialT);
        inline key_actor &operator=(no_key_t);
        [[nodiscard]] constexpr char describe() const;

        inline bool operator==(key_actor const &other) const;
        inline bool operator!=(key_actor const &other) const;
    };

}// namespace desfire

namespace desfire {

    template <class SpecialT>
    constexpr key_actor<SpecialT>::key_actor(std::uint8_t key_index) : _repr{unsigned(key_index & 0b1111)} {
        if (not std::is_constant_evaluated()) {
            if (key_index >= desfire::bits::max_keys_per_app) {
                ESP_LOGW(DESFIRE_LOG_PREFIX, "Invalid key number %d", key_index);
            }
        }
    }

    template <class SpecialT>
    constexpr key_actor<SpecialT>::key_actor() : _repr{0} {}

    template <class SpecialT>
    constexpr key_actor<SpecialT>::key_actor(SpecialT) : _repr{special_value} {}

    template <class SpecialT>
    constexpr key_actor<SpecialT>::key_actor(no_key_t) : _repr{no_key_value} {}

    template <class SpecialT>
    void key_actor<SpecialT>::set_nibble(std::uint8_t v) {
        _repr = v & 0b1111;
    }

    template <class SpecialT>
    std::uint8_t key_actor<SpecialT>::get_nibble() const {
        return _repr;
    }

    template <class SpecialT>
    key_actor<SpecialT> &key_actor<SpecialT>::operator=(std::uint8_t key_index) {
        if (key_index > max_key_index) {
            DESFIRE_LOGE("Specified key index %u is not valid, master key (0) assumed.", key_index);
            key_index = 0;
        }
        set_nibble(key_index);
        return *this;
    }

    template <class SpecialT>
    key_actor<SpecialT> &key_actor<SpecialT>::operator=(SpecialT) {
        _repr = special_value;
        return *this;
    }

    template <class SpecialT>
    key_actor<SpecialT> &key_actor<SpecialT>::operator=(no_key_t) {
        _repr = no_key_value;
        return *this;
    }

    template <class SpecialT>
    constexpr char key_actor<SpecialT>::describe() const {
        if (_repr == special_value) {
            return 'S';
        } else if (_repr == no_key_value) {
            return 'N';
        } else {
            return "0123456789ABCDEF"[_repr];
        }
    }

    template <class SpecialT>
    bool key_actor<SpecialT>::operator==(key_actor const &other) const {
        return get_nibble() == other.get_nibble();
    }

    template <class SpecialT>
    bool key_actor<SpecialT>::operator!=(key_actor const &other) const {
        return get_nibble() != other.get_nibble();
    }
}// namespace desfire

#endif//DESFIRE_KEY_ACTOR_HPP