예제 #1
0
        // This is the only method about exchange data between this software and AirVPN infrastructure.
        // We don't use SSL. Useless layer in our case, and we need to fetch hostname and direct IP that don't permit common-name match.

        // 'S' is the AES 256 bit one-time session key, crypted with a RSA 4096 public-key.
        // 'D' is the data from the client to our server, crypted with the AES.
        // The server answer is XML decrypted with the same AES session.
        public static XmlDocument FetchUrl(string authPublicKey, string url, Dictionary <string, string> parameters)
        {
            // AES
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.KeySize = 256;
                rijAlg.GenerateKey();
                rijAlg.GenerateIV();

                // Generate S

                // Bug workaround: Xamarin 6.1.2 macOS throw an 'Default constructor not found for type System.Diagnostics.FilterElement' error.
                // in 'new System.Xml.Serialization.XmlSerializer', so i avoid that.

                /*
                 * StringReader sr = new System.IO.StringReader(authPublicKey);
                 * System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
                 * RSAParameters publicKey = (RSAParameters)xs.Deserialize(sr);
                 */
                RSAParameters publicKey        = new RSAParameters();
                XmlDocument   docAuthPublicKey = new XmlDocument();
                docAuthPublicKey.LoadXml(authPublicKey);
                publicKey.Modulus  = Convert.FromBase64String(docAuthPublicKey.DocumentElement["Modulus"].InnerText);
                publicKey.Exponent = Convert.FromBase64String(docAuthPublicKey.DocumentElement["Exponent"].InnerText);

                Dictionary <string, byte[]> assocParamS = new Dictionary <string, byte[]>();
                assocParamS["key"] = rijAlg.Key;
                assocParamS["iv"]  = rijAlg.IV;

                byte[] bytesParamS = null;
                using (RSACryptoServiceProvider csp = new RSACryptoServiceProvider())
                {
                    csp.ImportParameters(publicKey);
                    bytesParamS = csp.Encrypt(UtilsCore.AssocToUtf8Bytes(assocParamS), false);
                }

                // Generate D

                byte[] aesDataIn   = UtilsCore.AssocToUtf8Bytes(parameters);
                byte[] bytesParamD = null;

                {
                    MemoryStream aesCryptStream  = null;
                    CryptoStream aesCryptStream2 = null;

                    try
                    {
                        aesCryptStream = new MemoryStream();
                        using (ICryptoTransform aesEncryptor = rijAlg.CreateEncryptor())
                        {
                            aesCryptStream2 = new CryptoStream(aesCryptStream, aesEncryptor, CryptoStreamMode.Write);
                            aesCryptStream2.Write(aesDataIn, 0, aesDataIn.Length);
                            aesCryptStream2.FlushFinalBlock();

                            bytesParamD = aesCryptStream.ToArray();
                        }
                    }
                    finally
                    {
                        if (aesCryptStream2 != null)
                        {
                            aesCryptStream2.Dispose();
                        }
                        else if (aesCryptStream != null)
                        {
                            aesCryptStream.Dispose();
                        }
                    }
                }

                // HTTP Fetch
                HttpRequest request = new HttpRequest();
                request.Url             = url;
                request.Parameters["s"] = UtilsString.Base64Encode(bytesParamS);
                request.Parameters["d"] = UtilsString.Base64Encode(bytesParamD);

                HttpResponse response = Engine.Instance.FetchUrl(request);

                try
                {
                    byte[] fetchResponse      = response.BufferData;
                    byte[] fetchResponsePlain = null;

                    MemoryStream aesDecryptStream  = null;
                    CryptoStream aesDecryptStream2 = null;

                    // Decrypt answer

                    try
                    {
                        aesDecryptStream = new MemoryStream();
                        using (ICryptoTransform aesDecryptor = rijAlg.CreateDecryptor())
                        {
                            aesDecryptStream2 = new CryptoStream(aesDecryptStream, aesDecryptor, CryptoStreamMode.Write);
                            aesDecryptStream2.Write(fetchResponse, 0, fetchResponse.Length);
                            aesDecryptStream2.FlushFinalBlock();

                            fetchResponsePlain = aesDecryptStream.ToArray();
                        }
                    }
                    finally
                    {
                        if (aesDecryptStream2 != null)
                        {
                            aesDecryptStream2.Dispose();
                        }
                        else if (aesDecryptStream != null)
                        {
                            aesDecryptStream.Dispose();
                        }
                    }

                    string finalData = System.Text.Encoding.UTF8.GetString(fetchResponsePlain);

                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(finalData);
                    return(doc);
                }
                catch (Exception ex)
                {
                    string message = "";
                    if (response.GetHeader("location") != "")
                    {
                        message = MessagesFormatter.Format(Messages.ManifestFailedUnexpected302, response.GetHeader("location"));
                    }
                    else
                    {
                        message = ex.Message + " - " + response.GetLineReport();
                    }
                    throw new Exception(message);
                }
            }
        }