/// <summary> /// Generate sub header Data of BW result /// </summary> /// <param name="sequenceNumber"></param> /// <returns></returns> public byte[] GenerateSubHander_BWResult() { RDP_BW_RESULTS bwresult = RdpbcgrUtility.GenerateBandwidthMeasureResults(AUTO_DETECT_RESPONSE_TYPE.RDP_BW_RESULTS_AFTER_CONNECT, bwStopSequenceNumber, timeDelta, bandwidthMeasurePayloadByteCount); byte[] subHeaderbytes = RdpbcgrClient.EncodeNetworkDetectionResponse(bwresult, true); return(subHeaderbytes); }
/// <summary> /// Send a Tunnel Data PDU with RDP_NETCHAR_RESULT in its subheader /// </summary> /// <param name="requestedProtocol"></param> /// <param name="sequenceNumber"></param> private void SendTunnelDataPdu_NetcharResult(Multitransport_Protocol_value requestedProtocol, ushort sequenceNumber) { autoDetectedBaseRTT = (uint)(rttDataStore.responseTime - rttDataStore.requestTime).Milliseconds; autoDetectedAverageRTT = (uint)(rttDataStore.responseTime - rttDataStore.requestTime).Milliseconds; if (bwDataStore.timeDelta != 0) { autoDetectedBandwidth = (bwDataStore.byteCount * 8) / bwDataStore.timeDelta; } RdpemtServer rdpemtServer = rdpemtServerR; if (requestedProtocol == Multitransport_Protocol_value.INITITATE_REQUEST_PROTOCOL_UDPFECL) { rdpemtServer = rdpemtServerL; } RDP_NETCHAR_RESULT netResult = RdpbcgrUtility.GenerateNetworkCharacteristicsResult(AUTO_DETECT_REQUEST_TYPE.RDP_NETCHAR_RESULT_BASERTT_BANDWIDTH_AVERAGERTT, sequenceNumber, autoDetectedBaseRTT, autoDetectedBandwidth, autoDetectedAverageRTT); byte[] reqData = rdpbcgrServer.EncodeNetworkDetectionRequest(netResult, true); List <byte[]> subHdDataList = new List <byte[]>(); subHdDataList.Add(reqData); RDP_TUNNEL_DATA tunnelData = rdpemtServer.CreateTunnelDataPdu(null, subHdDataList); rdpemtServer.SendRdpemtPacket(tunnelData); }
/// <summary> /// Validate data signature for received PDUs. /// </summary> /// <param name="dataSignature">The data signature to be validate. This argument can be null.</param> /// <param name="data">Data generates the signature. This argument can be null.</param> /// <param name="isSalted">Specify if data signature generated with salted MAC.</param> /// <returns>If the data signature is valid.</returns> internal bool ValidateDataSignature(byte[] dataSignature, byte[] data, bool isSalted) { byte[] signature = null; if (data != null) { if (encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_40BIT || encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_56BIT || encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_128BIT) { if (isSalted) { signature = GenerateSaltedDataSignature(macKey, data, decryptionCount); } else { signature = GenerateNonFIPSDataSignature(macKey, data); } } else if (encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS) { signature = GenerateFIPSDataSignature(macKey, data, decryptionCount); } // else do nothing } return(RdpbcgrUtility.AreEqual(signature, dataSignature)); }
/// <summary> /// Reverse all bits of every byte for all bytes of a buffer. /// </summary> /// <param name="buffer">The buffer to be reversed.</param> private static void ReverseEveryByte(byte[] buffer) { for (int i = 0; i < buffer.Length; ++i) { buffer[i] = RdpbcgrUtility.ReverseByte(buffer[i]); } }
/// <summary> /// Generate the FIPS MAC signature for the given data. /// </summary> /// <param name="macKey">MAC key used for generating MAC signature.</param> /// <param name="data">The given Data</param> /// <param name="count">The cumulative encryption count, indicating how many encryptions have been /// carried out.</param> /// <returns>The MAC signature.</returns> private static byte[] GenerateFIPSDataSignature(byte[] macKey, byte[] data, Int32 count) { // MACSignature = First64Bits(HMAC(HMACKey, Data + EncryptionCount)) byte[] temp = RdpbcgrUtility.ConcatenateArrays(data, BitConverter.GetBytes(count)); HMACSHA1 hmac = new HMACSHA1(macKey); return(GetFirstNBits(64, hmac.ComputeHash(temp))); }
private void SendClientSecurityExchangePDU() { // Create random data byte[] clientRandom = RdpbcgrUtility.GenerateRandom(RdpbcgrTestData.ClientRandomSize); Client_Security_Exchange_Pdu exchangePdu = rdpbcgrClient.CreateSecurityExchangePdu(clientRandom); rdpbcgrClient.SendPdu(exchangePdu); }
/// <summary> /// Generate the session key for Non-FIPS according to section 5.3.5 Initial Session Key Generation. /// </summary> /// <param name="clientRandom">The client random generated by client.</param> /// <param name="serverRandom">The server random received from server.</param> /// <param name="macKey">The computed MACKey.</param> /// <param name="clientEncKey">The computed client encrypt key.</param> /// <param name="clientDecKey">The computed client decrypt key.</param> private static void GenerateNonFIPSSessionKey(byte[] clientRandom, byte[] serverRandom, out byte[] macKey, out byte[] clientEncKey, out byte[] clientDecKey) { // PreMasterSecret = First192Bits(ClientRandom) + First192Bits(ServerRandom) byte[] preMasterSecret = RdpbcgrUtility.ConcatenateArrays(GetFirstNBits(192, clientRandom), GetFirstNBits(192, serverRandom)); // SaltedHash(S, I) = MD5(S + SHA(I + S + ClientRandom + ServerRandom)) // PreMasterHash(I) = SaltedHash(PremasterSecret, I) // MasterSecret = PreMasterHash('A') + PreMasterHash('BB') + PreMasterHash('CCC') byte[] Salt1 = SaltedHash(preMasterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_A), clientRandom, serverRandom); byte[] Salt2 = SaltedHash(preMasterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_BB), clientRandom, serverRandom); byte[] Salt3 = SaltedHash(preMasterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_CCC), clientRandom, serverRandom); byte[] masterSecret = RdpbcgrUtility.ConcatenateArrays(Salt1, Salt2, Salt3); // MasterHash(I) = SaltedHash(MasterSecret, I) // SessionKeyBlob = MasterHash('X') + MasterHash('YY') + MasterHash('ZZZ') byte[] Salt11 = SaltedHash(masterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_X), clientRandom, serverRandom); byte[] Salt21 = SaltedHash(masterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_YY), clientRandom, serverRandom); byte[] Salt31 = SaltedHash(masterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_ZZZ), clientRandom, serverRandom); byte[] sessionKey = RdpbcgrUtility.ConcatenateArrays(Salt11, Salt21, Salt31); // MACKey128 = First128Bits(SessionKeyBlob) macKey = GetFirstNBits(128, sessionKey); // FinalHash(K) = MD5(K + ClientRandom + ServerRandom) // InitialClientDecryptKey128 = FinalHash(Second128Bits(SessionKeyBlob)) byte[] tempKey = GetLastNBits(128, GetFirstNBits(128 * 2, sessionKey)); clientDecKey = FinalHash(tempKey, clientRandom, serverRandom); // FinalHash(K) = MD5(K + ClientRandom + ServerRandom) // InitialClientEncryptKey128 = FinalHash(Third128Bits(SessionKeyBlob)) tempKey = GetLastNBits(128, GetFirstNBits(128 * 3, sessionKey)); clientEncKey = FinalHash(tempKey, clientRandom, serverRandom); }
private TS_LICENSE_PDU ConstructLicensePDU(bMsgType_Values messageType, LicensingMessage message) { TS_LICENSE_PDU pdu = new TS_LICENSE_PDU(rdpbcgrClient.context); RdpbcgrUtility.FillCommonHeader(rdpbcgrClient.context, ref pdu.commonHeader, TS_SECURITY_HEADER_flags_Values.SEC_LICENSE_PKT); pdu.LicensingMessage = message; pdu.preamble.bMsgType = messageType; pdu.preamble.bVersion = bVersion_Values.PREAMBLE_VERSION_3_0 | bVersion_Values.EXTENDED_ERROR_MSG_SUPPORTED; return(pdu); }
/// <summary> /// Construct and send CLIENT_LICENSE_INFO /// Meanwhile, generate the two licensing keys: licensing encryption key and MAC salt key. /// </summary> public void SendClientLicenseInformation(KeyExchangeAlg preferredKeyExchangeAlg, uint platformId, byte[] licenseInfo, CLIENT_HARDWARE_ID clientHardwareID) { CLIENT_LICENSE_INFO info = new CLIENT_LICENSE_INFO(); info.PreferredKeyExchangeAlg = preferredKeyExchangeAlg; info.PlatformId = platformId; info.LicenseInfo.blobData = licenseInfo; info.LicenseInfo.wBlobLen = (ushort)licenseInfo.Length; info.LicenseInfo.wBlobType = wBlobType_Values.BB_DATA_BLOB; var random = new Random(); clientRandom = new byte[32]; random.NextBytes(clientRandom); info.ClientRandom = clientRandom; preMasterSecret = new byte[48]; random.NextBytes(preMasterSecret); EncryptionAlgorithm.GenerateLicensingKeys(preMasterSecret, clientRandom, serverRandom, out macSaltKey, out licensingEncryptionKey); if (macSaltKey == null) { throw new Exception("The generated MAC-salt-key should not be NULL!"); } if (licensingEncryptionKey == null) { throw new Exception("The generated LicensingEncryptionKey should not be NULL!"); } info.EncryptedPreMasterSecret.blobData = RdpbcgrUtility.GenerateEncryptedRandom(preMasterSecret, publicExponent, modulus); info.EncryptedPreMasterSecret.wBlobLen = (ushort)info.EncryptedPreMasterSecret.blobData.Length; info.EncryptedPreMasterSecret.wBlobType = wBlobType_Values.BB_RANDOM_BLOB; CLIENT_HARDWARE_ID hardwareID = new CLIENT_HARDWARE_ID(); hardwareID = clientHardwareID; info.EncryptedHWID.wBlobType = wBlobType_Values.BB_ENCRYPTED_DATA_BLOB; var hardwareIDBytes = TypeMarshal.ToBytes <CLIENT_HARDWARE_ID>(hardwareID); info.EncryptedHWID.blobData = RC4(hardwareIDBytes); info.EncryptedHWID.wBlobLen = (ushort)info.EncryptedHWID.blobData.Length; // MACData (16 bytes): An array of 16 bytes containing an MD5 digest (Message Authentication Code (MAC)) // that is generated over the unencrypted Client Hardware Identification structure. info.MACData = EncryptionAlgorithm.GenerateNonFIPSDataSignature(macSaltKey, hardwareIDBytes, 16 * 8); // n is 16 * 8 bits. TS_LICENSE_PDU pdu = ConstructLicensePDU(bMsgType_Values.LICENSE_INFO, new LicensingMessage { ClientLicenseInfo = info }); rdpbcgrClient.SendBytes(pdu.ToBytes()); }
/// <summary> /// Construct and send CLIENT_NEW_LICENSE_REQUEST /// Meanwhile, generate the two licensing keys: licensing encryption key and MAC salt key. /// </summary> public void SendClientNewLicenseRequest(KeyExchangeAlg preferredKeyExchangeAlg, uint platformId, string clientUserName, string clientMachineName) { CLIENT_NEW_LICENSE_REQUEST request = new CLIENT_NEW_LICENSE_REQUEST(); request.PreferredKeyExchangeAlg = preferredKeyExchangeAlg; request.PlatformId = platformId; var random = new Random(); clientRandom = new byte[32]; random.NextBytes(clientRandom); request.ClientRandom = clientRandom; preMasterSecret = new byte[48]; random.NextBytes(preMasterSecret); // Generate licensingEncryptionKey and macSaltKey EncryptionAlgorithm.GenerateLicensingKeys(preMasterSecret, clientRandom, serverRandom, out macSaltKey, out licensingEncryptionKey); if (macSaltKey == null) { throw new Exception("The generated MAC-salt-key should not be NULL!"); } if (licensingEncryptionKey == null) { throw new Exception("The generated LicensingEncryptionKey should not be NULL!"); } try { request.EncryptedPreMasterSecret.blobData = RdpbcgrUtility.GenerateEncryptedRandom(preMasterSecret, publicExponent, modulus); request.EncryptedPreMasterSecret.wBlobLen = (ushort)request.EncryptedPreMasterSecret.blobData.Length; request.EncryptedPreMasterSecret.wBlobType = wBlobType_Values.BB_RANDOM_BLOB; request.ClientUserName.wBlobType = wBlobType_Values.BB_CLIENT_USER_NAME_BLOB; request.ClientUserName.blobData = Encoding.UTF8.GetBytes(clientUserName); request.ClientUserName.wBlobLen = (ushort)request.ClientUserName.blobData.Length; request.ClientMachineName.wBlobType = wBlobType_Values.BB_CLIENT_MACHINE_NAME_BLOB; request.ClientMachineName.blobData = Encoding.UTF8.GetBytes(clientMachineName); request.ClientMachineName.wBlobLen = (ushort)request.ClientMachineName.blobData.Length; TS_LICENSE_PDU pdu = ConstructLicensePDU(bMsgType_Values.NEW_LICENSE_REQUEST, new LicensingMessage { ClientNewLicenseRequest = request }); var bytes = pdu.ToBytes(); rdpbcgrClient.SendBytes(bytes); } catch (Exception e) { throw e; } }
/// <summary> /// Update session key for Non-FIPS according to section 5.3.7 Session Key Updates. /// </summary> /// <param name="initialKey">The initial session key.</param> /// <param name="currentKey">The current session key.</param> /// <param name="encryptionMethod">The current encryption method.</param> /// <returns>The new session key.</returns> private static byte[] UpdateKey(byte[] initialKey, byte[] currentKey, EncryptionMethods encryptionMethod) { byte[] pad1 = ConstValue.NON_FIPS_PAD1; byte[] pad2 = ConstValue.NON_FIPS_PAD2; byte[] newKey = null; // SHAComponent = SHA(InitialEncryptKey + Pad1 + CurrentEncryptKey) byte[] shaComponentBuffer = RdpbcgrUtility.ConcatenateArrays(initialKey, pad1, currentKey); byte[] shaComponent = ShaHash(shaComponentBuffer); // TempKey128 = MD5(InitialEncryptKey + Pad2 + SHAComponent) byte[] tempKey128Buffer = RdpbcgrUtility.ConcatenateArrays(initialKey, pad2, shaComponent); byte[] tempKey128 = MD5Hash(tempKey128Buffer); if (encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_128BIT) { // S-TableEncrypt = InitRC4(TempKey128) RC4CryptoServiceProvider rc4 = new RC4CryptoServiceProvider(); ICryptoTransform ict = rc4.CreateEncryptor(tempKey128, null); // NewEncryptKey128 = RC4(TempKey128, S-TableEncrypt) newKey = ict.TransformFinalBlock(tempKey128, 0, tempKey128.Length); } else if (encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_40BIT || encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_56BIT) { // TempKey64 = First64Bits(TempKey128) byte[] tempKey64 = GetFirstNBits(64, tempKey128); // S-TableEncrypt = InitRC4(TempKey64) RC4CryptoServiceProvider rc4 = new RC4CryptoServiceProvider(); ICryptoTransform ict = rc4.CreateEncryptor(tempKey64, null); // PreSaltKey = RC4(TempKey64, S-TableEncrypt) byte[] preSaltKey = ict.TransformFinalBlock(tempKey64, 0, tempKey64.Length); if (encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_40BIT) { // NewEncryptKey40 = 0xD1269E + Last40Bits(PreSaltKey) newKey = RdpbcgrUtility.ConcatenateArrays(ConstValue.NON_FIPS_SALT_40BIT, GetLastNBits(40, preSaltKey)); } else { // NewEncryptKey56 = 0xD1 + Last56Bits(PreSaltKey) newKey = RdpbcgrUtility.ConcatenateArrays(ConstValue.NON_FIPS_SALT_56BIT, GetLastNBits(56, preSaltKey)); } } // else do nothing return(newKey); }
/// <summary> /// Generate the licensing encryption and MAC salt keys for RDPELE according to [MS-RDPELE] section 5.1.2 /// </summary> /// <param name="preMasterSecret">The client random generated by client.</param> /// <param name="clientRandom">The client random generated by client.</param> /// <param name="serverRandom">The server random received from server.</param> /// <param name="macKey">The computed MACKey.</param> /// <param name="licensingEncryptionKey">The computed licensing encrypt key.</param> public static void GenerateLicensingKeys(byte[] preMasterSecret, byte[] clientRandom, byte[] serverRandom, out byte[] macKey, out byte[] licensingEncryptionKey) { // [MS-RDPELE] 5.1.2 // SaltedHash(S, I) = MD5(S + SHA(I + S + ClientRandom + ServerRandom)) // PreMasterHash(I) = SaltedHash(PremasterSecret, I) // MasterSecret = PreMasterHash('A') + PreMasterHash('BB') + PreMasterHash('CCC') byte[] Salt1 = SaltedHash(preMasterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_A), clientRandom, serverRandom); byte[] Salt2 = SaltedHash(preMasterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_BB), clientRandom, serverRandom); byte[] Salt3 = SaltedHash(preMasterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_CCC), clientRandom, serverRandom); byte[] masterSecret = RdpbcgrUtility.ConcatenateArrays(Salt1, Salt2, Salt3); // SaltedHash2(S, I) = MD5(S + SHA-1 (I + S + ServerRandom + ClientRandom)) // MasterHash(I) = SaltedHash2(MasterSecret, I) // SessionKeyBlob = MasterHash('A') + MasterHash('BB') + MasterHash('CCC') // SaltedHash2 is SaltedHash with swapped serverRandaom and clientRandom. byte[] Salt11 = SaltedHash(masterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_A), serverRandom, clientRandom); byte[] Salt21 = SaltedHash(masterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_BB), serverRandom, clientRandom); byte[] Salt31 = SaltedHash(masterSecret, Encoding.ASCII.GetBytes(ConstValue.NON_FIPS_MASTER_SECRET_CCC), serverRandom, clientRandom); byte[] sessionKey = RdpbcgrUtility.ConcatenateArrays(Salt11, Salt21, Salt31); // MAC-salt-key = First128Bits(SessionKeyBlob) macKey = GetFirstNBits(128, sessionKey); // FinalHash(K) = MD5(K + ClientRandom + ServerRandom) // LicensingEncryptionKey = FinalHash(Second128Bits(SessionKeyBlob)) byte[] tempKey = GetLastNBits(128, GetFirstNBits(128 * 2, sessionKey)); licensingEncryptionKey = FinalHash(tempKey, clientRandom, serverRandom); }
/// <summary> /// Send static virtual channel data /// </summary> /// <param name="channelId">Channel ID</param> /// <param name="channelPduHeader">Channel PDU Header</param> /// <param name="SVCData"></param> public void SendPacket(UInt16 channelId, CHANNEL_PDU_HEADER channelPduHeader, byte[] SVCData) { Virtual_Channel_RAW_Pdu channelPdu = new Virtual_Channel_RAW_Pdu(context); RdpbcgrUtility.FillCommonHeader(ref channelPdu.commonHeader, TS_SECURITY_HEADER_flags_Values.SEC_IGNORE_SEQNO | TS_SECURITY_HEADER_flags_Values.SEC_RESET_SEQNO, context, channelId); channelPdu.virtualChannelData = SVCData; channelPdu.channelPduHeader = channelPduHeader; context.Client.SendPdu(channelPdu); }
public override byte[] ToBytes() { byte[] licensingMessageBytes = null; switch (preamble.bMsgType) { case bMsgType_Values.None: break; case bMsgType_Values.LICENSE_REQUEST: licensingMessageBytes = TypeMarshal.ToBytes <SERVER_LICENSE_REQUEST>(LicensingMessage.ServerLicenseRequest.Value); break; case bMsgType_Values.PLATFORM_CHALLENGE: licensingMessageBytes = TypeMarshal.ToBytes <SERVER_PLATFORM_CHALLENGE>(LicensingMessage.ServerPlatformChallenge.Value); break; case bMsgType_Values.NEW_LICENSE: licensingMessageBytes = TypeMarshal.ToBytes <SERVER_NEW_LICENSE>(LicensingMessage.ServerNewLicense.Value); break; case bMsgType_Values.UPGRADE_LICENSE: licensingMessageBytes = TypeMarshal.ToBytes <SERVER_UPGRADE_LICENSE>(LicensingMessage.ServerUgradeLicense.Value); break; case bMsgType_Values.LICENSE_INFO: licensingMessageBytes = TypeMarshal.ToBytes <CLIENT_LICENSE_INFO>(LicensingMessage.ClientLicenseInfo.Value); break; case bMsgType_Values.NEW_LICENSE_REQUEST: licensingMessageBytes = TypeMarshal.ToBytes <CLIENT_NEW_LICENSE_REQUEST>(LicensingMessage.ClientNewLicenseRequest.Value); break; case bMsgType_Values.PLATFORM_CHALLENGE_RESPONSE: licensingMessageBytes = TypeMarshal.ToBytes <CLIENT_PLATFORM_CHALLENGE_RESPONSE>(LicensingMessage.ClientPlatformChallengeResponse.Value); break; case bMsgType_Values.ERROR_ALERT: licensingMessageBytes = TypeMarshal.ToBytes <LICENSE_ERROR_MESSAGE>(LicensingMessage.LicenseError.Value); break; default: break; } preamble.wMsgSize = (ushort)(licensingMessageBytes.Length + TypeMarshal.GetBlockMemorySize <LICENSE_PREAMBLE>(preamble)); List <byte> totalBuffer = new List <byte>(); RdpbcgrEncoder.EncodeSlowPathPdu(totalBuffer, commonHeader, TypeMarshal.ToBytes <LICENSE_PREAMBLE>(preamble).Concat(licensingMessageBytes).ToArray(), context); return(RdpbcgrUtility.ToBytes(totalBuffer.ToArray())); }
/// <summary> /// Generate the Non-FIPS MAC signature for the given data. /// </summary> /// <param name="macKey">MAC key used for generating MAC signature.</param> /// <param name="data">The given Data</param> /// <returns>The MAC signature.</returns> private static byte[] GenerateNonFIPSDataSignature(byte[] macKey, byte[] data) { byte[] pad1 = ConstValue.NON_FIPS_PAD1; byte[] pad2 = ConstValue.NON_FIPS_PAD2; // SHAComponent = SHA(MACKeyN + Pad1 + DataLength + Data) byte[] temp = RdpbcgrUtility.ConcatenateArrays(macKey, pad1, BitConverter.GetBytes(data.Length), data); byte[] shaData = ShaHash(temp); // MACSignature = First64Bits(MD5(MACKeyN + Pad2 + SHAComponent)) byte[] md5Temp = RdpbcgrUtility.ConcatenateArrays(macKey, pad2, shaData); temp = MD5Hash(md5Temp); return(GetFirstNBits(64, temp)); }
/// <summary> /// Generate the session key for FIPS according to section 5.3.5 Initial Session Key Generation. /// </summary> /// <param name="clientRandom">The client random generated by client.</param> /// <param name="serverRandom">The server random received from server.</param> /// <param name="macKey">The computed MACKey.</param> /// <param name="clientEncKey">The computed client encrypt key.</param> /// <param name="clientDecKey">The computed client decrypt key.</param> private static void GenerateFIPSSessionKey(byte[] clientRandom, byte[] serverRandom, out byte[] macKey, out byte[] clientEncKey, out byte[] clientDecKey, out byte[] serverEncKey, out byte[] serverDecKey) { // ClientEncryptKeyT = SHA(Last128Bits(ClientRandom) + Last128Bits(ServerRandom)) byte[] clientKeyT = RdpbcgrUtility.ConcatenateArrays(GetLastNBits(128, clientRandom), GetLastNBits(128, serverRandom)); byte[] clientEncryptKeyT = ShaHash(clientKeyT); // ClientDecryptKeyT = SHA(First128Bits(ClientRandom) + First128Bits(ServerRandom)) clientKeyT = RdpbcgrUtility.ConcatenateArrays(GetFirstNBits(128, clientRandom), GetFirstNBits(128, serverRandom)); byte[] clientDecryptKeyT = ShaHash(clientKeyT); // ClientEncryptKey = ClientEncryptKeyT + First8Bits(ClientEncryptKeyT) clientEncKey = RdpbcgrUtility.ConcatenateArrays(clientEncryptKeyT, GetFirstNBits(8, clientEncryptKeyT)); serverDecKey = RdpbcgrUtility.ConcatenateArrays(clientEncryptKeyT, GetFirstNBits(8, clientEncryptKeyT)); // ClientDecryptKey = ClientDecryptKeyT + First8Bits(ClientDecryptKeyT) clientDecKey = RdpbcgrUtility.ConcatenateArrays(clientDecryptKeyT, GetFirstNBits(8, clientDecryptKeyT)); serverEncKey = RdpbcgrUtility.ConcatenateArrays(clientDecryptKeyT, GetFirstNBits(8, clientDecryptKeyT)); ReverseEveryByte(clientEncKey); InsertZeroBit(ref clientEncKey); ReverseEveryByte(clientEncKey); FillOddParity(clientEncKey); ReverseEveryByte(clientDecKey); InsertZeroBit(ref clientDecKey); ReverseEveryByte(clientDecKey); FillOddParity(clientDecKey); ReverseEveryByte(serverEncKey); InsertZeroBit(ref serverEncKey); ReverseEveryByte(serverEncKey); FillOddParity(serverEncKey); ReverseEveryByte(serverDecKey); InsertZeroBit(ref serverDecKey); ReverseEveryByte(serverDecKey); FillOddParity(serverDecKey); byte[] temp = RdpbcgrUtility.ConcatenateArrays(clientDecryptKeyT, clientEncryptKeyT); macKey = ShaHash(temp); }
/// <summary> /// Compute SaltedHash(S, I) = MD5(S + SHA(I + S + ClientRandom + ServerRandom)) /// </summary> /// <param name="parameterS">Argument S in the formula above.</param> /// <param name="parameterI">Argument I in the formula above.</param> /// <param name="clientRandom">Argument ClientRandom in the formula above.</param> /// <param name="serverRandom">Argument ServerRandom in the formula above.</param> /// <returns>The computed result.</returns> private static byte[] SaltedHash(byte[] parameterS, byte[] parameterI, byte[] clientRandom, byte[] serverRandom) { // I + S + ClientRandom + ServerRandom byte[] shaData = RdpbcgrUtility.ConcatenateArrays(parameterI, parameterS, clientRandom, serverRandom); //Computing the ShaHash of (I + S + ClientRandom + ServerRandom) byte[] shaHash = ShaHash(shaData); // S + SHA(I + S + ClientRandom + ServerRandom) byte[] md5Data = RdpbcgrUtility.ConcatenateArrays(parameterS, shaHash); // Computing the MD5Hash of (S + SHA(I + S + ClientRandom + ServerRandom)) return(MD5Hash(md5Data)); }
/// <summary> /// Send a Tunnel Data PDU with RDP_BW_STOP in its subheader /// </summary> /// <param name="requestedProtocol"></param> /// <param name="sequenceNumber"></param> private void SendTunnelDataPdu_BWStop(Multitransport_Protocol_value requestedProtocol, ushort sequenceNumber) { AUTO_DETECT_REQUEST_TYPE requestType = AUTO_DETECT_REQUEST_TYPE.RDP_BW_STOP_AFTER_CONNECTTIME_OR_RELIABLEUDP; RdpemtServer rdpemtServer = rdpemtServerR; if (requestedProtocol == Multitransport_Protocol_value.INITITATE_REQUEST_PROTOCOL_UDPFECL) { requestType = AUTO_DETECT_REQUEST_TYPE.RDP_BW_STOP_AFTER_CONNECTTIME_OR_LOSSYUDP; rdpemtServer = rdpemtServerL; } RDP_BW_STOP bwStop = RdpbcgrUtility.GenerateBandwidthMeasureStop(requestType, sequenceNumber); byte[] reqData = rdpbcgrServer.EncodeNetworkDetectionRequest(bwStop, true); List <byte[]> subHdDataList = new List <byte[]>(); subHdDataList.Add(reqData); RDP_TUNNEL_DATA tunnelData = rdpemtServer.CreateTunnelDataPdu(null, subHdDataList); rdpemtServer.SendRdpemtPacket(tunnelData); }
/// <summary> /// Send a Tunnel Data PDU with RTT Measure Request in its subheader /// </summary> /// <param name="udpTransportMode">Transport Mode: Reliable or Lossy</param> private void SendTunnelDataPdu_RTTMeasureRequest(Multitransport_Protocol_value requestedProtocol, ushort sequenceNumber) { AUTO_DETECT_REQUEST_TYPE requestType = AUTO_DETECT_REQUEST_TYPE.RDP_RTT_REQUEST_AFTER_CONNECTTIME; RdpemtServer rdpemtServer = rdpemtServerR; if (requestedProtocol == Multitransport_Protocol_value.INITITATE_REQUEST_PROTOCOL_UDPFECL) { rdpemtServer = rdpemtServerL; } RDP_RTT_REQUEST RTTRequest = RdpbcgrUtility.GenerateRTTMeasureRequest(requestType, sequenceNumber); byte[] reqData = rdpbcgrServer.EncodeNetworkDetectionRequest(RTTRequest, true); List <byte[]> subHdDataList = new List <byte[]>(); subHdDataList.Add(reqData); RDP_TUNNEL_DATA tunnelData = rdpemtServer.CreateTunnelDataPdu(null, subHdDataList); rttDataStore.requestTime = DateTime.Now; rdpemtServer.SendRdpemtPacket(tunnelData); }
private void CheckRDSTLSAuthenticationFields(RDSTLS_AuthenticationRequestPDUwithPasswordCredentials pdu) { // redirection GUID var redirectionGuid = RdpbcgrUtility.EncodeUnicodeStringToBytes(RdpbcgrTestData.Test_RedirectionGuid); bool checkRedirectionGuid = redirectionGuid.SequenceEqual(pdu.RedirectionGuid); this.TestSite.Assert.AreEqual <bool>(true, checkRedirectionGuid, "Redirection PDU should equal to that set in server redirection PDU."); // user name this.TestSite.Assert.AreEqual <string>(RdpbcgrTestData.Test_UserName, pdu.UserName, "User name should equal to that set in server redirection PDU."); // domain this.TestSite.Assert.AreEqual <string>(RdpbcgrTestData.Test_Domain, pdu.Domain, "Domain should equal to that set in server redirection PDU."); // password var password = RdpbcgrUtility.EncodeUnicodeStringToBytes(RdpbcgrTestData.Test_Password); bool checkPassword = password.SequenceEqual(pdu.Password); this.TestSite.Assert.AreEqual <bool>(true, checkPassword, "Password should equal to that set in server redirection PDU."); }
/// <summary> /// Encode a structure to a byte list. /// </summary> /// <param name="buffer">The buffer list to contain the structure. /// This argument cannot be null. It may throw ArgumentNullException if it is null.</param> /// <param name="structure">The structure to be added to buffer list. /// This argument cannot be null. It may throw ArgumentNullException if it is null.</param> internal static void EncodeStructure(List <byte> buffer, object structure) { byte[] structBuffer = RdpbcgrUtility.StructToBytes(structure); buffer.AddRange(structBuffer); }
/// <summary> /// Compute FinalHash(K) = MD5(K + ClientRandom + ServerRandom) /// </summary> /// <param name="parameterK">Argument K in the formula above.</param> /// <param name="clientRandom">Argument ClientRandom in the formula above.</param> /// <param name="serverRandom">Argument ServerRandom in the formula above.</param> /// <returns>The computed result.</returns> private static byte[] FinalHash(byte[] parameterK, byte[] clientRandom, byte[] serverRandom) { byte[] temp = RdpbcgrUtility.ConcatenateArrays(parameterK, clientRandom, serverRandom); return(MD5Hash(temp)); }
internal void GenerateSessionKey(byte[] clientRandom, byte[] serverRandom) { if (encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_40BIT || encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_56BIT || encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_128BIT) { byte[] mackey = null; byte[] clientEncKey = null; byte[] clientDecKey = null; GenerateNonFIPSSessionKey(clientRandom, serverRandom, out mackey, out clientEncKey, out clientDecKey); if (encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_40BIT) { // MACKey40 = 0xD1269E + Last40Bits(First64Bits(MACKey128)) byte[] salt = ConstValue.NON_FIPS_SALT_40BIT; byte[] first = GetFirstNBits(64, mackey); byte[] last = GetLastNBits(40, first); macKey = RdpbcgrUtility.ConcatenateArrays(salt, last); // InitialClientEncryptKey40 = 0xD1269E + Last40Bits(First64Bits(InitialClientEncryptKey128)) first = GetFirstNBits(64, clientEncKey); last = GetLastNBits(40, first); currentClientEncryptKey = RdpbcgrUtility.ConcatenateArrays(salt, last); currentServerDecryptKey = RdpbcgrUtility.ConcatenateArrays(salt, last); // InitialClientDecryptKey40 = 0xD1269E + Last40Bits(First64Bits(InitialClientDecryptKey128)) first = GetFirstNBits(64, clientDecKey); last = GetLastNBits(40, first); currentClientDecryptKey = RdpbcgrUtility.ConcatenateArrays(salt, last); currentServerEncryptKey = RdpbcgrUtility.ConcatenateArrays(salt, last); } else if (encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_56BIT) { // MACKey56 = 0xD1 + Last56Bits(First64Bits(MACKey128)) byte[] salt = ConstValue.NON_FIPS_SALT_56BIT; byte[] first = GetFirstNBits(64, mackey); byte[] last = GetLastNBits(56, first); macKey = RdpbcgrUtility.ConcatenateArrays(salt, last); // InitialClientEncryptKey56 = 0xD1 + Last56Bits(First64Bits(InitialClientEncryptKey128)) first = GetFirstNBits(64, clientEncKey); last = GetLastNBits(56, first); currentClientEncryptKey = RdpbcgrUtility.ConcatenateArrays(salt, last); currentServerDecryptKey = RdpbcgrUtility.ConcatenateArrays(salt, last); // InitialClientDecryptKey56 = 0xD1 + Last56Bits(First64Bits(InitialClientDecryptKey128)) first = GetFirstNBits(64, clientDecKey); last = GetLastNBits(56, first); currentClientDecryptKey = RdpbcgrUtility.ConcatenateArrays(salt, last); currentServerEncryptKey = RdpbcgrUtility.ConcatenateArrays(salt, last); } else // encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_128BIT { macKey = mackey; currentClientEncryptKey = clientEncKey; currentServerDecryptKey = clientEncKey; currentClientDecryptKey = clientDecKey; currentServerEncryptKey = clientDecKey; } initialClientDecryptKey = currentClientDecryptKey; initialClientEncryptKey = currentClientEncryptKey; initialServerEncryptKey = currentServerEncryptKey; initialServerDecryptKey = currentServerDecryptKey; RC4CryptoServiceProvider rc4Enc = new RC4CryptoServiceProvider(); rc4Encrypt = rc4Enc.CreateEncryptor(currentClientEncryptKey, null); rc4EncryptServer = rc4Enc.CreateEncryptor(currentServerEncryptKey, null); RC4CryptoServiceProvider rc4Dec = new RC4CryptoServiceProvider(); rc4Decrypt = rc4Dec.CreateDecryptor(currentClientDecryptKey, null); rc4DecryptServer = rc4Dec.CreateDecryptor(currentServerDecryptKey, null); } else if (encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS) { GenerateFIPSSessionKey(clientRandom, serverRandom, out macKey, out currentClientEncryptKey, out currentClientDecryptKey, out currentServerEncryptKey, out currentServerDecryptKey); initialClientDecryptKey = currentClientDecryptKey; initialClientEncryptKey = currentClientEncryptKey; initialServerDecryptKey = currentServerDecryptKey; initialServerEncryptKey = currentServerEncryptKey; // suppress "CA5353:TripleDESCannotBeUsed" message, since TripleDES is used according protocol definition in MS-RDPBCGR desEncrypt = new TripleDESCryptoServiceProvider(); desEncrypt.IV = ConstValue.TRPLE_DES_IV; desEncrypt.Key = currentClientEncryptKey; desEncrypt.Mode = CipherMode.CBC; desDecrypt = new TripleDESCryptoServiceProvider(); desDecrypt.IV = ConstValue.TRPLE_DES_IV; desDecrypt.Key = currentClientDecryptKey; desDecrypt.Mode = CipherMode.CBC; desEncryptServer = new TripleDESCryptoServiceProvider(); desEncryptServer.IV = ConstValue.TRPLE_DES_IV; desEncryptServer.Key = currentServerEncryptKey; desEncryptServer.Mode = CipherMode.CBC; desDecryptServer = new TripleDESCryptoServiceProvider(); desDecryptServer.IV = ConstValue.TRPLE_DES_IV; desDecryptServer.Key = currentServerDecryptKey; desDecryptServer.Mode = CipherMode.CBC; } else // the encryption method is ENCRYPTION_METHOD_NONE or error { macKey = null; initialClientEncryptKey = null; initialClientDecryptKey = null; currentClientEncryptKey = null; currentClientDecryptKey = null; initialServerEncryptKey = null; initialServerDecryptKey = null; currentServerEncryptKey = null; currentServerDecryptKey = null; rc4Encrypt = null; rc4Decrypt = null; rc4EncryptServer = null; rc4DecryptServer = null; desEncrypt = null; desDecrypt = null; desEncryptServer = null; desDecryptServer = null; } // the cumulative encryption/decryption count // indicating how many encryptions/decryptions have been carried out. encryptionCount = 0; // the first encryption start with 0 decryptionCount = -1; // after the first decryption, decryptionCount++ up to 0 }