2021-12-05 15:47:31 +01:00
# include <iostream>
# include <sstream>
# include <array>
2021-12-05 15:58:56 +01:00
# include <bitset>
2021-12-05 15:47:31 +01:00
2021-12-05 16:38:42 +01:00
# define BLOCK_SIZE 128
2021-12-05 15:58:56 +01:00
# define FEISTELBLOCK_SIZE (BLOCK_SIZE / 2)
2021-12-05 17:09:01 +01:00
# define N_ROUNDS 64
2021-12-05 15:47:31 +01:00
2021-12-05 15:58:56 +01:00
typedef std : : bitset < BLOCK_SIZE > Block ;
typedef std : : bitset < FEISTELBLOCK_SIZE > Feistelblock ;
2021-12-05 17:09:01 +01:00
typedef std : : array < Feistelblock , N_ROUNDS > Keyset ;
2021-12-05 15:58:56 +01:00
2021-12-05 16:38:42 +01:00
// Will convert a string to a data block
Block StringToBits ( const std : : string & s ) ;
2021-12-05 15:47:31 +01:00
2021-12-05 16:38:42 +01:00
// Will convert a data block to a string
std : : string BitsToString ( const Block & bits ) ;
2021-12-05 16:15:11 +01:00
// Split a data block into two feistel blocks (into L and R)
std : : pair < Feistelblock , Feistelblock > FeistelSplit ( const Block & block ) ;
// Combine two feistel blocks (L and R) into a regular data block
Block FeistelCombine ( const Feistelblock & l , const Feistelblock & r ) ;
2021-12-05 17:09:01 +01:00
// Will generate a keyset from a seed-key
Keyset GenerateRoundkeys ( const Feistelblock & seedKey ) ;
2021-12-05 16:15:11 +01:00
// Feistel-cipher
2021-12-05 17:09:01 +01:00
Block Feistel ( const Block & data , const Keyset & keys , bool reverseKeyOrder = false ) ;
2021-12-05 16:15:11 +01:00
// Arbitrary cipher function
Feistelblock F ( Feistelblock m , const Feistelblock & key ) ;
2021-12-05 15:47:31 +01:00
int main ( )
{
2021-12-05 17:09:01 +01:00
const std : : string asciiMessage = " Guten Abend! " ;
2021-12-05 16:38:42 +01:00
Block message = StringToBits ( asciiMessage ) ;
2021-12-05 16:15:11 +01:00
2021-12-05 17:09:01 +01:00
const Feistelblock seedKey ( StringToBits ( " Ich bin ein PASSWORT-SCHLÜSSEL! " ) . to_string ( ) ) ; // StringToBits returns a bitset that's too large. We have to trim it to fit the smaller FeistelBlock bitset.
const Keyset roundkeys = GenerateRoundkeys ( seedKey ) ;
//std::cout << "Keys: " << std::endl;
//for (std::size_t i = 0; i < roundkeys.size(); i++)
// std::cout << roundkeys[i] << std::endl;
//std::cout << "---" << std::endl;
2021-12-05 15:47:31 +01:00
2021-12-05 16:38:42 +01:00
std : : cout < < " Message ascii: " < < asciiMessage < < std : : endl ;
std : : cout < < " Message: " < < message < < std : : endl ;
2021-12-05 15:47:31 +01:00
2021-12-05 17:09:01 +01:00
Block ciphertext = Feistel ( message , roundkeys ) ;
2021-12-05 16:38:42 +01:00
std : : cout < < " Ciphertext: " < < ciphertext < < std : : endl ;
2021-12-05 15:47:31 +01:00
2021-12-05 17:09:01 +01:00
Block decrypted = Feistel ( ciphertext , roundkeys , true ) ;
2021-12-05 16:38:42 +01:00
std : : cout < < " Decrypted: " < < decrypted < < std : : endl ;
const std : : string asciiDecrypted = BitsToString ( decrypted ) ;
std : : cout < < " Decrypted ascii: " < < asciiDecrypted < < std : : endl ;
2021-12-05 15:47:31 +01:00
return 0 ;
}
2021-12-05 17:09:01 +01:00
Block Feistel ( const Block & data , const Keyset & keys , bool reverseKeyOrder )
2021-12-05 15:47:31 +01:00
{
2021-12-05 16:15:11 +01:00
const auto splitData = FeistelSplit ( data ) ;
Feistelblock l = splitData . first ;
Feistelblock r = splitData . second ;
2021-12-05 15:58:56 +01:00
Feistelblock tmp ;
2021-12-05 15:47:31 +01:00
for ( std : : size_t i = 0 ; i < N_ROUNDS ; i + + )
{
// Calculate key index
std : : size_t keyIndex ;
if ( reverseKeyOrder )
keyIndex = N_ROUNDS - i - 1 ;
else
keyIndex = i ;
// Do a feistel round
tmp = r ;
2021-12-05 15:58:56 +01:00
r = l ^ F ( r , keys [ keyIndex ] ) ;
2021-12-05 15:47:31 +01:00
l = tmp ;
}
2021-12-05 16:15:11 +01:00
return FeistelCombine ( r , l ) ;
2021-12-05 15:47:31 +01:00
}
2021-12-05 15:58:56 +01:00
Feistelblock F ( Feistelblock m , const Feistelblock & key )
2021-12-05 15:47:31 +01:00
{
// Made-up F function
2021-12-05 17:09:01 +01:00
// Shift to left by 3 for every 1 in the key
for ( std : : size_t i = 0 ; i < key . size ( ) ; i + + )
if ( key [ i ] )
m < < = 3 ;
2021-12-05 15:47:31 +01:00
// Xor with key
2021-12-05 15:58:56 +01:00
return m ^ key ;
2021-12-05 15:47:31 +01:00
}
2021-12-05 16:15:11 +01:00
2021-12-05 16:38:42 +01:00
Block StringToBits ( const std : : string & s )
{
std : : stringstream ss ;
for ( std : : size_t i = 0 ; i < s . size ( ) ; i + + )
ss < < std : : bitset < 8 > ( s [ i ] ) ;
// Pad rest with zeores
for ( std : : size_t i = s . size ( ) * 8 ; i < BLOCK_SIZE ; i + + )
ss < < ' 0 ' ;
return Block ( ss . str ( ) ) ;
}
std : : string BitsToString ( const Block & bits )
{
std : : stringstream ss ;
const std : : string bitstring = bits . to_string ( ) ;
for ( std : : size_t i = 0 ; i < BLOCK_SIZE ; i + = 8 )
{
ss < < ( char ) std : : bitset < 8 > ( bitstring . substr ( i , i + 8 ) ) . to_ulong ( ) ;
}
return ss . str ( ) ;
}
2021-12-05 16:15:11 +01:00
std : : pair < Feistelblock , Feistelblock > FeistelSplit ( const Block & block )
{
const std : : string bits = block . to_string ( ) ;
Feistelblock l ( bits . substr ( 0 , bits . size ( ) / 2 ) ) ;
Feistelblock r ( bits . substr ( bits . size ( ) / 2 ) ) ;
return std : : make_pair ( l , r ) ;
}
Block FeistelCombine ( const Feistelblock & l , const Feistelblock & r )
{
return Block ( l . to_string ( ) + r . to_string ( ) ) ;
}
2021-12-05 17:09:01 +01:00
Keyset GenerateRoundkeys ( const Feistelblock & seedKey )
{
Keyset keys ;
keys [ 0 ] = seedKey ;
for ( std : : size_t i = 1 ; i < keys . size ( ) ; i + + )
{
keys [ i ] = std : : hash < Feistelblock > { } ( keys [ i - 1 ] ) ;
}
return keys ;
}