Program Listing for File protocol.hpp

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

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

#ifndef DESFIRE_PROTOCOL_HPP
#define DESFIRE_PROTOCOL_HPP

#include <desfire/bits.hpp>
#include <desfire/crypto.hpp>
#include <desfire/log.h>
#include <memory>
#include <mlab/bin_data.hpp>

namespace desfire {

    struct block_tag {};

    class protocol {
    public:
        virtual void prepare_tx(bin_data &data, std::size_t offset, comm_mode mode) = 0;

        virtual bool confirm_rx(bin_data &data, comm_mode mode) = 0;

        virtual void init_session(bin_data const &random_data) = 0;

        [[nodiscard]] virtual bool is_legacy() const = 0;

        virtual ~protocol() = default;
    };

    class protocol_dummy final : public protocol {
    public:
        inline void prepare_tx(bin_data &, std::size_t, comm_mode mode) override;

        inline bool confirm_rx(bin_data &, comm_mode mode) override;

        inline void init_session(bin_data const &) override;

        [[nodiscard]] bool is_legacy() const override;
    };

    class protocol_legacy final : public protocol {
    public:
        static constexpr std::size_t block_size = 8;
        static constexpr std::size_t mac_size = 4;
        static constexpr std::size_t crc_size = 2;

        using block_t = mlab::tagged_array<block_tag, block_size>;
        using mac_t = mlab::tagged_array<mac_tag, mac_size>;

        explicit protocol_legacy(std::unique_ptr<crypto> crypto);

        void prepare_tx(bin_data &data, std::size_t offset, comm_mode mode) override;

        bool confirm_rx(bin_data &data, comm_mode mode) override;

        void init_session(bin_data const &random_data) override;

        [[nodiscard]] bool is_legacy() const override;

    private:
        [[nodiscard]] block_t &get_zeroed_iv();
        [[nodiscard]] crypto &crypto_provider();

        mac_t compute_mac(range<bin_data::const_iterator> data);

        static bool drop_padding_verify_crc(bin_data &d);

        block_t _iv;
        std::unique_ptr<crypto> _crypto;
    };


    class protocol_default final : public protocol {
    public:
        static constexpr std::size_t mac_size = 8;
        static constexpr std::size_t crc_size = 4;

        explicit protocol_default(std::unique_ptr<crypto_with_cmac> crypto);

        void prepare_tx(bin_data &data, std::size_t offset, comm_mode mode) override;

        bool confirm_rx(bin_data &data, comm_mode mode) override;

        void init_session(bin_data const &random_data) override;
        [[nodiscard]] bool is_legacy() const override;

    private:
        [[nodiscard]] crypto_with_cmac &crypto_provider();

        [[nodiscard]] range<std::uint8_t *> iv();

        bool drop_padding_verify_crc(bin_data &d, std::uint8_t status);


        std::unique_ptr<std::uint8_t[]> _iv;
        std::unique_ptr<crypto_with_cmac> _crypto;
    };
}// namespace desfire

namespace desfire {

    void protocol_dummy::prepare_tx(bin_data &, std::size_t, comm_mode mode) {
        if (mode != comm_mode::plain) {
            DESFIRE_LOGE("Dummy protocol supports only plain comm mode.");
        }
    }

    bool protocol_dummy::confirm_rx(bin_data &, comm_mode mode) {
        if (mode != comm_mode::plain) {
            DESFIRE_LOGE("Dummy protocol supports only plain comm mode.");
            return false;
        }
        return true;
    }

    void protocol_dummy::init_session(bin_data const &) {}

}// namespace desfire

#endif//DESFIRE_PROTOCOL_HPP