老周的部落格http://blog.csdn.net/tcjiaan,轉載請註明原作者和出處。
對於一些需要特列保護的資料,舉個例子,剛從伺服器上取到的一堆JSON資料,並儲存到本地檔案中,你知道,JSON資料是文本,如果我不希望別人查看資料,可以對檔案進行加密,今天,我們來看一種比較簡單的資料加密和解密。
實現這一構想,我們需要用到Windows.Security.Cryptography.DataProtection命名空間下的DataProtectionProvider類,各位可以開啟“物件瀏覽器”查看一下。
使用方法如下:
DataProtectionProvider類有兩個建構函式,即
1、
public DataProtectionProvider()
2、
public DataProtectionProvider( string protectionDescriptor)
在加密資料的時候,使用第二個建構函式,即帶一個參數的,參數為字串類型,但是,這個字串不是亂寫的,不信你試試,隨便寫個字串進去,加密的時候就會拋出異常。所以,這個參數應取下面這些值。
/****************************************************************************Example Protection Descriptors: "SID=S-1-5-21-4392301 AND SID=S-1-5-21-3101812" "SDDL=O:S-1-5-5-0-290724G:SYD:(A;;CCDC;;;S-1-5-5-0-290724)(A;;DC;;;WD)" "LOCAL=user" "LOCAL=machine" "WEBCREDENTIALS=MyPasswordName" "WEBCREDENTIALS=MyPasswordName,myweb.com"****************************************************************************/
而對於本地加密,只有兩個可以用,其他的都會發生異常,哪兩個呢?你猜,看他們的名字,本地使用的嘛,肯定帶有“local”字樣的,看看,上面的各值,哪些是帶“local”的?
對,就是這兩個
LOCAL=user
LOCAL=machine
那麼它們有啥區別呢?看它們的值,懂了嗎?一個是使用者層級的加密,另一個呢?哈,當然是機器層級的。
我估計是這樣的,有興趣的朋友可以自己做做實驗。
對於user層級,例如,我以使用者名稱“dog”登陸了當前系統,然後我運了程式App,我在App中將檔案kill加了密,如果我要將加密後的檔案解密還原到kill的內容,當前電腦必須用“dog”的使用者登陸才能完成操作。
而machine層級就好理解了,就是本機,拿到其他電腦上就解不了密,雖然SDK文檔沒有明地說明,但我估計應該是這樣的。
雖然這種方式不能算是十分安全,但是對於一般資料就足夠了。
接下來,我們通過一個執行個體來說一下如何使用。
1、啟動VS,建立項目。
2、頁面的XAML如下。
<Page x:Class="App2.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:App2" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <StackPanel> <Button Name="btnPickInputFile" Content="輸入檔案..." Margin="5,14,0,10" Click="onInputFile"/> <Button Name="btnPickOutputFile" Content="輸出檔案..." Margin="5,8,0,10" Click="onOutputFile"/> <Line Margin="0,3,0,12" Stroke="LightGray" StrokeThickness="3"/> <Button Content="保護檔案" Click="onProtect"/> <Button Content="解除保護" Click="onUnProtect"/> <TextBlock Name="msgLabel" Margin="2,12,0,0" FontSize="20"/> </StackPanel> </Grid></Page>
3、轉到程式碼檢視,完成後面的代碼,自己看看。
using System;using System.Collections.Generic;using System.IO;using System.Linq;using Windows.Foundation;using Windows.Foundation.Collections;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Controls.Primitives;using Windows.UI.Xaml.Data;using Windows.UI.Xaml.Input;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Navigation;using Windows.Security.Cryptography.DataProtection;using Windows.Storage;using Windows.Storage.Streams;using Windows.Storage.Pickers;// “空白頁”項目範本在 http://go.microsoft.com/fwlink/?LinkId=234238 上有介紹namespace App2{ /// <summary> /// 可用於自身或導航至 Frame 內部的空白頁。 /// </summary> public sealed partial class MainPage : Page { StorageFile inputFile, outputFile; public MainPage() { this.InitializeComponent(); } /// <summary> /// 在此頁將要在 Frame 中顯示時進行調用。 /// </summary> /// <param name="e">描述如何訪問此頁的事件數目據。Parameter /// 屬性通常用於配置頁。</param> protected override void OnNavigatedTo(NavigationEventArgs e) { } private async void onInputFile(object sender, RoutedEventArgs e) { FileOpenPicker opPicker = new FileOpenPicker(); opPicker.SuggestedStartLocation = PickerLocationId.Desktop; opPicker.FileTypeFilter.Add(".txt"); opPicker.FileTypeFilter.Add(".data"); this.inputFile = await opPicker.PickSingleFileAsync(); Button btn = sender as Button; if (btn != null && inputFile != null) { btn.Content = inputFile.Path; } } private async void onOutputFile(object sender, RoutedEventArgs e) { FileSavePicker fsPicker = new FileSavePicker(); fsPicker.FileTypeChoices.Add("加密檔案", new string[] { ".data" }); fsPicker.FileTypeChoices.Add("檔案檔案", new string[] { ".txt" }); fsPicker.SuggestedStartLocation = PickerLocationId.Desktop; this.outputFile = await fsPicker.PickSaveFileAsync(); Button btn = sender as Button; if (btn != null && outputFile != null) { btn.Content = outputFile.Path; } } private async void onProtect(object sender, RoutedEventArgs e) { if (inputFile == null || outputFile == null) return; IRandomAccessStream inputstr = await inputFile.OpenAsync(FileAccessMode.Read); IRandomAccessStream outputstr = await outputFile.OpenAsync(FileAccessMode.ReadWrite); DataProtectionProvider dp = new DataProtectionProvider("LOCAL=user"); await dp.ProtectStreamAsync(inputstr, outputstr); this.msgLabel.Text = "完成資料加密。"; inputFile = null; outputFile = null; ClearDisplay(); } private async void onUnProtect(object sender, RoutedEventArgs e) { if (inputFile == null || outputFile == null) { return; } IRandomAccessStream inputstr = await inputFile.OpenAsync(FileAccessMode.Read); IRandomAccessStream outputstr = await outputFile.OpenAsync(FileAccessMode.ReadWrite); DataProtectionProvider dp = new DataProtectionProvider(); await dp.UnprotectStreamAsync(inputstr, outputstr); this.msgLabel.Text = "解密資料完成。"; inputFile = null; outputFile = null; ClearDisplay(); } private void ClearDisplay() { this.btnPickInputFile.Content = "輸入檔案..."; this.btnPickOutputFile.Content = "輸出檔案..."; //this.msgLabel.Text = string.Empty; } }}
代碼不算複雜,主要是DataProtectionProvider類的兩個方法:
ProtectStreamAsync——對資料進行保護,第一個參數是輸入資料流,即要加密的資料,第二個參數為輸出資料流,也就是加密後的資料。
UnprotectStreamAsync——解除對資料的保護,即解密。
上面兩個方法是針對流操作的,如果是針對位元組緩衝區,即使用IBuffer的,可以用這兩個方法:
ProtectAsync
UnprotectAsync
實現的效果是一樣的,只是針對不同的對象而設計罷了。
現在,運行一下程式。
1、在案頭上建立一個txt檔案,並輸入一些內容,儲存。
2、把滑鼠移到左上方,你會看到剛才啟動並執行應用程式,點一下,就切回到應用程式。
3、選擇剛才建立的文字檔作為輸入檔案,並選擇一個輸出檔案。
4、點擊保護檔案,完成加密。這時我們用記事本開啟加密後的檔案,看到的是亂碼。說明已加密。
5、回到應用程式,把剛才加密後的檔案作為輸入檔案,另外選取一個輸入檔案。點擊解除保護按鈕,完成後開啟解密後的檔案,對比一下原來的檔案,看到了吧,解密成功。