./ MultiCS.r82 / msg-cccam.c
#include "common.h" #include <stdio.h> #include <string.h> #include <stdarg.h> #include <unistd.h> #ifdef WIN32 #include <windows.h> #include <sys/types.h> #include <sys/_default_fcntl.h> #include <sys/poll.h> #include <cygwin/types.h> #include <cygwin/socket.h> #include <sys/errno.h> #include <cygwin/in.h> #include <sched.h> #include <netdb.h> #include <netinet/tcp.h> #else #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <signal.h> #include <errno.h> #include <poll.h> #endif #include "debug.h" #include "msg-cccam.h" #include "sockets.h" /////////////////////////////////////////////////////////////////////////////// inline void cc_crypt_swap(unsigned char *p1, unsigned char *p2) { register unsigned char tmp=*p1; *p1=*p2; *p2=tmp; } /////////////////////////////////////////////////////////////////////////////// void cc_crypt_init( struct cc_crypt_block *block, uint8_t *key, int len) { register int i; for (i=0; i<256; i++) block->keytable[i] = i; register uint8_t j = 0; for (i=0; i<256; i++) { j += key[i % len] + block->keytable[i]; cc_crypt_swap(&block->keytable[i], &block->keytable[j]); } block->state = *key; block->counter=0; block->sum=0; } /////////////////////////////////////////////////////////////////////////////// // XOR init bytes with 'CCcam' void cc_crypt_xor(uint8_t *buf) { const char cccam[] = "CCcam"; buf[8+0] = 0 * buf[0]; buf[0] ^= cccam[0]; buf[8+1] = 1 * buf[1]; buf[1] ^= cccam[1]; buf[8+2] = 2 * buf[2]; buf[2] ^= cccam[2]; buf[8+3] = 3 * buf[3]; buf[3] ^= cccam[3]; buf[8+4] = 4 * buf[4]; buf[4] ^= cccam[4]; buf[8+5] = 5 * buf[5]; buf[5] ^= cccam[5]; buf[8+6] = 6 * buf[6]; buf[8+7] = 7 * buf[7]; } /* // XOR init bytes with 'CCcam' void cc_crypt_xor(uint8_t *buf) { const char cccam[] = "CCcam"; register unsigned int i; for ( i = 0; i < 8; i++ ) { buf[8 + i] = i * buf[i]; if ( i <= 5 ) { buf[i] ^= cccam[i]; } } } */ /////////////////////////////////////////////////////////////////////////////// __inline void cc_decrypt(struct cc_crypt_block *block, uint8_t *data, int len) { register int i; uint8_t z; for (i = 0; i < len; i++) { block->counter++; block->sum += block->keytable[block->counter]; cc_crypt_swap(&block->keytable[block->counter], &block->keytable[block->sum]); z = data[i]; data[i] = z ^ block->keytable[(block->keytable[block->counter] + block->keytable[block->sum]) & 0xff] ^ block->state; z = data[i]; block->state = block->state ^ z; } } /////////////////////////////////////////////////////////////////////////////// __inline void cc_encrypt(struct cc_crypt_block *block, uint8_t *data, int len) { register int i; uint8_t z; // There is a side-effect in this function: // If in & out pointer are the same, then state is xor'ed with modified input // (because output(=in ptr) is written before state xor) // This side-effect is used when initialising the encrypt state! for (i = 0; i < len; i++) { block->counter++; block->sum += block->keytable[block->counter]; cc_crypt_swap(&block->keytable[block->counter], &block->keytable[block->sum]); z = data[i]; data[i] = z ^ block->keytable[(block->keytable[block->counter] + block->keytable[block->sum]) & 0xff] ^ block->state; block->state = block->state ^ z; } } /////////////////////////////////////////////////////////////////////////////// // node_id : client nodeid, the sender of the ECM Request(big endian) // card_id : local card_id for the server void cc_crypt_cw(uint8_t *nodeid/*client node id*/, uint32_t card_id, uint8_t *cws) { uint8_t tmp; register int i; register int n; uint8_t nod[8]; for(i=0; i<8; i++) nod[i] = nodeid[7-i]; for (i = 0; i < 16; i++) { if (i&1) if (i!=15) n = (nod[i>>1]>>4) | (nod[(i>>1)+1]<<4); else n = nod[i>>1]>>4; else n = nod[i>>1]; n = n & 0xff; tmp = cws[i] ^ n; if (i & 1) tmp = ~tmp; cws[i] = (card_id >> (2 * i)) ^ tmp; //printf("(%d) n=%02x, tmp=%02x, cw=%02x\n",i,n,tmp,cws[i]); } } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Return: // =0: Disconnected // -1: Packet Error // >0: Success int cc_msg_recv(int handle,struct cc_crypt_block *recvblock, uint8_t *buf, int timeout) { int len; uint8_t netbuf[CC_MAXMSGSIZE]; if (handle < 0) return -1; len = recv_nonb(handle, netbuf, 4, timeout); if (len<=0) { debugf( getdbgflag(DBG_ERROR,0,0), " CCcam: recv error %d(%d)\n",len, errno); return len; } if (len != 4) { // invalid header length read debugf( getdbgflag(DBG_ERROR,0,0), " CCcam: invalid header length\n"); //debugdump(netbuf, len, "Header:"); return -1; } cc_decrypt(recvblock, netbuf, 4); //debugdump(netbuf, 4, "CCcam: decrypted header:"); if (((netbuf[2] << 8) | netbuf[3]) != 0) { // check if any data is expected in msg if (((netbuf[2] << 8) | netbuf[3]) > CC_MAXMSGSIZE - 2) { debugf( getdbgflag(DBG_ERROR,0,0), " CCcam: message too big\n"); return -1; } len = recv_nonb(handle, netbuf+4, (netbuf[2] << 8) | netbuf[3], timeout); if (len != ((netbuf[2] << 8) | netbuf[3])) { debugf( getdbgflag(DBG_ERROR,0,0), " CCcam: invalid message length read %d(%d)\n",len,errno); return -1; } cc_decrypt(recvblock, netbuf+4, len); len += 4; } //debugdump(netbuf, len, "CCcam: Reveive Data"); #ifdef DEBUG_NETWORK if (flag_debugnet) { debugf( getdbgflag(DBG_CCCAM,0,0), " CCcam: receive data %d\n",len); debughex(netbuf,len); } #endif memcpy(buf, netbuf, len); return len; } // -1: not yet // 0: disconnect // >0: ok int cc_msg_chkrecv(int handle,struct cc_crypt_block *recvblock) { int len; uint8_t netbuf[CC_MAXMSGSIZE]; struct cc_crypt_block block; if (handle<=0) return -1; //len = recv(handle, netbuf, 4, 0); len = recv(handle, netbuf, 4, MSG_PEEK|MSG_NOSIGNAL|MSG_DONTWAIT); if (len==0) return 0; if (len!=4) return -1; memcpy( &block, recvblock, sizeof(struct cc_crypt_block)); cc_decrypt(&block, netbuf, 4); int datasize = (netbuf[2] << 8) | netbuf[3]; if ( datasize!=0 ) { // check if any data is expected in msg if ( datasize > CC_MAXMSGSIZE - 2) return 0; // Disconnect len = recv(handle, netbuf, 4+datasize, MSG_PEEK|MSG_NOSIGNAL|MSG_DONTWAIT); if (len==0) return 0; if (len != 4+datasize) return -1; cc_decrypt(&block, netbuf+4, len-4); } //debugf( getdbgflag(DBG_CCCAM,0,0), "CCcam: Check Reveive Data %d\n",datasize+4); return len; } /////////////////////////////////////////////////////////////////////////////// // Return: // =0: Disconnected // -1: Packet Error // >0: Success int cc_msg_recv_nohead(int handle, struct cc_crypt_block *recvblock, uint8_t *buf, int len) { if (handle < 0) return -1; len = recv_nonb(handle, buf, len, 2000); // read rest of msg cc_decrypt(recvblock, buf, len); return len; } /////////////////////////////////////////////////////////////////////////////// int cc_msg_send(int handle,struct cc_crypt_block *sendblock, cc_msg_cmd cmd, int len, uint8_t *buf) { uint8_t netbuf[CC_MAXMSGSIZE]; memset(netbuf, 0, len+4); if (cmd == CC_MSG_NO_HEADER) memcpy(netbuf, buf, len); else { // build command message netbuf[0] = 0; // flags?? netbuf[1] = cmd & 0xff; netbuf[2] = len >> 8; netbuf[3] = len & 0xff; if (buf) memcpy(netbuf+4, buf, len); len += 4; } //debugdump(netbuf, len, "CCcam: Send data"); #ifdef DEBUG_NETWORK if (flag_debugnet) { debugf( getdbgflag(DBG_CCCAM,0,0), " CCcam: send data %d\n",len); debughex(netbuf,len); } #endif cc_encrypt(sendblock, netbuf, len); return send_nonb(handle, netbuf, len, 100); } // int nonblock_recv( int handle, uint8_t *buf, int len ) { int i; for (i=0; i<3; i++) { // only 3 times int got = recv(handle, buf, len, MSG_NOSIGNAL|MSG_DONTWAIT); if (len==0) return 0; if (len==-1) { if ( (errno==EINTR)||(errno==EWOULDBLOCK)||(errno==EAGAIN) ) { usleep(1); continue; } else return 0; } if (got>0) len -= got; if ( !len ) return 1; } return 0; } // -1: not yet // 0: disconnect/error // >0: ok int cc_peekmsg(int handle,struct cc_crypt_block *recvblock, struct message_data *msg, uint8_t *buf) { // header if ( !nonblock_recv(handle, buf, 4) ) return 0; cc_decrypt(recvblock, buf, 4); // data int datasize = 4 + ((buf[2] << 8) | buf[3]); if (datasize > 4) { // check if any data is expected in msg if (datasize >= CC_MAXMSGSIZE) return 0; if ( !nonblock_recv(handle, buf+4, datasize-4) ) return 0; cc_decrypt(recvblock, buf+4, datasize-4); } return datasize; } int cc_peekmsg0(int handle,struct cc_crypt_block *recvblock, struct message_data *msg, uint8_t *buf) { int len; if (handle<0) return 0; if (msg->len<4) { len = recv(handle, msg->data+msg->len, 4-msg->len, MSG_NOSIGNAL|MSG_DONTWAIT); if (len==0) return 0; if (len==-1) { if ( (errno==EINTR)||(errno==EWOULDBLOCK)||(errno==EAGAIN) ) return -1; else return 0; } if (len>0) msg->len += len; if (msg->len==4) cc_decrypt(recvblock, msg->data, 4); } if (msg->len<4) return -1; int datasize = 4 + ((msg->data[2] << 8) | msg->data[3]); if (datasize > 4) { // check if any data is expected in msg if (datasize >= CC_MAXMSGSIZE) return 0; len = recv(handle, msg->data+msg->len, datasize-msg->len, MSG_NOSIGNAL|MSG_DONTWAIT); if (len==0) return 0; if (len==-1) { if ( (errno==EINTR)||(errno==EWOULDBLOCK)||(errno==EAGAIN) ) return -1; else return 0; } if (len>0) msg->len += len; if (msg->len<datasize) return -1; cc_decrypt(recvblock, msg->data+4, datasize-4); } memcpy(buf, msg->data, datasize); msg->len = 0; return datasize; }