.. _program_listing_file_libspookyaction_include_desfire_crypto_algo.hpp: Program Listing for File crypto_algo.hpp ======================================== |exhale_lsh| :ref:`Return to documentation for file ` (``libspookyaction/include/desfire/crypto_algo.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // // Created by Pietro Saccardi on 02/01/2021. // #ifndef DESFIRE_CRYPTO_ALGO_HPP #define DESFIRE_CRYPTO_ALGO_HPP #include #include #include #include #include #include #include namespace desfire { struct randbytes { std::size_t n; constexpr explicit randbytes(std::size_t len) : n{len} {} }; static constexpr std::uint16_t crc16_init = 0x6363; static constexpr std::uint32_t crc32_init = 0xffffffff; [[nodiscard]] std::uint16_t compute_crc16(mlab::range data, std::uint16_t init = crc16_init); [[nodiscard]] std::uint32_t compute_crc32(mlab::range data, std::uint32_t init = crc32_init); [[nodiscard]] inline std::uint16_t compute_crc16(mlab::bin_data const &data, std::uint16_t init = crc16_init); [[nodiscard]] inline std::uint32_t compute_crc32(mlab::bin_data const &data, std::uint32_t init = crc32_init); [[nodiscard]] std::uint16_t compute_crc16(std::uint8_t data, std::uint16_t init = crc16_init); [[nodiscard]] std::uint32_t compute_crc32(std::uint8_t data, std::uint32_t init = crc32_init); template void lshift_sequence(It begin, It end, unsigned lshift); template void set_key_version(Container &c, std::uint8_t v); template [[nodiscard]] std::uint8_t get_key_version(Container const &c); template [[nodiscard]] std::pair find_crc_tail(ByteIterator begin, ByteIterator end, Fn &&crc_fn, N init, std::size_t block_size, bool incremental_crc, BytesContainer const &valid_padding_bytes); template [[nodiscard]] std::pair find_crc_tail(ByteIterator begin, ByteIterator end, Fn &&crc_fn, N init, std::size_t block_size, bool incremental_crc); }// namespace desfire namespace mlab { #ifndef DOXYGEN_SHOULD_SKIP_THIS bin_data &operator<<(bin_data &bd, desfire::randbytes const &rndb); #endif }// namespace mlab namespace desfire { template void lshift_sequence(It begin, It end, unsigned lshift) { using value_type = typename std::iterator_traits::value_type; static_assert(std::is_integral_v and std::is_unsigned_v); static constexpr unsigned value_nbits = sizeof(value_type) * 8; const unsigned complementary_rshift = value_nbits - std::min(value_nbits, lshift); if (begin != end) { It prev = begin++; for (; begin != end; prev = begin++) { *prev = ((*prev) << lshift) | ((*begin) >> complementary_rshift); } *prev <<= lshift; } } template std::pair find_crc_tail(ByteIterator begin, ByteIterator end, Fn &&crc_fn, N init, std::size_t block_size, bool incremental_crc, BytesContainer const &valid_padding_bytes) { static const auto nonzero_byte_pred = [&](std::uint8_t b) -> bool { return std::find(std::begin(valid_padding_bytes), std::end(valid_padding_bytes), b) == std::end(valid_padding_bytes); }; const bool multiple_of_block_size = std::distance(begin, end) % block_size == 0; if (not multiple_of_block_size) { DESFIRE_LOGE("Cannot scan for CRC tail if data length is not a multiple of the block size."); } if (begin != end and multiple_of_block_size) { // Find the last nonzero byte, get and iterator to the element past that. // You just have to scan the last block, and in the worst case, the last non-padding byte is the first // byte of the last block. // This is achieved by reverse scanning for a nonzero byte, and getting the underlying iterator. // Since the reverse iterator holds an underlying iterator to the next element (in the normal traversal // sense), we can just get that. const auto rev_end = std::reverse_iterator(end); auto end_payload = std::find_if(rev_end, rev_end + block_size, nonzero_byte_pred).base(); // Compute the crc until the supposed end of the payload N crc = crc_fn(begin, end_payload, init); while (crc != N(0) and end_payload != end) { if (incremental_crc) { // Update the crc with one byte at a time crc = crc_fn(end_payload, std::next(end_payload), crc); } else { // Recalculate the crc on the whole new sequence crc = crc_fn(begin, std::next(end_payload), init); } // Keep advancing the supposed end of the payload until end ++end_payload; } return {end_payload, crc == N(0)}; } return {end, false}; } template std::pair find_crc_tail(ByteIterator begin, ByteIterator end, Fn &&crc_fn, N init, std::size_t block_size, bool incremental_crc) { static constexpr std::array default_padding_bytes = {0x00, 0x80}; return find_crc_tail(begin, end, std::forward(crc_fn), init, block_size, incremental_crc, default_padding_bytes); } template void set_key_version(Container &c, std::uint8_t v) { std::uint_fast8_t i = 0; for (auto &b : c) { static_assert(std::is_same_v); if (++i > 8) { break; } b = (b & 0b11111110) | (v >> 7); v <<= 1; } } template std::uint8_t get_key_version(Container const &c) { std::uint8_t v = 0x0; std::uint_fast8_t i = 0; for (std::uint8_t b : c) { if (++i > 8) { break; } v = (v << 1) | (b & 0b00000001); } return v; } std::uint16_t compute_crc16(mlab::bin_data const &data, std::uint16_t init) { return compute_crc16(data.data_view(), init); } std::uint32_t compute_crc32(mlab::bin_data const &data, std::uint32_t init) { return compute_crc32(data.data_view(), init); } }// namespace desfire #endif//DESFIRE_CRYPTO_ALGO_HPP