.. _program_listing_file_libspookyaction_include_desfire_kdf.hpp: Program Listing for File kdf.hpp ================================ |exhale_lsh| :ref:`Return to documentation for file ` (``libspookyaction/include/desfire/kdf.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp // // Created by spak on 9/15/22. // #ifndef LIBSPOOKYACTION_KDF_HPP #define LIBSPOOKYACTION_KDF_HPP #include #include #include #include #include #include namespace desfire { class any_key; struct cipher_provider; template struct key; template [[nodiscard]] key_body kdf_an10922( cmac_keychain const &keychain, crypto &crypto, mlab::bin_data &diversify_input, std::array data_prepend_const); [[nodiscard]] any_key kdf_an10922(crypto &crypto, mlab::bin_data &diversify_input, std::uint8_t key_version); [[nodiscard]] any_key kdf_an10922(any_key const &key, cipher_provider &provider, mlab::bin_data &diversify_input); [[nodiscard]] key kdf_an10922(key const &key, cipher_provider &provider, mlab::bin_data &diversify_input); [[nodiscard]] key kdf_an10922(key const &key, cipher_provider &provider, mlab::bin_data &diversify_input); [[nodiscard]] key kdf_an10922(key const &key, cipher_provider &provider, mlab::bin_data &diversify_input); [[nodiscard]] key kdf_an10922(key const &key, cipher_provider &provider, mlab::bin_data &diversify_input); key_body<8> kdf_an10922(crypto_des_base &crypto, mlab::bin_data &diversify_input); key_body<16> kdf_an10922(crypto_2k3des_base &crypto, mlab::bin_data &diversify_input); key_body<24> kdf_an10922(crypto_3k3des_base &crypto, mlab::bin_data &diversify_input); key_body<16> kdf_an10922(crypto_aes_base &crypto, mlab::bin_data &diversify_input); key_body<8> kdf_an10922(crypto_des_base &crypto, mlab::bin_data &diversify_input, std::uint8_t key_version); key_body<16> kdf_an10922(crypto_2k3des_base &crypto, mlab::bin_data &diversify_input, std::uint8_t key_version); key_body<24> kdf_an10922(crypto_3k3des_base &crypto, mlab::bin_data &diversify_input, std::uint8_t key_version); }// namespace desfire namespace desfire { template key_body kdf_an10922( cmac_keychain const &keychain, crypto &crypto, mlab::bin_data &diversify_input, std::array data_prepend_const) { static constexpr auto MaxDiversifyLength = 2 * BlockSize - 1; static constexpr auto KeyLength = BlockSize * NBlocks; // This will be the final key returned. key_body diversified_key{}; std::fill_n(std::begin(diversified_key), KeyLength, 0); if (keychain.block_size() != BlockSize) { DESFIRE_LOGE("The keychain block size differs to the block size required by the ciphers: %u != %u.", keychain.block_size(), BlockSize); return diversified_key; } // We use at most 15 bits of the diversification data if (diversify_input.size() > MaxDiversifyLength) { DESFIRE_LOGW("Too long diversification input, %d > %u bytes. Will truncate.", diversify_input.size(), MaxDiversifyLength); diversify_input.resize(MaxDiversifyLength); } // The CMAC procedure will process a total of 2 blocks of data. We use the diversification input as a buffer: diversify_input.reserve(2 * BlockSize); // For each block, we need to insert a different constant in front of the diversification data. For now, put zero. diversify_input.insert(std::begin(diversify_input), 0); // Preprocess the diversification input. It should never alter the first block: keychain.prepare_cmac_data(diversify_input, 2 * BlockSize); assert(diversify_input.size() == 2 * BlockSize); assert(diversify_input[0] == 0); // Each block is always processed in the same way: auto process_one_block = [&](std::uint8_t block_data_prepend_const, std::size_t offset_in_diversified_key) { // Set the first constant to be the requested one diversify_input[0] = block_data_prepend_const; // The new piece of the final key is now at zero, so we can use it as an IV and then copy over it const range iv{ std::begin(diversified_key) + offset_in_diversified_key, std::begin(diversified_key) + offset_in_diversified_key + BlockSize}; // Perform crypto in CMAC mode with a zero block IV. crypto.do_crypto(diversify_input.data_view(), iv, crypto_operation::mac); // Copy the last block of the diversified data onto the key std::copy(std::begin(diversify_input) + BlockSize, std::end(diversify_input), std::begin(iv)); }; if constexpr (NBlocks == 1) { // Just process the single block process_one_block(data_prepend_const[0], 0); } else { // We will need to do NBlock interations, so we will need a copy of the current data. std::array diversify_input_backup{}; std::copy(std::begin(diversify_input), std::end(diversify_input), std::begin(diversify_input_backup)); // Now loop once for each block for (std::uint_fast8_t block_idx = 0; block_idx < NBlocks; ++block_idx) { if (block_idx > 0) { // We need to restore the original data std::copy(std::begin(diversify_input_backup), std::end(diversify_input_backup), std::begin(diversify_input)); } process_one_block(data_prepend_const[block_idx], BlockSize * block_idx); } } return diversified_key; } }// namespace desfire #endif//LIBSPOOKYACTION_KDF_HPP