/// <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_PLATFORM_CHALLENGE_RESPONSE with encrypted Platform Challeng Response
        /// </summary>
        public void SendClientPlatformChallengeResponse(CLIENT_HARDWARE_ID clientHardwareID)
        {
            CLIENT_PLATFORM_CHALLENGE_RESPONSE response = new CLIENT_PLATFORM_CHALLENGE_RESPONSE();

            PLATFORM_CHALLENGE_RESPONSE_DATA challengeData = new PLATFORM_CHALLENGE_RESPONSE_DATA();

            challengeData.pbChallenge         = platformChallenge;
            challengeData.cbChallenge         = (ushort)platformChallenge.Length;
            challengeData.wClientType         = 0x0100;
            challengeData.wVersion            = 0x0100;
            challengeData.wLicenseDetailLevel = 0x0003;
            response.EncryptedPlatformChallengResponse.wBlobType = wBlobType_Values.BB_ENCRYPTED_DATA_BLOB;
            var challengeDataBytes = TypeMarshal.ToBytes <PLATFORM_CHALLENGE_RESPONSE_DATA>(challengeData);

            response.EncryptedPlatformChallengResponse.blobData = RC4(challengeDataBytes);
            response.EncryptedPlatformChallengResponse.wBlobLen = (ushort)response.EncryptedPlatformChallengResponse.blobData.Length;

            CLIENT_HARDWARE_ID hardwareID = new CLIENT_HARDWARE_ID();

            hardwareID = clientHardwareID;

            response.EncryptedHWID.wBlobType = wBlobType_Values.BB_ENCRYPTED_DATA_BLOB;
            var hardwareIDBytes = TypeMarshal.ToBytes <CLIENT_HARDWARE_ID>(hardwareID);

            response.EncryptedHWID.blobData = RC4(hardwareIDBytes);
            response.EncryptedHWID.wBlobLen = (ushort)response.EncryptedHWID.blobData.Length;

            // MACData (16 bytes): An array of 16 bytes containing an MD5 digest (MAC) generated over the Platform Challenge Response Data and decrypted Client Hardware Identification.
            var data = challengeDataBytes.Concat(hardwareIDBytes).ToArray();

            response.MACData = EncryptionAlgorithm.GenerateNonFIPSDataSignature(macSaltKey, data, 16 * 8); // n is 16 * 8 bits.

            TS_LICENSE_PDU pdu = ConstructLicensePDU(bMsgType_Values.PLATFORM_CHALLENGE_RESPONSE, new LicensingMessage {
                ClientPlatformChallengeResponse = response
            });

            rdpbcgrClient.SendBytes(pdu.ToBytes());
        }
        /// <summary>
        /// Verify if the MACData received from server is valid or not.
        /// </summary>
        /// <param name="receivedMAC">The MACData received from Server</param>
        /// <param name="decryptedData">The decrypted data from Server, which is protected by MACData</param>
        /// <returns>If the received MAC is valid or not</returns>
        public bool VerifyServerMAC(byte[] receivedMAC, byte[] decryptedData)
        {
            var calculatedMAC = EncryptionAlgorithm.GenerateNonFIPSDataSignature(macSaltKey, decryptedData, 16 * 8);

            return(Enumerable.SequenceEqual(receivedMAC, calculatedMAC));
        }