// simeck.cpp - written and placed in the public domain by Gangqiang Yang and Jeffrey Walton. // Based on "The Simeck Family of Lightweight Block Ciphers" by Gangqiang Yang, // Bo Zhu, Valentin Suder, Mark D. Aagaard, and Guang Gong #include "pch.h" #include "config.h" #include "simeck.h" #include "misc.h" #include "cpu.h" ANONYMOUS_NAMESPACE_BEGIN using CryptoPP::rotlConstant; using CryptoPP::rotrConstant; /// \brief SIMECK encryption round /// \tparam T word type /// \param key the key for the round or iteration /// \param left the first value /// \param right the second value /// \details SIMECK_Encryption serves as the key schedule, encryption and /// decryption functions. template inline void SIMECK_Encryption(const T key, T& left, T& right) { const T temp = left; left = (left & rotlConstant<5>(left)) ^ rotlConstant<1>(left) ^ right ^ key; right = temp; } ANONYMOUS_NAMESPACE_END NAMESPACE_BEGIN(CryptoPP) std::string SIMECK32::Base::AlgorithmProvider() const { return "C++"; } void SIMECK32::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) { CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(keyLength); GetBlock kblock(userKey); kblock(m_t[3])(m_t[2])(m_t[1])(m_t[0]); word16 constant = 0xFFFC; word32 sequence = 0x9A42BB1F; for (unsigned int i = 0; i < ROUNDS; ++i) { m_rk[i] = m_t[0]; constant &= 0xFFFC; constant |= sequence & 1; sequence >>= 1; SIMECK_Encryption(static_cast(constant), m_t[1], m_t[0]); // rotate the LFSR of m_t m_t[4] = m_t[1]; m_t[1] = m_t[2]; m_t[2] = m_t[3]; m_t[3] = m_t[4]; } } void SIMECK32::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const { // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. GetBlock iblock(inBlock); iblock(m_t[1])(m_t[0]); for (int idx = 0; idx < ROUNDS; ++idx) SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); PutBlock oblock(xorBlock, outBlock); oblock(m_t[1])(m_t[0]); } void SIMECK32::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const { // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. GetBlock iblock(inBlock); iblock(m_t[0])(m_t[1]); for (int idx = ROUNDS - 1; idx >= 0; --idx) SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); PutBlock oblock(xorBlock, outBlock); oblock(m_t[0])(m_t[1]); } std::string SIMECK64::Base::AlgorithmProvider() const { return "C++"; } void SIMECK64::Base::UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms) { CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(keyLength); GetBlock kblock(userKey); kblock(m_t[3])(m_t[2])(m_t[1])(m_t[0]); word64 constant = W64LIT(0xFFFFFFFC); word64 sequence = W64LIT(0x938BCA3083F); for (unsigned int i = 0; i < ROUNDS; ++i) { m_rk[i] = m_t[0]; constant &= W64LIT(0xFFFFFFFC); constant |= sequence & 1; sequence >>= 1; SIMECK_Encryption(static_cast(constant), m_t[1], m_t[0]); // rotate the LFSR of m_t m_t[4] = m_t[1]; m_t[1] = m_t[2]; m_t[2] = m_t[3]; m_t[3] = m_t[4]; } } void SIMECK64::Enc::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const { // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. GetBlock iblock(inBlock); iblock(m_t[1])(m_t[0]); for (int idx = 0; idx < ROUNDS; ++idx) SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); PutBlock oblock(xorBlock, outBlock); oblock(m_t[1])(m_t[0]); } void SIMECK64::Dec::ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const { // Do not cast the buffer. It will SIGBUS on some ARM and SPARC. GetBlock iblock(inBlock); iblock(m_t[0])(m_t[1]); for (int idx = ROUNDS - 1; idx >= 0; --idx) SIMECK_Encryption(m_rk[idx], m_t[1], m_t[0]); PutBlock oblock(xorBlock, outBlock); oblock(m_t[0])(m_t[1]); } NAMESPACE_END