⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 newcamd-client.cpp

📁 Example Dreambox CAM source code
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		return (net_msg_type_t)(-1);
}

int newcamd_client::receive_message(unsigned char *message, unsigned char *custom_data, key_encryption_t key_type)
{
	unsigned char message_buffer[CWS_NETMSGSIZE];
	unsigned short int message_length;
	int bytes_received;
	
	//message header length is 2-byte size header (unencrypted) + 2-byte sequence id (encrypted) + 
	//8 or 4-byte custom data field (encrypted).
	unsigned short int message_header_length = 2 + 2 + custom_data_length;
	
	//read first 2 bytes, this is the message length
	if( (bytes_received = network_read(message_buffer, 2)) != 2 )
	{
		switch( bytes_received )
		{
			case -1:
				status = 3;
				printf( "[Newcamd] Failed to read network stream. Server disconnected.\n");
				return 0;
			
			case -2:
				status = 4;
				printf( "[Newcamd] Failed to read network stream. Time-out.\n");
				return 0;
				
			default:
				status = 5;
				printf( "[Newcamd] Failed to read network stream.\n");
				return 0;
		}
	}
	
	//message length is big-endian
	message_length = message_buffer[0] << 8 | message_buffer[1];
	
	//check if message length is valid
	if( message_length > CWS_NETMSGSIZE - 2 )
	{
		status = 1;
		printf( "[Newcamd] Received message too large (%d bytes).\n", message_length + 2);
		return 0;
	}
	
	//read the rest of the message
	if( (bytes_received = network_read(message_buffer + 2, message_length)) != message_length )
	{
		switch( bytes_received )
		{
			case -1:
				status = 1;
				printf( "[Newcamd] Failed to read network stream. Server disconnected.\n");
				return 0;
			
			case -2:
				status = 2;
				printf( "[Newcamd] Failed to read network stream. Time-out.\n");
				return 0;
				
			default:
				status = 3;
				printf( "[Newcamd] Failed to read network stream.\n");
				return 0;
		}
	}
	message_length += 2;
	
	//decrypt the whole message, includes the 2-byte size header, using apropriate key_type	switch( key_type )
	switch( key_type )
	{
		case LOGIN_KEY:
			memcpy(des.des_key, expanded_login_key, sizeof(des.des_key));
			break;
			
		case SESSION_KEY:
			memcpy(des.des_key, expanded_session_key, sizeof(des.des_key));
			break;
	}
	des.decrypt(message_buffer, message_length);
	message_length -= sizeof(i_DES_cblock);
	
	//check sum the result
	if(des.xor_checksum(message_buffer + 2, message_length - 2))
	{
		status = 1;
		printf( "[Newcamd] Checksum error on decrypted packet.\n");
		return 0;
	}
	
	//get size from 12-bit command data length of message, add 3 bytes (from command header) to get 
	//total size of data to be returned
	unsigned short command_length = 
		((message_buffer[message_header_length + 1] & 0x0F) | message_buffer[message_header_length + 2]) + 3;
	
	//get the received sequence id (used for message synchronization)
	received_sequence_id = (message_buffer[2] << 8) | message_buffer[3];
	
	//if custom_data pointer is present, copy custom data from mesage to it
	if( custom_data ) memcpy(custom_data, message_buffer + 4, custom_data_length);
	
	memcpy(message, message_buffer + message_header_length, command_length);
	//debug_output(message_buffer, message_length, "< ");
	return command_length;
}

void newcamd_client::send_message(unsigned char *message, unsigned short int length, unsigned char *custom_data, key_encryption_t key_type)
{
	unsigned char message_buffer[CWS_NETMSGSIZE];
	memset(message_buffer, 0, CWS_NETMSGSIZE);
	
	//message header length is 2-byte size header (unencrypted) + 2-byte sequence id (encrypted) + 
	//8 or 4-byte custom data field (encrypted).
	unsigned short int message_header_length = 2 + 2 + custom_data_length;
	
	//total message length is the message header length + the length of the command data received.
	unsigned short int message_length = message_header_length + length;
	
	if( length < 3 || (message_header_length + length ) > CWS_NETMSGSIZE )
	{
		status = 1;
		printf( "[Newcamd] Invalid message size.\n");
		return;
	}
	
	//increment and big-endian set new session id to bytes 2 & 3 of message buffer
	message_buffer[2] = ((sent_sequence_id + 1) >> 8);
	message_buffer[3] = (sent_sequence_id + 1) & 0xFF;
	
	if(length > 3)
	{

		//copy received command data to message buffer (it includes the 3-byte header)
		memcpy(message_buffer + message_header_length, message, length);
		
		//correct the 12-bit size in the received command data in case it is not set properly.
		message_buffer[message_header_length + 1] = (message[1] & 0xF0) | (((length - 3) >> 8) & 0x0F);
		message_buffer[message_header_length + 2] = (length - 3) & 0xFF;

	}
	else
	{
		//this is a simple command (3-byte message), just copy it to the message buffer as-is.
		memcpy(message_buffer + message_header_length, message, length);
	}
	
	//if custom data is received, embed it in the custom data section of the message
	//depending on protocol version, custom data length can be either 4 bytes or 8 bytes.
	if( custom_data ) memcpy(message_buffer + 4, custom_data, custom_data_length);
	
	//debug_output(message_buffer, message_length, "> ");
	
	//pad message for encrypting
	message_length = des.pad_message(message_buffer, message_length);
	
	//3des encrypt full message with appropriate key
	switch( key_type )
	{
		case LOGIN_KEY:
			memcpy(des.des_key, expanded_login_key, sizeof(des.des_key));
			break;
			
		case SESSION_KEY:
			memcpy(des.des_key, expanded_session_key, sizeof(des.des_key));
			break;
	}
	des.schedule_key();
	des.encrypt(message_buffer, message_length, message_buffer);
	
	//compensate for message padding (add 1 DES block to message length)
	message_length += sizeof(i_DES_cblock);
	
  	//set total message length UNENCRYPTED in bytes 0 & 1 of message
  	message_buffer[0] = (message_length - 2) >> 8;
  	message_buffer[1] = (message_length - 2) & 0xFF;
  	
  	//write message to network socket
  	if( network_write(message_buffer, message_length) != message_length )
  	{
  		status = 1;
  		printf( "[Newcamd] Error writing network stream.\n");
  		return;
  	}
	sent_sequence_id++;
	
  	status = 0;
  	if (dbg) printf( "[Newcamd] Message sent successfully.\n");
}

void newcamd_client::create_login_key()
{
	//xors the received 14-byte random key with the 14-byte common key.
	//expands the resulting 14-byte login_key to a 16-byte expanded_login_key
	des.xor_buffers(login_key, random_key, des_key, sizeof(login_key));
	des.expand(login_key, expanded_login_key);
}

void newcamd_client::create_session_key( char *encrypted_password )
{
	//xors the common des key with the authenticaded user password to form the 14-byte session key
	//expands 14-byte sesion_key to a 16-byte expanded_session_key
	memcpy(session_key, des_key, sizeof(session_key));
	for(unsigned int i=0;i<strlen(encrypted_password);i++)
		session_key[i % sizeof(session_key)] ^= encrypted_password[i];
	des.expand(session_key, expanded_session_key);
}

int newcamd_client::connect_non_blocking(int fd, struct sockaddr_in *addr, unsigned int timeout_seconds)
{
    int return_value = 0;

    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
    return_value = connect(fd, (struct sockaddr *)addr, sizeof(struct sockaddr));
    
    if(return_value < 0 && errno != EINPROGRESS) return -errno;
    if(return_value == 0) return 0;

    fd_set rset;
    FD_ZERO(&rset);
    FD_SET(fd, &rset);
	
	struct timeval select_timeout = {timeout_seconds, 0};
    return_value = select(fd + 1, NULL, &rset, NULL, &select_timeout);
    if(return_value <= 0) if(return_value == 0) return -ETIMEDOUT; else return -errno;

    if(FD_ISSET(fd, &rset))
    {
        socklen_t return_value_length = sizeof(return_value);
        if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&return_value, &return_value_length) < 0) return -errno;
        if(return_value) return -return_value;
    }
    
    return return_value;
}

int newcamd_client::network_write(unsigned char *buffer, unsigned int length)
{
	//write with time-out
	struct pollfd pfd;
	int write_result;
	
	pfd.fd = fd;
	pfd.events = POLLOUT | POLLERR;
	pfd.revents = 0;
	
	if(poll(&pfd, 1, network_timeout) != 1) return -1;
	
	if(pfd.revents & POLLOUT)
	{
		if( (write_result = write(fd, buffer, length)) <= 0 ) ready = false;
		//debug_output(buffer, write_result, "e> ");
		return write_result;
	}
	else
		return -1;
}

int newcamd_client::network_read(unsigned char *buffer, unsigned int length, int override_timeout)
{
	//read with time-out
	struct pollfd pfd;
	int read_result;
	
	pfd.fd = fd;
	pfd.events = POLLIN | POLLERR;
	pfd.revents = 0;
	
	if( override_timeout < 0 ) override_timeout = network_timeout;
	
	if(poll(&pfd, 1, override_timeout) != 1) return -2;
	
	if(pfd.revents & POLLIN)
	{
		if( (read_result = read(fd, buffer, length)) <= 0 ) ready = false;
		//debug_output(buffer, read_result, "e< ");
		return read_result;
	}
	else
		return -1;
}

int newcamd_client::network_read_poll(int override_timeout)
{
	//read with time-out
	struct pollfd pfd;
	
	pfd.fd = fd;
	pfd.events = POLLIN | POLLPRI;
	pfd.revents = 0;
	
	if( override_timeout < 0 ) override_timeout = network_timeout;
	if(poll(&pfd, 1, override_timeout) != 1) return -2;
	
	return 1;
}


void newcamd_client::debug_output(unsigned char *buffer, unsigned int length, char *header)
{
	printf("%s ", header);
	for(unsigned int i=0;i<length;i++) printf("%02X ", buffer[i]);
	printf("\n");
}

// --------------------------------- triple des class member implementation --------------------------------
triple_des::triple_des( void )
{
	memset(des_key, 0, sizeof(des_key));
}

void triple_des::set_odd_parity(unsigned char *key)
{
	//fixes the paritiy of a 16-byte key during expansion, if necessary, to be odd.
	i_DES_set_odd_parity((i_DES_cblock *)&key[0]); // set odd parity on both keys
	i_DES_set_odd_parity((i_DES_cblock *)&key[8]); // 
}

void triple_des::schedule_key(void)
{
	//prepares the internal des_key to speed up the encryption/decryption process (sets ks1 & ks2).
	i_DES_key_sched((i_DES_cblock *)&des_key[0], &ks1);
	i_DES_key_sched((i_DES_cblock *)&des_key[8], &ks2);
}

void triple_des::expand(unsigned char *original_key, unsigned char *expanded_key)
{
	//expands a 14-byte key to a 16-byte key and fixes it's parity, if necessary, setting it to odd.
	expanded_key[0]  =   original_key[0] & 0xfe;
	expanded_key[1]  = ((original_key[0] << 7) | (original_key[1] >> 1)) & 0xfe;
	expanded_key[2]  = ((original_key[1] << 6) | (original_key[2] >> 2)) & 0xfe;
	expanded_key[3]  = ((original_key[2] << 5) | (original_key[3] >> 3)) & 0xfe;
	expanded_key[4]  = ((original_key[3] << 4) | (original_key[4] >> 4)) & 0xfe;
	expanded_key[5]  = ((original_key[4] << 3) | (original_key[5] >> 5)) & 0xfe;
	expanded_key[6]  = ((original_key[5] << 2) | (original_key[6] >> 6)) & 0xfe;
	expanded_key[7]  =   original_key[6] << 1;
	expanded_key[8]  =   original_key[7] & 0xfe;
	expanded_key[9]  = ((original_key[7] << 7)  | (original_key[8] >> 1)) & 0xfe;
	expanded_key[10] = ((original_key[8] << 6)  | (original_key[9] >> 2)) & 0xfe;
	expanded_key[11] = ((original_key[9] << 5)  | (original_key[10] >> 3)) & 0xfe;
	expanded_key[12] = ((original_key[10] << 4) | (original_key[11] >> 4)) & 0xfe;
	expanded_key[13] = ((original_key[11] << 3) | (original_key[12] >> 5)) & 0xfe;
	expanded_key[14] = ((original_key[12] << 2) | (original_key[13] >> 6)) & 0xfe;
	expanded_key[15] =   original_key[13] << 1;
	set_odd_parity(expanded_key);
}

int triple_des::pad_message(unsigned char *data, unsigned short int len)
{
	i_DES_cblock pad_bytes;
	unsigned char pad_bytes_count;
	
	pad_bytes_count = (8 - ((len - 1) % 8)) % 8;

	//message over-flow
	if( len + pad_bytes_count + 1 >= CWS_NETMSGSIZE - 8) return 0;

	i_DES_random_key((i_DES_cblock *)pad_bytes);
	memcpy(data + len, pad_bytes, pad_bytes_count);
	len += pad_bytes_count;
	data[len] = xor_checksum(data + 2, len - 2);
	
	return len + 1;
}

int triple_des::encrypt(const unsigned char *data, int len, unsigned char *crypt)
{
	//des encrypt
	i_DES_cblock input_vector;
	i_DES_random_key((i_DES_cblock *)input_vector);
	memcpy(crypt + len, input_vector, sizeof(input_vector));
	i_DES_ede2_cbc_encrypt(data + 2, crypt + 2, len - 2, &ks1, &ks2, (i_DES_cblock *)input_vector, i_DES_ENCRYPT);
	return 1;
}

int triple_des::decrypt(unsigned char *data, int len)
{
	//des decrypt
	if( (len-2) % 8 || (len - 2) < 16 ) return 0;

	i_DES_cblock input_vector;
	len -= sizeof(input_vector);
	memcpy(input_vector, data + len, sizeof(input_vector));
	i_DES_ede2_cbc_encrypt(data + 2, data + 2, len - 2, &ks1, &ks2, (i_DES_cblock *)input_vector, i_DES_DECRYPT);
	return 1;
}

unsigned char triple_des::xor_checksum(const unsigned char *buf, unsigned int length)
{
	//return a 1-byte checksum by xoring every byte in the specified buffer.
	unsigned char checksum = 0;
	while(length--) checksum ^= *buf++;
	return checksum;
}

void triple_des::xor_buffers(unsigned char *dest, unsigned char *src_1, unsigned char *src_2, unsigned int length)
{
	//xor two buffers together.
	while(length--) *dest++ = *src_1++ ^ *src_2++;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -