【WP開發】不一樣客戶端之間傳輸加密數據

在上一篇文章中,曾說好本次將提供一個客戶端之間傳輸加密數據的例子。前些天就打算寫了,只是因一些人類科技沒法預知的事情發生,故拖到今天。算法

本示例沒什麼技術含量,也沒什麼亮點,Bug林立,只不過提供給有須要的朋友娛樂娛樂一下,喜歡鑽牛角尖的朋友最好別看,不然會讓你一把鼻涕一把淚的。服務器

好,廢話到此爲止。dom

由於在Windows上的RT應用程序的加/解密方法和上一篇文章中我給你們講述的WP加解密的方法是同樣的,畢竟那是共享的API。爲了達到充分裝逼的效果,我準備的服務器應用程序爲Windows Forms應用程序,這類項目相信你們都無比熟悉了,若是你不知道Windows Forms是啥,那就沒辦法了。async

客戶端固然是WP手機端了。爲了裝逼而又不復雜,個人思路是這樣的:ide

一、在WP端上選擇一張.jpg靚照,經過DES算法加密,而後經過HTTP POST到服務器應用程序上。測試

二、做爲服務器的Windows Forms應用收到文件後,用DES算法解密,並保存接收到的文件。ui

三、爲了便於處理,加密和解密的密鑰都固定。key爲12345678共八個字節,iv爲12345678共八個字節。this

 

先說服務器端,由於你們都熟悉。那麼,若是創建一個臨時的HTTP服務器來監聽鏈接呢。就是爲了方便,因此我纔不建ASP.NET應用程序,這樣的小演示,就不要勞煩IIS君了。其實,在System.Net命名空間下,有一個HttpListener類,它能夠經過編寫代碼創建一個簡單的HTTP服務器,並添加綁定的URI列表,能夠監聽HTTP請求,而後做出處理。加密

在使用HttpListener前,最好調用它的靜態的IsSupported屬性來確認一下,你當前的系統是否能支持HTTP監聽。spa

            if (!HttpListener.IsSupported)
            {
                MessageBox.Show("你當前的系統太破,不支持HTTP監聽。");
                this.Close();
            }

經過這一檢查後,說明系統是支持的,而後再實現後面的功能。這裏順便說說配置服務器地址時要注意的一些小事。

一、綁定的URI加到Prefixes集合中。

二、URI的路徑能夠本身安排,好比http://192.168.1.101:8080/sv/,也能夠http://192.168.1.101:8080/a/b/c/,假設你的IP是192.168.1.101,不該該用localhost,由於它只有本機才能訪問,實際上就是127.0.0.1。

URI必須以HTTP開頭,以/結尾,尤爲是結尾,不要少了/,不然會發生異常。

若是不肯定個人IP呢,或者說綁定本地多個IP呢,能夠這樣http://+:80/rec/,80是端口號,你能夠根據實際來指定。

 

調用Start方法開始監聽,調用Stop方法中止。我這裏用一個Task來循環監聽鏈接。主要代碼以下:

            this.mHttpListener.Start();
            Task backTask = new Task(WorkInBack, mHttpListener);
            backTask.Start();

            ……
        private async void WorkInBack(object obj)
        {
            HttpListener httpSvr = obj as HttpListener;
            while (httpSvr.IsListening)
            {
                HttpListenerContext context = await httpSvr.GetContextAsync();
                // 從標頭中提取文件名
                string fileName = context.Request.Headers.Get("file_name");
                fileName = Path.Combine(this.docFolderPath, fileName);
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
                using (FileStream outStream = File.OpenWrite(fileName))
                {
                    MemoryStream tempStream = new MemoryStream();
                    // 解密
                    byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8 };
                    byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 };
                    DESCryptoServiceProvider des=new DESCryptoServiceProvider();
                    CryptoStream streamCrypt = new CryptoStream(tempStream, des.CreateDecryptor(key, iv), CryptoStreamMode.Write);
                    context.Request.InputStream.CopyTo(streamCrypt);
                    //streamCrypt.Flush();
                    // 複製內存流到文件流
                    tempStream.Position = 0L;
                    tempStream.CopyTo(outStream);
                    streamCrypt.Dispose();
                    tempStream.Dispose();
                }
            }
        }

在傳統.net程序中使用DES加解密相信你們都用得很多了,我就不介紹了。IsListening屬性能夠判斷監聽器是否正在工做,若是Stop了就再也不接收鏈接請求了。

文件名是從file_name標頭中獲取的,這個標頭是自定義的,在WP客戶端發送文件時順便加上這個標頭。

 

下面是WP客戶端的實現。

這裏用到我之前說過的文件選擇器。前面文章中我說過,FileOpenPicker的PickSingleFileAndContinue方法調用後,會暫時離開當前應用,等用戶選擇完後,會從新激活應用,並經過OnActivated方法把用戶選擇的文件傳遞進來。

        protected override void OnActivated(IActivatedEventArgs args)
        {
            if (args.Kind == ActivationKind.PickFileContinuation)
            {
                FileOpenPickerContinuationEventArgs e = (FileOpenPickerContinuationEventArgs)args;
                if (e.Files.Count > 0)
                {
                    StorageFile theFile = e.Files[0];
                    Frame root = Window.Current.Content as Frame;
                    if (root != null)
                    {
                        MainPage page=root.Content as MainPage;
                        if (page != null)
                        {
                            page.SendFile(theFile);
                        }
                    }
                }
            }
            Window.Current.Activate();
        }

SendFile方法是在MainPage頁面類中公開的一個自定義方法,代碼以下:

        public async void SendFile(StorageFile file)
        {
            IRandomAccessStream encryptedstream = null;
            using (IRandomAccessStream inStream = await file.OpenReadAsync())
            {
                encryptedstream = await EncryptoDataAsync(inStream);
            }
            using (HttpClient client = new HttpClient())
            {
                client.DefaultRequestHeaders.Add("file_name", file.Name);
                HttpResponseMessage response = null;
                using (HttpStreamContent content = new HttpStreamContent(encryptedstream))
                {
                    response = await client.PostAsync(new Uri(txtServer.Text), content);
                }
                if (response != null && response.StatusCode == HttpStatusCode.Ok)
                {
                    // 發送成功
                }
            }

        }

HttpClient比較好的地方是它對要發送的內容能夠以不一樣內容格式進行封裝。

好比,要發字符串,就用HttpStringContent;要發送 multipart/form-data MIME數據就用HttpMultipartFormDataContent。此處,發送的是文件,應該用HttpStreamContent,以流的形式發送。

 

在上面代碼中,EncryptoDataAsync是我定義的一個方法,做用固然是將輸入的文件流加密,再存放到內存流中,並將內存流返回。代碼:

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="inputStream"></param>
        /// <returns></returns>
        private async Task<IRandomAccessStream> EncryptoDataAsync(IRandomAccessStream inputStream)
        {
            byte[] bytekey = { 1, 2, 3, 4, 5, 6, 7, 8 };
            byte[] byteiv = { 1, 2, 3, 4, 5, 6, 7, 8 };
            IBuffer key = bytekey.AsBuffer();
            IBuffer iv = byteiv.AsBuffer();
            SymmetricKeyAlgorithmProvider prd = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.DesCbcPkcs7);
            // 建立密鑰
            CryptographicKey crykey = prd.CreateSymmetricKey(key);
            // 加密數據
            InMemoryRandomAccessStream mms = new InMemoryRandomAccessStream();
            IBuffer orgData = null;
            using (DataReader reader = new DataReader(inputStream))
            {
                uint len=(uint)inputStream.Size;
                await reader.LoadAsync(len);
                orgData = reader.ReadBuffer(len);
            }
            IBuffer res = CryptographicEngine.Encrypt(crykey, orgData, iv);
            await mms.WriteAsync(res);
            mms.Seek(0UL);
            return mms;
        }

前面在說雙向加密時,介紹過RT API中加密解密的過程。

先經過SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.DesCbcPkcs7)得到一個實例。
而後,建立CryptographicKey實例,做爲加密用的key。

最後,用CryptographicEngine類來完成加密。

==============================

示例核心部分已經向你們介紹了。其他部分省略5000多個字,稍後我會把源代碼打包上傳。

注意在使用源碼時,以管理員身份運行VS,這樣HTTP服務才能監聽;手機端用真機測試容易鏈接;要是連不上,就先把防火牆關了再試,試完了從新開啓防火牆便可。

下載地址:http://files.cnblogs.com/files/tcjiaan/Sample.zip

相關文章
相關標籤/搜索