SASC
DVBSoftCAM

FFdecsa.h File Reference

Go to the source code of this file.

Functions

int get_internal_parallelism (void)
int get_suggested_cluster_size (void)
void * get_key_struct (void)
void free_key_struct (void *keys)
void set_control_words (void *keys, const unsigned char *even, const unsigned char *odd)
void set_even_control_word (void *keys, const unsigned char *even)
void set_odd_control_word (void *keys, const unsigned char *odd)
int decrypt_packets (void *keys, unsigned char **cluster)

Function Documentation

int decrypt_packets ( void *  keys,
unsigned char **  cluster 
)

Definition at line 562 of file FFdecsa.c.

References block_decypher_group(), cluster, COPY_8_BY, DBG, FFTABLEIN(), FFTABLEOUT(), FFTABLEOUTXORNBY(), g_swap, GROUP_PARALLELISM, i, csa_key_t::iA_g, csa_key_t::iB_g, j, k, csa_key_t::kkmulti, M_EMPTY, MEMALIGN, NULL, XOR_8_BY, XOREQ_4_BY, and XOREQ_8_BY.

Referenced by cDeCSA::Decrypt(), main(), and process_ts().

                                                        {
  // 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];
#ifdef COPY_UNALIGNED_PKT
  unsigned char *unaligned[GROUP_PARALLELISM];
  MEMALIGN unsigned char alignedBuff[GROUP_PARALLELISM][188];
#endif
  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<grouped;i++){
    DBG(fprintf(stderr,"%2i of %2i: pkt=%p len=%03i n=%2i residue=%i\n",i,grouped,g_pkt[i],g_len[i],g_n[i],g_residue[i]));
    }
  // grouped is always <= GROUP_PARALLELISM

#define g_swap(a,b) \
    pkt=g_pkt[a]; \
    g_pkt[a]=g_pkt[b]; \
    g_pkt[b]=pkt; \
\
    len=g_len[a]; \
    g_len[a]=g_len[b]; \
    g_len[b]=len; \
\
    offset=g_offset[a]; \
    g_offset[a]=g_offset[b]; \
    g_offset[b]=offset; \
\
    n=g_n[a]; \
    g_n[a]=g_n[b]; \
    g_n[b]=n; \
\
    residue=g_residue[a]; \
    g_residue[a]=g_residue[b]; \
    g_residue[b]=residue;

  // step 1: move n=23 packets before small packets
  t23=0;
  tsmall=grouped-1;
  for(;;){
    for(;t23<grouped;t23++){
      if(g_n[t23]!=23) break;
    }
DBG(fprintf(stderr,"t23 after for =%i\n",t23));
    
    for(;tsmall>=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;i<grouped;i++){
    DBG(fprintf(stderr,"%2i of %2i: pkt=%p len=%03i n=%2i residue=%i\n",i,grouped,g_pkt[i],g_len[i],g_n[i],g_residue[i]));
    }

  // step 2: sort small packets in decreasing order of n (bubble sort is enough)
  for(i=t23;i<grouped;i++){
    for(j=i+1;j<grouped;j++){
      if(g_n[j]>g_n[i]){
        g_swap(i,j);
      }
    }
  }
  DBG(fprintf(stderr,"POSTSORTING\n"));
  for(i=0;i<grouped;i++){
    DBG(fprintf(stderr,"%2i of %2i: pkt=%p len=%03i n=%2i residue=%i\n",i,grouped,g_pkt[i],g_len[i],g_n[i],g_residue[i]));
    }

  // we need to know how many packets need 23 iterations, how many 22...
  for(i=0;i<=23;i++){
    alive[i]=0;
  }
  // count
  alive[23-1]=t23;
  for(i=t23;i<grouped;i++){
    alive[g_n[i]-1]++;
  }
  // integrate
  for(i=22;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<GROUP_PARALLELISM, but it's not a problem,
// as final results will be discarded.
// random data makes debugging sessions difficult.
  for(j=0;j<GROUP_PARALLELISM*8;j++) stream_in[j]=0;
DBG(fprintf(stderr,"--- WARNING: you could gain speed by not initializing unused memory ---\n"));
#else
DBG(fprintf(stderr,"--- WARNING: DEBUGGING IS MORE DIFFICULT WHEN PROCESSING RANDOM DATA CHANGING AT EVERY RUN! ---\n"));
#endif

  for(g=0;g<grouped;g++){
    encp[g]=g_pkt[g];
    DBG(fprintf(stderr,"header[%i]=%p (%02x)\n",g,encp[g],*(encp[g])));
    encp[g]+=g_offset[g]; // skip header
#ifdef COPY_UNALIGNED_PKT
    if(((int)encp[g])&0x03) {
      memcpy(alignedBuff[g],encp[g],g_len[g]);
      unaligned[g]=encp[g];
      encp[g]=alignedBuff[g];
      }
    else unaligned[g]=0;
#endif
    FFTABLEIN(stream_in,g,encp[g]);
  }
//dump_mem("stream_in",stream_in,GROUP_PARALLELISM*8,BYPG);


  // ITER 0
DBG(fprintf(stderr,">>>>>ITER 0\n"));
  iter=0;
  stream_cypher_group_init(&regs,k->iA_g,k->iB_g,stream_in);
  // fill first ib
  for(g=0;g<alive[iter];g++){
    COPY_8_BY(ib+8*g,encp[g]);
  }
DBG(dump_mem("IB ",ib,8*alive[iter],8));
  // ITER 1..N-1
  for (iter=1;iter<23&&alive[iter-1]>0;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(&regs,stream_out);
//dump_mem("stream_out",stream_out,GROUP_PARALLELISM*8,BYPG);

    // alive packets: calc ib
    for(g=0;g<alive[iter];g++){
      FFTABLEOUT(ib+8*g,stream_out,g);
DBG(dump_mem("stream_out_ib ",ib+8*g,8,8));
// XOREQ8BY gcc bug? 2x4 ok, 8 ko    UPDATE: result ok but speed 1-2% slower (!!!???)
#if 1
      XOREQ_4_BY(ib+8*g,encp[g]+8);
      XOREQ_4_BY(ib+8*g+4,encp[g]+8+4);
#else
      XOREQ_8_BY(ib+8*g,encp[g]+8);
#endif
DBG(dump_mem("after_stream_xor_ib ",ib+8*g,8,8));
    }
    // alive packets: decrypt data
    for(g=0;g<alive[iter];g++){
DBG(dump_mem("before_ib_decrypt_data ",encp[g],8,8));
      XOR_8_BY(encp[g],ib+8*g,block_out+8*g);
DBG(dump_mem("after_ib_decrypt_data ",encp[g],8,8));
    }
    // just dead packets: write decrypted data
    for(g=alive[iter];g<alive[iter-1];g++){
DBG(dump_mem("jd_before_ib_decrypt_data ",encp[g],8,8));
      COPY_8_BY(encp[g],block_out+8*g);
DBG(dump_mem("jd_after_ib_decrypt_data ",encp[g],8,8));
    }
    // just dead packets: decrypt residue
    for(g=alive[iter];g<alive[iter-1];g++){
DBG(dump_mem("jd_before_decrypt_residue ",encp[g]+8,g_residue[g],g_residue[g]));
      FFTABLEOUTXORNBY(g_residue[g],encp[g]+8,stream_out,g);
DBG(dump_mem("jd_after_decrypt_residue ",encp[g]+8,g_residue[g],g_residue[g]));
    }
    // alive packets: pointers++
    for(g=0;g<alive[iter];g++) encp[g]+=8;
  };
  // ITER N
DBG(fprintf(stderr,">>>>>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<alive[iter-1];g++){
DBG(dump_mem("23jd_before_ib_decrypt_data ",encp[g],8,8));
    COPY_8_BY(encp[g],block_out+8*g);
DBG(dump_mem("23jd_after_ib_decrypt_data ",encp[g],8,8));
  }
  // no residue possible
  // so do nothing

  DBG(fprintf(stderr,"returning advanced=%i\n",advanced));

#ifdef COPY_UNALIGNED_PKT
  for(g=0;g<grouped;g++)
    if(unaligned[g]) memcpy(unaligned[g],alignedBuff[g],g_len[g]);
#endif

  M_EMPTY(); // restore CPU multimedia state

  return advanced;
}
void free_key_struct ( void *  keys)

Definition at line 506 of file FFdecsa.c.

References FREE.

Referenced by cDeCSA::~cDeCSA().

                                {
  return FREE(keys);
}
int get_internal_parallelism ( void  )

Definition at line 482 of file FFdecsa.c.

References GROUP_PARALLELISM.

                                  {
  return GROUP_PARALLELISM;
}
void* get_key_struct ( void  )

Definition at line 497 of file FFdecsa.c.

References keys, MALLOC, and set_control_words().

Referenced by connect_ffd(), and main().

                          {
  struct csa_keys_t *keys=(struct csa_keys_t *)MALLOC(sizeof(struct csa_keys_t));
  if(keys) {
    static const unsigned char pk[8] = { 0,0,0,0,0,0,0,0 };
    set_control_words(keys,pk,pk);
    }
  return keys;
}
int get_suggested_cluster_size ( void  )

Definition at line 488 of file FFdecsa.c.

References GROUP_PARALLELISM.

Referenced by cDeCSA::cDeCSA(), and connect_ffd().

void set_control_words ( void *  keys,
const unsigned char *  even,
const unsigned char *  odd 
)

Definition at line 540 of file FFdecsa.c.

References csa_keys_t::even, csa_keys_t::odd, and schedule_key().

Referenced by get_key_struct(), and main().

                                                                                    {
  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 *  even 
)

Definition at line 545 of file FFdecsa.c.

References csa_keys_t::even, and schedule_key().

Referenced by process_ts(), and cDeCSA::SetDescr().

                                                               {
  schedule_key(&((struct csa_keys_t *)keys)->even,pk);
}
void set_odd_control_word ( void *  keys,
const unsigned char *  odd 
)

Definition at line 549 of file FFdecsa.c.

References csa_keys_t::odd, and schedule_key().

Referenced by process_ts(), and cDeCSA::SetDescr().

                                                              {
  schedule_key(&((struct csa_keys_t *)keys)->odd,pk);
}
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines