📄 newcamd-client.cpp
字号:
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 + -