work on rdp encryption

This commit is contained in:
Jay Sorg 2011-09-12 23:40:27 -07:00
parent afc9ac89ae
commit 2ac4a5fa96
11 changed files with 274 additions and 18 deletions

View File

@ -53,7 +53,8 @@ endif()
# Compiler-specific flags
if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-unused-but-set-variable")
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-unused-but-set-variable")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -lncurses")
if(CMAKE_BUILD_TYPE STREQUAL "Release")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
endif()

View File

@ -198,6 +198,13 @@ struct rdp_settings
rdpBlob server_certificate;
struct rdp_certificate* server_cert;
uint8 sign_key[16];
uint8 decrypt_key[16];
uint8 encrypt_key[16];
uint8 decrypt_update_key[16];
uint8 encrypt_update_key[16];
int rc4_key_len;
boolean console_audio;
boolean console_session;
uint32 redirected_session_id;

View File

@ -19,6 +19,7 @@
#include "connection.h"
#include "info.h"
#include "per.h"
/**
* Connection Sequence
@ -107,10 +108,12 @@ boolean rdp_client_connect(rdpRdp* rdp)
static boolean rdp_establish_keys(rdpRdp* rdp)
{
uint8 client_random[32];
uint8 crypt_client_random[256];
uint8 crypt_client_random[256 + 8];
uint32 key_len;
uint8* mod;
uint8* exp;
uint32 length;
STREAM* s;
printf("rdp_establish_keys:\n");
if (rdp->settings->encryption == False)
@ -119,12 +122,51 @@ static boolean rdp_establish_keys(rdpRdp* rdp)
return True;
}
memset(client_random, 0x5e, 32); /* TODO: get real random */
crypto_nonce(client_random, 32);
/* encrypt client random */
memset(crypt_client_random, 0, sizeof(crypt_client_random));
memset(client_random, 0x5e, 32);
//crypto_nonce(client_random, 32);
printf("client random\n");
freerdp_hexdump(client_random, 32);
key_len = rdp->settings->server_cert->cert_info.modulus.length;
printf("key_len %d %d %d\n", key_len, rdp->mcs->user_id, MCS_BASE_CHANNEL_ID);
mod = rdp->settings->server_cert->cert_info.modulus.data;
exp = rdp->settings->server_cert->cert_info.exponent;
crypto_rsa_encrypt(client_random, 32, key_len, mod, exp, crypt_client_random);
printf("client crypt random\n");
freerdp_hexdump(crypt_client_random, key_len);
/* send crypt client random to server */
length = 7 + 8 + 4 + 4 + key_len + 8;
s = transport_send_stream_init(rdp->mcs->transport, length);
tpkt_write_header(s, length);
tpdu_write_header(s, 2, 0xf0);
per_write_choice(s, DomainMCSPDU_SendDataRequest << 2);
per_write_integer16(s, rdp->mcs->user_id, MCS_BASE_CHANNEL_ID);
per_write_integer16(s, MCS_GLOBAL_CHANNEL_ID, 0);
stream_write_uint8(s, 0x70);
length = (4 + 4 + key_len + 8) | 0x8000;
stream_write_uint16_be(s, length);
stream_write_uint32(s, 1); /* SEC_CLIENT_RANDOM */
length = key_len + 8;
stream_write_uint32(s, length);
memcpy(s->p, crypt_client_random, length);
stream_seek(s, length);
if (transport_write(rdp->mcs->transport, s) < 0)
{
return False;
}
/* now calculate encrypt / decrypt and upate keys */
if (!security_establish_keys(client_random, rdp->settings))
{
return False;
}
rdp->rc4_decrypt_key = crypto_rc4_init(rdp->settings->decrypt_key, rdp->settings->rc4_key_len);
rdp->rc4_encrypt_key = crypto_rc4_init(rdp->settings->encrypt_key, rdp->settings->rc4_key_len);
rdp->do_crypt = True;
return True;
}

View File

@ -57,6 +57,7 @@ uint16 fastpath_read_header(rdpFastPath* fastpath, STREAM* s)
if (fastpath != NULL)
{
fastpath->encryptionFlags = (header & 0xC0) >> 6;
printf("fastpath_read_header: fastpath->encryptionFlags %d\n", fastpath->encryptionFlags);
fastpath->numberEvents = (header & 0x3C) >> 2;
}

View File

@ -584,11 +584,10 @@ boolean rdp_send_client_info(rdpRdp* rdp)
{
STREAM* s;
//rdp->settings->crypt_flags |= SEC_INFO_PKT;
rdp->sec_flags |= SEC_INFO_PKT;
s = rdp_send_stream_init(rdp);
rdp_write_security_header(s, SEC_INFO_PKT);
rdp_write_info_packet(s, rdp->settings);
return rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID);
}

View File

@ -179,7 +179,7 @@ boolean license_recv(rdpLicense* license, STREAM* s)
rdp_read_security_header(s, &sec_flags);
if (!(sec_flags & SEC_LICENSE_PKT))
{
printf("Unexpected license packet.\n");
printf("Unexpected license packet. got 0x%4.4x need bit 0x%4.4x set\n", sec_flags, SEC_LICENSE_PKT);
return False;
}

View File

@ -146,6 +146,21 @@ void rdp_write_share_data_header(STREAM* s, uint16 length, uint8 type, uint32 sh
stream_write_uint16(s, 0); /* compressedLength (2 bytes) */
}
static int rdp_security_stream_init(rdpRdp* rdp, STREAM* s)
{
printf("rdp_security_stream_init:\n");
if (rdp->do_crypt)
{
stream_seek(s, 12);
rdp->sec_flags |= SEC_ENCRYPT;
}
else if (rdp->sec_flags != 0)
{
stream_seek(s, 4);
}
return 0;
}
/**
* Initialize an RDP packet stream.\n
* @param rdp rdp module
@ -155,8 +170,10 @@ void rdp_write_share_data_header(STREAM* s, uint16 length, uint8 type, uint32 sh
STREAM* rdp_send_stream_init(rdpRdp* rdp)
{
STREAM* s;
s = transport_send_stream_init(rdp->transport, 2048);
stream_seek(s, RDP_PACKET_HEADER_LENGTH);
rdp_security_stream_init(rdp, s);
return s;
}
@ -165,6 +182,7 @@ STREAM* rdp_pdu_init(rdpRdp* rdp)
STREAM* s;
s = transport_send_stream_init(rdp->transport, 2048);
stream_seek(s, RDP_PACKET_HEADER_LENGTH);
rdp_security_stream_init(rdp, s);
stream_seek(s, RDP_SHARE_CONTROL_HEADER_LENGTH);
return s;
}
@ -174,6 +192,7 @@ STREAM* rdp_data_pdu_init(rdpRdp* rdp)
STREAM* s;
s = transport_send_stream_init(rdp->transport, 2048);
stream_seek(s, RDP_PACKET_HEADER_LENGTH);
rdp_security_stream_init(rdp, s);
stream_seek(s, RDP_SHARE_CONTROL_HEADER_LENGTH);
stream_seek(s, RDP_SHARE_DATA_HEADER_LENGTH);
return s;
@ -229,6 +248,46 @@ void rdp_write_header(rdpRdp* rdp, STREAM* s, uint16 length, uint16 channel_id)
stream_write_uint16_be(s, length); /* userData (OCTET_STRING) */
}
static uint32 rdp_security_stream_out(rdpRdp* rdp, STREAM* s, int length)
{
uint32 sec_flags;
uint32 ml;
uint8* mk;
uint8* data;
printf("rdp_security_stream_out:\n");
sec_flags = rdp->sec_flags;
if (sec_flags != 0)
{
rdp_write_security_header(s, sec_flags);
if (sec_flags & SEC_ENCRYPT)
{
data = s->p + 8;
length = length - (data - s->data);
mk = rdp->settings->sign_key;
ml = rdp->settings->rc4_key_len;
security_mac_signature(mk, ml, data, length, s->p);
stream_seek(s, 8);
security_encrypt(s->p, length, rdp);
}
rdp->sec_flags = 0;
}
return 0;
}
static uint32 rdp_get_sec_bytes(uint32 sec_flags)
{
uint32 sec_bytes;
if (sec_flags & SEC_ENCRYPT)
sec_bytes = 12;
else if (sec_flags != 0)
sec_bytes = 4;
else
sec_bytes = 0;
return sec_bytes;
}
/**
* Send an RDP packet.\n
* @param rdp RDP module
@ -239,12 +298,22 @@ void rdp_write_header(rdpRdp* rdp, STREAM* s, uint16 length, uint16 channel_id)
boolean rdp_send(rdpRdp* rdp, STREAM* s, uint16 channel_id)
{
uint16 length;
uint32 sec_bytes;
uint8* sec_hold;
printf("rdp_send:\n");
length = stream_get_length(s);
stream_set_pos(s, 0);
rdp_write_header(rdp, s, length, channel_id);
sec_bytes = rdp_get_sec_bytes(rdp->sec_flags);
sec_hold = s->p;
stream_seek(s, sec_bytes);
s->p = sec_hold;
rdp_security_stream_out(rdp, s, length);
stream_set_pos(s, length);
if (transport_write(rdp->transport, s) < 0)
return False;
@ -255,13 +324,24 @@ boolean rdp_send(rdpRdp* rdp, STREAM* s, uint16 channel_id)
boolean rdp_send_pdu(rdpRdp* rdp, STREAM* s, uint16 type, uint16 channel_id)
{
uint16 length;
uint32 sec_bytes;
uint8* sec_hold;
printf("rdp_send_pdu:\n");
length = stream_get_length(s);
stream_set_pos(s, 0);
rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
sec_bytes = rdp_get_sec_bytes(rdp->sec_flags);
sec_hold = s->p;
stream_seek(s, sec_bytes);
rdp_write_share_control_header(s, length, type, channel_id);
s->p = sec_hold;
rdp_security_stream_out(rdp, s, length);
stream_set_pos(s, length);
if (transport_write(rdp->transport, s) < 0)
return False;
@ -272,16 +352,27 @@ boolean rdp_send_pdu(rdpRdp* rdp, STREAM* s, uint16 type, uint16 channel_id)
boolean rdp_send_data_pdu(rdpRdp* rdp, STREAM* s, uint8 type, uint16 channel_id)
{
uint16 length;
uint32 sec_bytes;
uint8* sec_hold;
printf("rdp_send_data_pdu:\n");
length = stream_get_length(s);
stream_set_pos(s, 0);
rdp_write_header(rdp, s, length, MCS_GLOBAL_CHANNEL_ID);
sec_bytes = rdp_get_sec_bytes(rdp->sec_flags);
sec_hold = s->p;
stream_seek(s, sec_bytes);
rdp_write_share_control_header(s, length, PDU_TYPE_DATA, channel_id);
rdp_write_share_data_header(s, length, type, rdp->settings->share_id);
//printf("send %s Data PDU (0x%02X), length:%d\n", DATA_PDU_TYPE_STRINGS[type], type, length);
s->p = sec_hold;
rdp_security_stream_out(rdp, s, length);
stream_set_pos(s, length);
if (transport_write(rdp->transport, s) < 0)
return False;

View File

@ -123,6 +123,12 @@ struct rdp_rdp
struct rdp_settings* settings;
struct rdp_transport* transport;
struct rdp_vchan* vchan;
struct crypto_rc4_struct* rc4_decrypt_key;
int decrypt_use_count;
struct crypto_rc4_struct* rc4_encrypt_key;
int encrypt_use_count;
uint32 sec_flags;
boolean do_crypt;
};
void rdp_read_security_header(STREAM* s, uint16* flags);

View File

@ -85,10 +85,10 @@ static void security_master_hash(char* input, int length, uint8* master_secret,
void security_session_key_blob(uint8* master_secret, uint8* client_random, uint8* server_random, uint8* output)
{
/* MasterHash = MasterHash('A') + MasterHash('BB') + MasterHash('CCC') */
security_master_hash("A", 1, master_secret, client_random, server_random, &output[0]);
security_master_hash("BB", 2, master_secret, client_random, server_random, &output[16]);
security_master_hash("CCC", 3, master_secret, client_random, server_random, &output[32]);
/* MasterHash = MasterHash('X') + MasterHash('YY') + MasterHash('ZZZ') */
security_master_hash("X", 1, master_secret, client_random, server_random, &output[0]);
security_master_hash("YY", 2, master_secret, client_random, server_random, &output[16]);
security_master_hash("ZZZ", 3, master_secret, client_random, server_random, &output[32]);
}
void security_mac_salt_key(uint8* session_key_blob, uint8* client_random, uint8* server_random, uint8* output)
@ -97,19 +97,23 @@ void security_mac_salt_key(uint8* session_key_blob, uint8* client_random, uint8*
memcpy(output, session_key_blob, 16);
}
void security_licensing_encryption_key(uint8* session_key_blob, uint8* client_random, uint8* server_random, uint8* output)
void security_md5_16_32_32(uint8* in0, uint8* in1, uint8* in2, uint8* output)
{
CryptoMd5 md5;
/* LicensingEncryptionKey = MD5(Second128Bits(SessionKeyBlob) + ClientRandom + ServerRandom)) */
md5 = crypto_md5_init();
crypto_md5_update(md5, &session_key_blob[16], 16); /* Second128Bits(SessionKeyBlob) */
crypto_md5_update(md5, client_random, 32); /* ClientRandom */
crypto_md5_update(md5, server_random, 32); /* ServerRandom */
crypto_md5_update(md5, in0, 16);
crypto_md5_update(md5, in1, 32);
crypto_md5_update(md5, in2, 32);
crypto_md5_final(md5, output);
}
void security_licensing_encryption_key(uint8* session_key_blob, uint8* client_random, uint8* server_random, uint8* output)
{
/* LicensingEncryptionKey = MD5(Second128Bits(SessionKeyBlob) + ClientRandom + ServerRandom)) */
security_md5_16_32_32(&session_key_blob[16], client_random, server_random, output);
}
void security_uint32_le(uint8* output, uint32 value)
{
output[0] = (value) & 0xFF;
@ -172,3 +176,102 @@ void security_mac_signature(uint8* mac_key, int mac_key_length, uint8* data, uin
memcpy(output, md5_digest, 8);
}
boolean security_establish_keys(uint8* client_random, rdpSettings* settings)
{
uint8 pre_master_secret[48];
uint8 master_secret[48];
uint8 session_key_blob[48];
uint8* server_random;
uint8 salt40[] = { 0xD1, 0x26, 0x9E };
printf("security_establish_keys:\n");
server_random = settings->server_random.data;
memcpy(pre_master_secret, client_random, 24);
memcpy(pre_master_secret + 24, server_random, 24);
security_master_secret(pre_master_secret, client_random, server_random, master_secret);
security_session_key_blob(master_secret, client_random, server_random, session_key_blob);
memcpy(settings->sign_key, session_key_blob, 16);
security_md5_16_32_32(&session_key_blob[16], client_random, server_random, settings->decrypt_key);
security_md5_16_32_32(&session_key_blob[32], client_random, server_random, settings->encrypt_key);
if (settings->encryption_method == 1) /* 40 and 56 bit */
{
memcpy(settings->sign_key, salt40, 3); /* TODO 56 bit */
memcpy(settings->decrypt_key, salt40, 3); /* TODO 56 bit */
memcpy(settings->encrypt_key, salt40, 3); /* TODO 56 bit */
settings->rc4_key_len = 8;
}
else /* 128 bit */
{
settings->rc4_key_len = 16;
}
memcpy(settings->decrypt_update_key, settings->decrypt_key, 16);
memcpy(settings->encrypt_update_key, settings->encrypt_key, 16);
return True;
}
boolean security_key_update(uint8* key, uint8* update_key, int key_len)
{
uint8 sha1h[20];
CryptoMd5 md5;
CryptoSha1 sha1;
CryptoRc4 rc4;
uint8 salt40[] = { 0xD1, 0x26, 0x9E };
sha1 = crypto_sha1_init();
crypto_sha1_update(sha1, update_key, key_len);
crypto_sha1_update(sha1, pad1, sizeof(pad1));
crypto_sha1_update(sha1, key, key_len);
crypto_sha1_final(sha1, sha1h);
md5 = crypto_md5_init();
crypto_md5_update(md5, update_key, key_len);
crypto_md5_update(md5, pad2, sizeof(pad2));
crypto_md5_update(md5, sha1h, 20);
crypto_md5_final(md5, key);
rc4 = crypto_rc4_init(key, key_len);
crypto_rc4(rc4, key_len, key, key);
crypto_rc4_free(rc4);
if (key_len == 8)
memcpy(key, salt40, 3); /* TODO 56 bit */
return True;
}
boolean security_encrypt(uint8* data, int length, rdpRdp* rdp)
{
if (rdp->encrypt_use_count >= 4096)
{
security_key_update(rdp->settings->encrypt_key, rdp->settings->encrypt_update_key, rdp->settings->rc4_key_len);
crypto_rc4_free(rdp->rc4_encrypt_key);
rdp->rc4_encrypt_key = crypto_rc4_init(rdp->settings->encrypt_key, rdp->settings->rc4_key_len);
rdp->encrypt_use_count = 0;
}
crypto_rc4(rdp->rc4_encrypt_key, length, data, data);
rdp->encrypt_use_count += 1;
return True;
}
boolean security_decrypt(uint8* data, int length, rdpRdp* rdp)
{
if (rdp->decrypt_use_count >= 4096)
{
security_key_update(rdp->settings->decrypt_key, rdp->settings->decrypt_update_key, rdp->settings->rc4_key_len);
crypto_rc4_free(rdp->rc4_decrypt_key);
rdp->rc4_decrypt_key = crypto_rc4_init(rdp->settings->decrypt_key, rdp->settings->rc4_key_len);
rdp->decrypt_use_count = 0;
}
crypto_rc4(rdp->rc4_decrypt_key, length, data, data);
rdp->decrypt_use_count += 1;
return True;
}

View File

@ -33,5 +33,9 @@ void security_licensing_encryption_key(uint8* session_key_blob, uint8* client_ra
void security_mac_data(uint8* mac_salt_key, uint8* data, uint32 length, uint8* output);
void security_mac_signature(uint8* mac_key, int mac_key_length, uint8* data, uint32 length, uint8* output);
boolean security_establish_keys(uint8* client_random, rdpSettings* settings);
boolean security_encrypt(uint8* data, int length, rdpRdp* rdp);
boolean security_decrypt(uint8* data, int length, rdpRdp* rdp);
#endif /* __SECURITY_H */

View File

@ -226,6 +226,8 @@ int transport_write(rdpTransport* transport, STREAM* s)
length = stream_get_length(s);
stream_set_pos(s, 0);
printf("transport_write:\n");
#ifdef WITH_DEBUG_TRANSPORT
if (length > 0)
{