在上一篇文章中,曾说好本次将提供一个客户端之间传输加密数据的例子。前些天就打算写了,只是因一些人类科技没法预知的事情发生,故拖到今天。算法
本示例没什么技术含量,也没什么亮点,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服务才能监听;手机端用真机测试容易链接;要是连不上,就先把防火墙关了再试,试完了从新开启防火墙便可。