/* FFdecsa -- fast decsa algorithm * * Copyright (C) 2003-2004 fatih89r * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include "FFdecsa.h" #ifndef NULL #define NULL 0 #endif //#define DEBUG #ifdef DEBUG #define DBG(a) a #else #define DBG(a) #endif //// parallelization stuff, large speed differences are possible // possible choices #define PARALLEL_32_4CHAR 320 #define PARALLEL_32_4CHARA 321 #define PARALLEL_32_INT 322 #define PARALLEL_64_8CHAR 640 #define PARALLEL_64_8CHARA 641 #define PARALLEL_64_2INT 642 #define PARALLEL_64_LONG 643 #define PARALLEL_64_MMX 644 #define PARALLEL_128_16CHAR 1280 #define PARALLEL_128_16CHARA 1281 #define PARALLEL_128_4INT 1282 #define PARALLEL_128_2LONG 1283 #define PARALLEL_128_2MMX 1284 #define PARALLEL_128_SSE 1285 #define PARALLEL_128_SSE2 1286 //////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// #ifndef PARALLEL_MODE #define PARALLEL_MODE PARALLEL_32_INT #endif //////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// #include "parallel_generic.h" //// conditionals #if PARALLEL_MODE==PARALLEL_32_4CHAR #include "parallel_032_4char.h" #elif PARALLEL_MODE==PARALLEL_32_4CHARA #include "parallel_032_4charA.h" #elif PARALLEL_MODE==PARALLEL_32_INT #include "parallel_032_int.h" #elif PARALLEL_MODE==PARALLEL_64_8CHAR #include "parallel_064_8char.h" #elif PARALLEL_MODE==PARALLEL_64_8CHARA #include "parallel_064_8charA.h" #elif PARALLEL_MODE==PARALLEL_64_2INT #include "parallel_064_2int.h" #elif PARALLEL_MODE==PARALLEL_64_LONG #include "parallel_064_long.h" #elif PARALLEL_MODE==PARALLEL_64_MMX #include "parallel_064_mmx.h" #elif PARALLEL_MODE==PARALLEL_128_16CHAR #include "parallel_128_16char.h" #elif PARALLEL_MODE==PARALLEL_128_16CHARA #include "parallel_128_16charA.h" #elif PARALLEL_MODE==PARALLEL_128_4INT #include "parallel_128_4int.h" #elif PARALLEL_MODE==PARALLEL_128_2LONG #include "parallel_128_2long.h" #elif PARALLEL_MODE==PARALLEL_128_2MMX #include "parallel_128_2mmx.h" #elif PARALLEL_MODE==PARALLEL_128_SSE #include "parallel_128_sse.h" #elif PARALLEL_MODE==PARALLEL_128_SSE2 #include "parallel_128_sse2.h" #else #error "unknown/undefined parallel mode" #endif // stuff depending on conditionals #define BYTES_PER_GROUP (GROUP_PARALLELISM/8) #define BYPG BYTES_PER_GROUP #define BITS_PER_GROUP GROUP_PARALLELISM #define BIPG BITS_PER_GROUP #ifndef MALLOC #define MALLOC(X) malloc(X) #endif #ifndef FREE #define FREE(X) free(X) #endif #ifndef MEMALIGN #define MEMALIGN #endif //// debug tool #ifdef DEBUG static void dump_mem(const char *string, const unsigned char *p, int len, int linelen){ int i; for(i=0;i>4)&0xf; iA[1]=(ck[0] )&0xf; iA[2]=(ck[1]>>4)&0xf; iA[3]=(ck[1] )&0xf; iA[4]=(ck[2]>>4)&0xf; iA[5]=(ck[2] )&0xf; iA[6]=(ck[3]>>4)&0xf; iA[7]=(ck[3] )&0xf; iB[0]=(ck[4]>>4)&0xf; iB[1]=(ck[4] )&0xf; iB[2]=(ck[5]>>4)&0xf; iB[3]=(ck[5] )&0xf; iB[4]=(ck[6]>>4)&0xf; iB[5]=(ck[6] )&0xf; iB[6]=(ck[7]>>4)&0xf; iB[7]=(ck[7] )&0xf; } //----- stream main function #define STREAM_INIT #include "stream.c" #undef STREAM_INIT #define STREAM_NORMAL #include "stream.c" #undef STREAM_NORMAL //-----block decypher //-----key schedule for block decypher static void key_schedule_block( unsigned char *ck, // [In] ck[0]-ck[7] 8 bytes | Key. unsigned char *kk) // [Out] kk[0]-kk[55] 56 bytes | Key schedule. { static const unsigned char key_perm[0x40] = { 0x12,0x24,0x09,0x07,0x2A,0x31,0x1D,0x15, 0x1C,0x36,0x3E,0x32,0x13,0x21,0x3B,0x40, 0x18,0x14,0x25,0x27,0x02,0x35,0x1B,0x01, 0x22,0x04,0x0D,0x0E,0x39,0x28,0x1A,0x29, 0x33,0x23,0x34,0x0C,0x16,0x30,0x1E,0x3A, 0x2D,0x1F,0x08,0x19,0x17,0x2F,0x3D,0x11, 0x3C,0x05,0x38,0x2B,0x0B,0x06,0x0A,0x2C, 0x20,0x3F,0x2E,0x0F,0x03,0x26,0x10,0x37, }; int i,j,k; int bit[64]; int newbit[64]; int kb[7][8]; // 56 steps // 56 key bytes kk(55)..kk(0) by key schedule from ck // kb(6,0) .. kb(6,7) = ck(0) .. ck(7) kb[6][0] = ck[0]; kb[6][1] = ck[1]; kb[6][2] = ck[2]; kb[6][3] = ck[3]; kb[6][4] = ck[4]; kb[6][5] = ck[5]; kb[6][6] = ck[6]; kb[6][7] = ck[7]; // calculate kb[5] .. kb[0] for(i=5; i>=0; i--){ // 64 bit perm on kb for(j=0; j<8; j++){ for(k=0; k<8; k++){ bit[j*8+k] = (kb[i+1][j] >> (7-k)) & 1; newbit[key_perm[j*8+k]-1] = bit[j*8+k]; } } for(j=0; j<8; j++){ kb[i][j] = 0; for(k=0; k<8; k++){ kb[i][j] |= newbit[j*8+k] << (7-k); } } } // xor to give kk for(i=0; i<7; i++){ for(j=0; j<8; j++){ kk[i*8+j] = kb[i][j] ^ i; } } } //-----block utils static inline __attribute__((always_inline)) void trasp_N_8 (unsigned char *in,unsigned char* out,int count){ int *ri=(int *)in; int *ibi=(int *)out; int j,i,k,g; // copy and first step for(g=0;g>16) | (b&0xffff0000) ; } } } //dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); // now 01010101 for(j=0;j<8;j+=2){ for(i=0;i<1;i++){ for(k=0;k>8) | (b&0xff00ff00); } } } //dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); // now 00000000 } static inline __attribute__((always_inline)) void trasp_8_N (unsigned char *in,unsigned char* out,int count){ int *ri=(int *)in; int *bdi=(int *)out; int j,i,k,g; #define INTS_PER_ROW (GROUP_PARALLELISM/8*2) //dump_mem("NE1 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); // now 00000000 for(j=0;j<8;j+=2){ for(i=0;i<1;i++){ for(k=0;k>8) | (b&0xff00ff00); } } } //dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); // now 01010101 for(j=0;j<8;j+=4){ for(i=0;i<2;i++){ for(k=0;k>16) | (b&0xffff0000) ; } } } //dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); // now 01230123 for(g=0;g=0;i--){ { MEMALIGN batch tkkmulti=kkmulti[i]; batch *si=(batch *)sbox_in; batch *r6_N=(batch *)(r+roff+GROUP_PARALLELISM*6); for(g=0;gck,pk,8); // precalculations for stream key_schedule_stream(key->ck,key->iA,key->iB); for(by=0;by<8;by++){ for(bi=0;bi<8;bi++){ key->ck_g[by][bi]=(key->ck[by]&(1<iA_g[by][bi]=(key->iA[by]&(1<iB_g[by][bi]=(key->iB[by]&(1<ck,key->kk); for(i=0;i<56;i++){ for(j=0;jkkmulti[i])+j)=key->kk[i]; } } } void set_control_words(void *keys, const unsigned char *ev, const unsigned char *od){ schedule_key(&((struct csa_keys_t *)keys)->even,ev); schedule_key(&((struct csa_keys_t *)keys)->odd,od); } void set_even_control_word(void *keys, const unsigned char *pk){ schedule_key(&((struct csa_keys_t *)keys)->even,pk); } void set_odd_control_word(void *keys, const unsigned char *pk){ schedule_key(&((struct csa_keys_t *)keys)->odd,pk); } //-----get control words void get_control_words(void *keys, unsigned char *even, unsigned char *odd){ memcpy(even,&((struct csa_keys_t *)keys)->even.ck,8); memcpy(odd,&((struct csa_keys_t *)keys)->odd.ck,8); } //----- decrypt int decrypt_packets(void *keys, unsigned char **cluster){ // statistics, currently unused int stat_no_scramble=0; int stat_reserved=0; int stat_decrypted[2]={0,0}; int stat_decrypted_mini=0; unsigned char **clst; unsigned char **clst2; int grouped; int group_ev_od; int advanced; int can_advance; unsigned char *g_pkt[GROUP_PARALLELISM]; int g_len[GROUP_PARALLELISM]; int g_offset[GROUP_PARALLELISM]; int g_n[GROUP_PARALLELISM]; int g_residue[GROUP_PARALLELISM]; unsigned char *pkt; int xc0,ev_od,len,offset,n,residue; struct csa_key_t* k; int i,j,iter,g; int t23,tsmall; int alive[24]; //icc craziness int pad1=0; //////////align! FIXME unsigned char *encp[GROUP_PARALLELISM]; MEMALIGN unsigned char stream_in[GROUP_PARALLELISM*8]; MEMALIGN unsigned char stream_out[GROUP_PARALLELISM*8]; MEMALIGN unsigned char ib[GROUP_PARALLELISM*8]; MEMALIGN unsigned char block_out[GROUP_PARALLELISM*8]; struct stream_regs regs; //icc craziness i=(int)&pad1;//////////align!!! FIXME // build a list of packets to be processed clst=cluster; grouped=0; advanced=0; can_advance=1; group_ev_od=-1; // silence incorrect compiler warning pkt=*clst; do{ // find a new packet if(grouped==GROUP_PARALLELISM){ // full break; } if(pkt==NULL){ // no more ranges break; } if(pkt>=*(clst+1)){ // out of this range, try next clst++;clst++; pkt=*clst; continue; } do{ // handle this packet xc0=pkt[3]&0xc0; DBG(fprintf(stderr," exam pkt=%p, xc0=%02x, can_adv=%i\n",pkt,xc0,can_advance)); if(xc0==0x00){ DBG(fprintf(stderr,"skip clear pkt %p (can_advance is %i)\n",pkt,can_advance)); advanced+=can_advance; stat_no_scramble++; break; } if(xc0==0x40){ DBG(fprintf(stderr,"skip reserved pkt %p (can_advance is %i)\n",pkt,can_advance)); advanced+=can_advance; stat_reserved++; break; } if(xc0==0x80||xc0==0xc0){ // encrypted ev_od=(xc0&0x40)>>6; // 0 even, 1 odd if(grouped==0) group_ev_od=ev_od; // this group will be all even (or odd) if(group_ev_od==ev_od){ // could be added to group pkt[3]&=0x3f; // consider it decrypted now if(pkt[3]&0x20){ // incomplete packet offset=4+pkt[4]+1; len=188-offset; n=len>>3; residue=len-(n<<3); if(n==0){ // decrypted==encrypted! DBG(fprintf(stderr,"DECRYPTED MINI! (can_advance is %i)\n",can_advance)); advanced+=can_advance; stat_decrypted_mini++; break; // this doesn't need more processing } }else{ len=184; offset=4; n=23; residue=0; } g_pkt[grouped]=pkt; g_len[grouped]=len; g_offset[grouped]=offset; g_n[grouped]=n; g_residue[grouped]=residue; DBG(fprintf(stderr,"%2i: eo=%i pkt=%p len=%03i n=%2i residue=%i\n",grouped,ev_od,pkt,len,n,residue)); grouped++; advanced+=can_advance; stat_decrypted[ev_od]++; } else{ can_advance=0; DBG(fprintf(stderr,"skip pkt %p and can_advance set to 0\n",pkt)); break; // skip and go on } } } while(0); if(can_advance){ // move range start forward *clst+=188; } // next packet, if there is one pkt+=188; } while(1); DBG(fprintf(stderr,"-- result: grouped %i pkts, advanced %i pkts\n",grouped,advanced)); // delete empty ranges and compact list clst2=cluster; for(clst=cluster;*clst!=NULL;clst+=2){ // if not empty if(*clst<*(clst+1)){ // it will remain *clst2=*clst; *(clst2+1)=*(clst+1); clst2+=2; } } *clst2=NULL; if(grouped==0){ // no processing needed return advanced; } // sort them, longest payload first // we expect many n=23 packets and a few n<23 DBG(fprintf(stderr,"PRESORTING\n")); for(i=0;i=0;tsmall--){ if(g_n[tsmall]==23) break; } DBG(fprintf(stderr,"tsmall after for =%i\n",tsmall)); if(tsmall-t23<1) break; DBG(fprintf(stderr,"swap t23=%i,tsmall=%i\n",t23,tsmall)); g_swap(t23,tsmall); t23++; tsmall--; DBG(fprintf(stderr,"new t23=%i,tsmall=%i\n\n",t23,tsmall)); } DBG(fprintf(stderr,"packets with n=23, t23=%i grouped=%i\n",t23,grouped)); DBG(fprintf(stderr,"MIDSORTING\n")); for(i=0;ig_n[i]){ g_swap(i,j); } } } DBG(fprintf(stderr,"POSTSORTING\n")); for(i=0;i=0;i--){ alive[i]+=alive[i+1]; } DBG(fprintf(stderr,"ALIVE\n")); for(i=0;i<=23;i++){ DBG(fprintf(stderr,"alive%2i=%i\n",i,alive[i])); } // choose key if(group_ev_od==0){ k=&((struct csa_keys_t *)keys)->even; } else{ k=&((struct csa_keys_t *)keys)->odd; } //INIT //#define INITIALIZE_UNUSED_INPUT #ifdef INITIALIZE_UNUSED_INPUT // unnecessary zeroing. // without this, we operate on uninitialized memory // when grouped>>>>ITER 0\n")); iter=0; stream_cypher_group_init(®s,k->iA_g,k->iB_g,stream_in); // fill first ib for(g=0;g0;iter++){ DBG(fprintf(stderr,">>>>>ITER %i\n",iter)); // alive and just dead packets: calc block block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]); DBG(dump_mem("BLO_ib ",block_out,8*alive[iter-1],8)); // all packets (dead too): calc stream stream_cypher_group_normal(®s,stream_out); //dump_mem("stream_out",stream_out,GROUP_PARALLELISM*8,BYPG); // alive packets: calc ib for(g=0;g>>>>ITER 23\n")); iter=23; // calc block block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]); DBG(dump_mem("23BLO_ib ",block_out,8*alive[iter-1],8)); // just dead packets: write decrypted data for(g=alive[iter];g