/*use Array: all; use String: {to_string,strlen,tochar};*/ use StdIO: all; use Structures: all; int[.] des( int[.] input, int[.,.] subkeys) { IP = [ 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7]; IPinv = [ 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25]; permutation = overSel( IP-1, input); l = take( shape( permutation)/2, permutation); r = drop( shape( permutation)/2, permutation); for( i=0; i <16; i++) { new_l = r; new_r = binPlus( l , cipher( r, subkeys[i])); l = new_l; r = new_r; } output = overSel( IPinv-1, r++l); return( output); } int[.] cipher( int[.] r, int[.]k) { E = [32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1]; P = [16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25]; S1 = reshape( [4,16], [ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]); S2 = reshape( [4,16], [ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]); S3 = reshape( [4,16], [ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]); S4 = reshape( [4,16], [ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]); S5 = reshape( [4,16], [ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]); S6 = reshape( [4,16], [ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]); S7 = reshape( [4,16], [ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]); S8 = reshape( [4,16], [ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]); S = reshape( [8, 4, 16, 4], hex2bits(S1) ++ hex2bits(S2) ++ hex2bits(S3) ++ hex2bits(S4) ++ hex2bits(S5) ++ hex2bits(S6) ++ hex2bits(S7) ++ hex2bits(S8)); sinput = reshape( [8,6], binPlus( overSel( E-1, r), k)); soutput = { [i] -> S[ [ i, sinput[[i,0]]*2 + sinput[[i,5]], sinput[[i,1]]*8 + sinput[[i,2]]*4 + sinput[[i,3]]*2 + sinput[[i,4]] ]] }; res = overSel( P-1, reshape( [32], soutput)); return( res); } int[4] hex2bits( int i) { n0 = [0,0,0,0]; n1 = [0,0,0,1]; n2 = [0,0,1,0]; n3 = [0,0,1,1]; n4 = [0,1,0,0]; n5 = [0,1,0,1]; n6 = [0,1,1,0]; n7 = [0,1,1,1]; n8 = [1,0,0,0]; n9 = [1,0,0,1]; n10 = [1,0,1,0]; n11 = [1,0,1,1]; n12 = [1,1,0,0]; n13 = [1,1,0,1]; n14 = [1,1,1,0]; n15 = [1,1,1,1]; n = [ n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15]; return( n[[i]]); } int[*] hex2bits( int[*] is) { res = { iv -> hex2bits( is[iv])}; return( res); } int[.] overSel( int[.]idcs, int[.] array) { res = { [i] -> array[idcs[[i]]] }; return( res); } int[*] binPlus( int[*] a, int[*] b) { res = { iv -> binPlus( a[iv], b[iv]) }; return( res); } int binPlus( int a, int b) { return( (a+b) %2); } int[ ., .] genSubKeys( int[.] key) { PC_1 = [57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4]; PC_2 = [14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 19, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32]; ROTATES = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]; pc_1 = overSel( PC_1-1, key); c0 = take( shape( pc_1)/2, pc_1); d0 = drop( shape( pc_1)/2, pc_1); res = with { ( . <= iv <= . ) : overSel( PC_2-1, rotate( 0, sum( take( iv+1, -ROTATES)), c0) ++ rotate( 0, sum( take( iv+1, -ROTATES)), d0)); } : genarray( [16], genarray( [48], 0 ) ); return( res); } int[.] int2byte( int x) { return( (x / [128,64,32,16,8,4,2,1]) % 2 ); } int byte2int( int[8] b) { return( sum( b * [128,64,32,16,8,4,2,1])); } int[*] string2bitBlocks( String::string s) { len = strlen( s); FibrePrint( "len:"); FibrePrint( len); pad = ( len % 8 == 0 ? 0 : 8 - len % 8); FibrePrint( "pad:"); FibrePrint( pad); ints = toi( tochar( s) ++ genarray( [pad], ' ')); bytes = { [i] -> int2byte( ints[[i]]) }; res = reshape( [ (len+ pad) / 8, 64 ], bytes); return( res); } String::string bitBlocks2string( int[.,.] bits) { bytes = reshape( [shape(bits)[0]*8] ++ [8], bits); ints = { [i] -> byte2int( bytes[[i]]) }; res = to_string( tochar( ints)); return( res); } int main() { k_hex = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; k = reshape( [64], hex2bits( k_hex)); input_bits = string2bitBlocks( "1024"); subkeys = genSubKeys( k); enciphered = { [i] -> des( input_bits[[i]], subkeys)}; FibrePrint( "enciphered data:\n"); FibrePrint( enciphered); FibrePrint( "deciphering data:\n"); deciphered = { [i] -> des( enciphered[[i]], reverse( subkeys))}; FibrePrint( "deciphered data:\n"); FibrePrint( deciphered); FibrePrint( "The deciphered text is: \n"); FibrePrint( bitBlocks2string( deciphered)); return( 0); }