/// <summary>
        /// Requests an update for the keyboard state and session ID.
        /// </summary>
        private async Task <bool> RequestAppleTVKeyboardInfoUpdateAsync()
        {
            List <byte> contentBytes = new List <byte>();

            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmcc", "0"));
            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmbe", "PromptResendReq"));

            ByteArrayContent content = new ByteArrayContent(contentBytes.ToArray());

            DACPRequest request = new DACPRequest("/ctrl-int/1/controlpromptentry");

            request.HttpContent = content;

            try
            {
                await SubmitRequestAsync(request).ConfigureAwait(false);
            }
            catch { return(false); }
            return(true);
        }
        /// <summary>
        /// Requests an update for the virtual trackpad connection parameters.
        /// </summary>
        private async Task <bool> RequestAppleTVTrackpadInfoUpdateAsync()
        {
            List <byte> contentBytes = new List <byte>();

            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmcc", "0"));
            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmbe", "DRPortInfoRequest"));
            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmte", string.Format("{0},0x{1}", AppleTVEncryptionKey, PairingCode)));

            ByteArrayContent content = new ByteArrayContent(contentBytes.ToArray());

            DACPRequest request = new DACPRequest("/ctrl-int/1/controlpromptentry");

            request.HttpContent = content;

            try
            {
                await SubmitRequestAsync(request).ConfigureAwait(false);
            }
            catch { return(false); }
            return(true);
        }
        private async Task <bool> SendAppleTVKeyboardStringUpdateCommandAsync(string value, bool done)
        {
            string command = (done) ? "PromptDone" : "PromptUpdate";

            List <byte> contentBytes = new List <byte>();

            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmcc", _appleTVKeyboardSessionID));
            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmbe", command));
            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmte", value));

            ByteArrayContent content = new ByteArrayContent(contentBytes.ToArray());

            DACPRequest request = new DACPRequest("/ctrl-int/1/controlpromptentry");

            request.HttpContent = content;

            try
            {
                await SubmitRequestAsync(request).ConfigureAwait(false);
            }
            catch { return(false); }
            return(true);
        }
        public async Task <bool> SendAppleTVKeyboardSecureTextAsync(string value)
        {
            if (!_appleTVKeyboardSecureText || string.IsNullOrEmpty(_appleTVKeyboardSecureTextCertificate) || string.IsNullOrEmpty(_appleTVKeyboardSecureTextChallenge))
            {
                return(false);
            }

            byte[] encryptedBytes;

            try
            {
                // Read the certificate
                byte[] certificateBytes = BitUtility.FromHexString(_appleTVKeyboardSecureTextCertificate);
                var    certificate      = new X509Certificate(certificateBytes);

                // X509Certificate gives us the ASN.1 DER-encoded RSA public key
                var publicKeyEncoded = certificate.GetPublicKey();
                if (publicKeyEncoded[0] != 0x30 || publicKeyEncoded[1] != 0x81)
                {
                    throw new Exception();
                }
                // Byte at index 2 is the length of the entire sequence, we can ignore this
                if (publicKeyEncoded[3] != 0x02 || publicKeyEncoded[4] != 0x81)
                {
                    throw new Exception();
                }

                // Length of the public key
                int length   = publicKeyEncoded[5];
                int position = 6;

                // Skip any padding at the beginning
                while (publicKeyEncoded[position] == 0x00)
                {
                    length--;
                    position++;
                }

                // Get the public key
                byte[] publicKey = new byte[length];
                System.Buffer.BlockCopy(publicKeyEncoded, position, publicKey, 0, length);

                // Length/position of exponent
                position += length;
                if (publicKeyEncoded[position] != 0x02)
                {
                    throw new Exception();
                }
                position++;
                length = publicKeyEncoded[position];
                position++;

                // Get the exponent
                byte[] exponent = new byte[length];
                System.Buffer.BlockCopy(publicKeyEncoded, position, exponent, 0, length);

                // Get bytes to encrypt
                var bytesToEncode = new List <byte>();
                bytesToEncode.AddRange(BitUtility.FromHexString(_appleTVKeyboardSecureTextChallenge));
                bytesToEncode.AddRange(Encoding.UTF8.GetBytes(value));

                // Set up RSA parameters
                var rsaParameters = new RSAParameters();
                rsaParameters.Modulus  = publicKey;
                rsaParameters.Exponent = exponent;

                // Create RSA provider
                using (var rsa = new RSACryptoServiceProvider())
                {
                    rsa.ImportParameters(rsaParameters);

                    // Encrypt the source data
                    encryptedBytes = rsa.Encrypt(bytesToEncode.ToArray(), false);
                }
            }
            catch { return(false); }

            // Create DACP request
            List <byte> contentBytes = new List <byte>();

            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmcc", _appleTVKeyboardSessionID));
            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmbe", "PromptDone"));
            contentBytes.AddRange(DACPUtility.GetDACPFormattedBytes("cmae", BitUtility.ToHexString(encryptedBytes)));

            ByteArrayContent content = new ByteArrayContent(contentBytes.ToArray());

            DACPRequest request = new DACPRequest("/ctrl-int/1/controlpromptentry");

            request.HttpContent = content;

            try
            {
                await SubmitRequestAsync(request).ConfigureAwait(false);
            }
            catch { return(false); }
            return(true);
        }