./ MultiCS.r82 / msg-camd35.c
#define CAMD_ECM_REQUEST     0
#define CAMD_ECM_REPLY       1
#define CAMD_KEEPALIVE       0x37
#define CAMD_CEX_IDREQUEST   0x3D
#define CAMD_CEX_IDREPLY     0x3E
#define CAMD_CEX_PUSH        0x3F

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void aes_set_keys( uint8_t *key, AES_KEY *dkey, AES_KEY *ekey)
{
	AES_set_decrypt_key( key, 128, dkey);
	AES_set_encrypt_key( key, 128, ekey);
}

void aes_decrypt(AES_KEY *dkey, uint8_t *buf, int n)
{
	int32_t i;
	for (i=0; i<n; i+=16) {
		AES_decrypt(buf+i, buf+i, dkey);
	}
}

void aes_encrypt(AES_KEY *ekey, uint8_t *buf, int n)
{
	int32_t i;
	for (i=0; i<n; i+=16) {
		AES_encrypt(buf+i, buf+i, ekey);
	}
}

void camd35_init_data( char *user, char *pass, AES_KEY *encryptkey, AES_KEY *decryptkey, uint32_t *ucrc)
{
	unsigned char md5tmp[MD5_DIGEST_LENGTH];
	*ucrc = crc32( 0L, MD5( (uint8_t*)user, strlen(user), md5tmp), MD5_DIGEST_LENGTH ); // user
	aes_set_keys( MD5( (uint8_t*)pass, strlen(pass), md5tmp) , decryptkey, encryptkey); // pass
}

///////////////////////////////////////////////////////////////////////////////

inline int camd35_padding( int len )
{
	if (len&0x0f) return ( (len&0xfff0)+0x10 ); else return len;
}

///////////////////////////////////////////////////////////////////////////////

// for connected udp sockets
void camd35_send( int handle, AES_KEY *encryptkey, uint32_t ucrc, unsigned char *buf, int len)
{
	uint8_t sbuf[1024];
	sbuf[0] = ucrc>>24;
	sbuf[1] = ucrc>>16;
	sbuf[2] = ucrc>>8;
	sbuf[3] = ucrc;
	memcpy( sbuf+4, buf, len );
	memset( sbuf+4+len, 0xFF, 15);
	//
	uint32_t datacrc = crc32(0L, buf+20, len-20);
	sbuf[8] = datacrc>>24;
	sbuf[9] = datacrc>>16;
	sbuf[10] = datacrc>>8;
	sbuf[11] = datacrc;
	int newlen = camd35_padding(len);
#ifdef DEBUG_NETWORK
	if (flag_debugnet) {
		debugf(0," camd35: Send data length %d\n", newlen+4);
		debughex(sbuf, newlen+4);
	}
#endif
	aes_encrypt( encryptkey, sbuf+4, newlen);
	// SEND
	send( handle, sbuf, newlen+4, 0);
}

void camd35_sendto( int handle, uint32_t ip, int port, AES_KEY *encryptkey, uint32_t ucrc, unsigned char *buf, int len)
{
	uint8_t sbuf[1024];
	sbuf[0] = ucrc>>24;
	sbuf[1] = ucrc>>16;
	sbuf[2] = ucrc>>8;
	sbuf[3] = ucrc;
	memcpy( sbuf+4, buf, len );
	memset( sbuf+4+len, 0xFF, 15);
	//
	uint32_t datacrc = crc32(0L, buf+20, len-20);
	sbuf[8] = datacrc>>24;
	sbuf[9] = datacrc>>16;
	sbuf[10] = datacrc>>8;
	sbuf[11] = datacrc;
	int newlen = camd35_padding(len);
#ifdef DEBUG_NETWORK
	if (flag_debugnet) {
		debugf(0," camd35: Send data to (%s:%d) length %d\n", ip2string(ip), port, newlen+4);
		debughex(sbuf, newlen+4);
	}
#endif
	aes_encrypt( encryptkey, sbuf+4, newlen);
	// SEND
	struct sockaddr_in si_other;
	int slen = sizeof(si_other);
	memset((char *) &si_other, 0, sizeof(si_other));
	si_other.sin_family = AF_INET;
	si_other.sin_port = htons( port );
	si_other.sin_addr.s_addr = ip;
	sendto( handle, sbuf, newlen+4, 0, (struct sockaddr *)&si_other, slen);
}

int cs378x_send( int handle, AES_KEY *encryptkey, uint32_t ucrc, unsigned char *buf, int len)
{
	uint8_t sbuf[1024];
	sbuf[0] = ucrc>>24;
	sbuf[1] = ucrc>>16;
	sbuf[2] = ucrc>>8;
	sbuf[3] = ucrc;
	memcpy( sbuf+4, buf, len );
	memset( sbuf+4+len, 0xFF, 15);
	//
	uint32_t datacrc = crc32(0L, buf+20, len-20);
	sbuf[8] = datacrc>>24;
	sbuf[9] = datacrc>>16;
	sbuf[10] = datacrc>>8;
	sbuf[11] = datacrc;
	int newlen = camd35_padding(len);
	//debugf(0, " cs378x: send data\n"); debughex(sbuf, newlen+4);
	aes_encrypt( encryptkey, sbuf+4, newlen);
	return send_nonb( handle, sbuf, newlen+4, 100 );
}

int cs378x_recv(int handle, uint32_t ucrc, AES_KEY *decryptkey, unsigned char *buf)
{
	int received = recv_nonb( handle, buf, 32+4, 1000); // Get minimum packet size
	if (received<=0) return received; // Disconnect
	uint32_t ucrc1 = (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3];
	if (ucrc!=ucrc1) return -2; // wrong ucrc
	aes_decrypt( decryptkey, buf+4, received-4);
	//Fix for ECM request size > 255 (use ecm length field)
	int datalen = buf[5];
	if (buf[4] == 0) datalen = (((buf[25] & 0x0f) << 8) | buf[26]) + 3; // ECM
	else if ( (buf[4]&0xFC)==0x3C ) datalen = buf[5] | (buf[6] << 8); // cacheex
	else datalen = buf[5]; // Normal
	int newlen = 4+camd35_padding(20+datalen);
	if (received<newlen) {
		int n = recv_nonb( handle, buf+received, newlen-received, 500);
		if ( n != (newlen-received) ) return -3; // receive timeout or wrong packet size
		aes_decrypt( decryptkey, buf+received, n);
	}
	//debugf(getdbgflag(DBG_SERVER,0,srv->id)," msg from cs378x server (%s:%d)\n", srv->host->name, srv->port); debughex(buf, newlen);
	return newlen;
}