《101 Windows Phone 7 Apps》读书笔记-PASSWORDS SECRETS
課程內容
? 加密和解密
? 密碼輸入框
? 值轉換
? DataTimeOffset
? 可觀察集合
? INotifyPropertyChanged事件
?
??? Passwords & Secrets是一個類似記事本風格的應用,它有一個主人保護密碼。因此,我們可以用它來存儲大量的密碼和一些不希望落入他人之手的秘密。當然,它的記事功能是一流的,支持:
? 自動保存,使得速記變得快速而簡單。
? 提供每條筆記的快速預覽。
? 可自定義每條筆記的背景色、前景色和字體大小。
? 可通過Email發送筆記。
??? 此外,每條筆記的數據會通過256位的AES加密算法進行加密,確保數據的私密性。這個加密過程也是建立在主人保護密碼的基礎上的,所以,用戶千萬不能忘記各自的保護密碼。沒有它,應用程序就沒有方法獲取數據,出于安全考慮,應用程序不會存儲該密碼。
??? 為了使管理主人密碼盡量簡單,Passwords & Secrets支持忘記密碼提示。應用程序也允許改變主人密碼(這也是以知道當前密碼為前提的)。
??? 為什么我需要對隔離存儲空間中的數據進行加密?不是只有應用程序才能獲取嗎?
??? 除非Windows Phone OS存在漏洞,其他應用程序是無法讀取本應用程序的隔離存儲空間的。而且,也沒有人可以遠程獲取隔離存儲空間的數據。但是,如果有能力的黑客從物理上攻破了你的設備,那么他們當然可以讀取存儲在其中的數據。數據加密以后,黑客們實際上很難再讀懂數據的意義了。
?
Basic Cryptography
??? Silverlight的System.Security.Cryptography命名空間中包含了一些具備加密功能的函數。本應用程序封裝了這些函數,形成了一個簡單易用的Crypto類。該類包含兩個簡單的方法:Encrypt 和 Decrypt,它們利用密鑰和解密/加密的數據來進行解密/加密的操作。
??? Encrypt 和 Decrypt都調用了GetAlgorithm helper方法(在文件的最后有定義)。返回的算法可以創建encryptor 或者 decryptor,它會被傳送給crypto stream,從而完成加密/解密過程。
??? 在Encrypt中,輸入的字符串被轉換成為UTF8編碼的字符。然后,這些字符被寫入crypto stream,來完成加密過程。通過ToArray方法,就可以在crypto stream使用的內存中獲取加密后的字符。這些字符通過Base64編碼轉換為stream,這是一種代表字符串中二進制數據的常用方法。
??? Decrypt從Base64編碼的字符串開始,將其轉換為寫入crypto stream的字符。然后,使用相應的ToArray方法將解密后的UTF8編碼的數據轉換為字符串。
??? 對輸入字符串使用SHA256(256位Secure Hash Algorithm)哈希加密,在其前面添加一個隨機的“salt”。這有時候被稱為salted hash。本應用程序調用這個方法來存儲密鑰的salted hash,而不是密鑰本身,來確保安全性。畢竟,如果黑客得到了隔離存儲空間中的數據,而密鑰是以普通文本的形式存放,那么,對數據加密就顯得毫無意義了。
??? GenerateNewSalt方法隨機產生一個指定長度的byte數組。與其他應用程序中使用Random類不同,該方法使用了一種高度偽隨機數產生器RNGCryptoServiceProvider,更適用于加密應用。正如下一節所示,就在應用程序第一次運行時,調用一次該方法。它將隨機產生的salt存放于隔離存儲空間中,用于隨后所有的加密、加密和哈希算法。
??? GetAlgorithm方法用于構造唯一內置的加密算法,即AesManaged,一種AES對稱加密算法。該算法初始化時,需要一個密鑰和一個初始化向量(IV),因此,它由Rfc2898DeriveBytes實例來處理。
??? Rfc2898DeriveBytes是基于密碼的密鑰派生功能- PBKDF2的實現。它使用密碼和一個隨機的salt值,將基于SHA1哈希功能的隨機函數執行很多次(默認是1000次)。這就使得密碼更難被破譯。
??? AesManaged中KeySize屬性的默認值也是它所支持的最大值:256。這意味著密鑰的長度是256,也就是為什么這個過程被稱為256比特的加密。
Salt in Cryptography
??? 使用salt可以帶來一些好處,特別是salt可以用來保密,使得黑客破譯的速度變慢。在本應用中,雖然salt值必須傳遞給Rfc2898DeriveBytes的構造函數,但是它并沒有改變,因為salt必須和加密后的數據一同存放。Hash函數中的salting也是一樣的道理。這對于管理多個密碼的服務器來說,是一種好的方法(因此,以字典為基礎的攻擊必須為每個用戶重新產生數據,即使用戶的密碼相同,它們的hash值也不同),這在本應用程序中得到了較好的體現。
?
The LoginControl User Control
??? 有了Crypto類,我們可以創建一個登陸控件,用來處理所有應用程序密碼輸入的交互。LoginControl用戶控件有3種不同的模式:
? 新用戶模式:用戶第一次使用時,必須選定主控密碼。
? 普通登陸模式:用戶登錄時,必須輸入之前選定的密碼。
? 修改密碼模式:在用戶輸入當前的密碼以后,可以修改其主控密碼。
注意:
? 該控件在需要輸入密碼的地方使用了password box。password box和text box類似,只是每個字符都是以小圓點顯示(在你輸入字符一段時間以后將會看到)。這與內置應用的密碼輸入行為相匹配。與Text屬性不同,它使用的是Password屬性。
? 第17章“Pick a Card Magic Trick”中的不透明度屏蔽技巧用來給出具有當前主題強調色的鎖的圖案。它的不透明度為50%,所以有點融入了背景中。
注意:
? 該列表使用了以下在Settings.cs文件中定義的一些設置:
Crypto類使用的Rfc2898DeriveBytes方法中,salt的長度至少是8個字節。本應用程序調用GenerateNewSalt,產生salt的長度是16個字節。
? 在普通登錄模式中,該控件必須判斷輸入的密碼是否正確。但是應用程序并沒有存儲用戶密碼。然而,它存儲了密碼的salted hash值。因此,為了驗證輸入的密碼,應用程序調用相同的Crypto.Hash函數,并檢查它與存儲的值是否一致。
? 雖然未加密的密碼沒有被存儲,但是應用程序將它保存在RAM中,所以應用程序能夠解密用戶保存的數據,并且對新數據進行加密。這些在CurrentContext類中完成,其定義如CurrentContext.cs所示。
? 在修改密碼模式中,舊密碼起到了非常重要的作用。因為那些使用舊密碼加密的數據必須通過舊密碼來解密,然后再使用新密碼進行加密。否則的話,原來存儲的數據會無法讀取,因為無法使用新密碼來解密舊密碼加密的數據。
? 在Close中,每個password box的Password屬性被設置為一個空字符串,而非空,因為如果設置為空的話,Password屬性會跑出一個異常。
? 我們可以發現,LoginControl并不是一個通用的控件,而是為本應用定制的(雖然在更改密碼過程中,通過給用戶提供鉤子來完成數據的重新加密并不是一件難事)。如本章的下面三節所示,它被使用在三個不同的地方。
?
The Main Page
??? 本應用的主頁面包含了用戶筆記的列表,如圖21.2所示。點擊每條記錄,可以對其進行瀏覽和編輯。應用程序欄上的按鈕使得我們可以增加新的記錄。但在列表形成并顯示之前,用戶必須輸入正確的密碼。在用戶沒有登錄的情況下,LoginControl除了header以外,會占據整個頁面,應用程序欄中也沒有了新增記錄的按鈕。
圖21.2 應用程序主頁面
注意:
? 應用程序標題中的“&”符號使用XML編碼,避免XAML解析錯誤。
? LoginControl用戶控件作為本頁面的一部分,而非獨立的登錄頁面,這樣是為了確保流暢的導航體驗。當用戶打開應用程序,登錄,看到主頁面上的數據,按硬件“Back”按鈕,應該退出應用程序,而非回到登錄頁面!
? LoginControl并不是簡單地通過視覺掩蓋來保護數據的,從背后的代碼中我們可以看到,只有用戶登錄了以后,數據才會顯示出來。而且,在用戶登錄之前,應用程序是無法顯示數據的,因為對存儲的數據進行解密的話,需要正確的密碼。
? list box中的條目模板與每個記錄中的多個屬性進行綁定(用于顯示記錄的Note類在本章的后面部分講述)。與Modified屬性的綁定使用了值轉換器,它用來改變結果的顯示。值轉換器會在下面講述。
?
Value Converters
??? 在數據綁定中,值轉換器可以將源數據轉換為一個完全不同的目標類型,使得我們可以在不丟失數據綁定好處的情況下,嵌入自定義邏輯。
??? 值轉換器被經常用來在源數據和目標數據類型之間進行轉換。比如,我們可以使用一些nonbrush的數據源來改變元素的背景色或者前景色,就像Microsoft Excel中的條件格式一樣。另外一個例子,Silverlight for Windows Phone Toolkit中的toggle switch控件具有一個稱為OnOffConverter的值轉換器,它把非空的布爾類型值IsChecked轉變為“On” 或者 “Off”為默認內容的字符串。
??? 在Passwords & Secrets應用中,我們想要對每條記錄的Modified屬性顯示做輕微的自定義。它的數據類型是DateTimeOffset,如果沒有值轉換器,它的顯示效果如下:
??? 12/11/2012 10:18:49 PM -08:00
??? -08:00代表時區,它表示與國際標準時間(UTC)之間的偏差。
??? 我們使用的自定義值轉換器省略了時區信息和秒,因為那些信息我們不需要。因此顯示效果如下:
??? 12/11/2010 10:18 PM
??? 即使Modified屬性是DateTime類型,而非DateTimeOffset,為了將秒從字符串中省去,值轉換器仍舊是有用的。
??? DateTime和DateTimeOffset這兩種數據類型有何區別?
??? DateTime是指與任何時區無關的邏輯時間點,而DateTimeOffset是指與UTC時間存在偏差的實際時間點。在本應用中,DateTimeOffset更適合給每條記錄的修改時間使用,因為即使用戶接下來會到另一個時區,他們也不希望時間點會改變。但是,在前一章“Alarm Clock”中,提醒時間使用了DateTime類型。假設你在一個時區設置了鬧鐘,但是在鬧鐘要響起的時候,你卻在另一個時區。例如,我們設置鬧鐘在早晨8點,那么,無論我們在哪個時區,我們都希望鬧鐘準時響起。
??? 對于大多數情況來說,使用DateTimeOffset要優于DateTime。但是,相對于DateTime來說,.NET Framework引入DateTimeOffset要晚幾年,所以命名已經被使用了(類的設計者拒絕稱之為DateTime2 或者 DateTimeEx)。幸運的是,這些數據類型的用戶可以經常交換地使用它們。
??? 為了創建一個值轉換器,我們必須寫一個實現System.Windows.Data 中的IValueConverter接口的類。該接口具有兩個簡單的方法:一個是Convert,它被傳入必須轉換為目標實例的源實例;另一個是ConvertBack,它正好相反。列表21.7包含了列表21.6中使用的DateConverter值轉換器的實現。
??? 每次源值改變時,Convert方法就會被調用。傳入DateTimeOffset值,返回短格式的日期和時間字符串。ConvertBack方法不是必須的,因為它只在雙向數據綁定中使用。因此,它返回一個虛值。
Additional Data for Value Converters
??? IValueConverter方法傳入一個參數和一個本地化語言類型。默認情況下,參數設置為空,本地化語言設置為目標元素的Language屬性值。但是,綁定的用戶仍舊可以通過Binding.ConverterParameter 和 Binding.ConverterCulture來控制這兩個值。
?? 傳遞給值轉換器類的ConverterParameter參數可以是任意的用戶數據,就像元素的Tag屬性一樣。ConverterCulture可以設置為因特網工程任務推動小組(IETF)語言標簽(如en-US 或者 ko-KR),值轉換器接收合適的CultureInfo對象。在DateConverter中,ToString方法已經遵守了當前的語言規則,所以沒有必要再做本地化相關的工作。
??? 與基本的格式轉換不同,值轉換器是把用戶邏輯融入數據綁定過程的關鍵。在原始數據進行顯示之前想要對其進行某種改變,或者基于原始數據的目標更新,這些都可以通過實現了IValueConverter的類來輕松實現。
??? 人們創建的最常見的值轉換器是Boolean-to-Visibility(常常被稱為BooleanToVisibilityConverter),它可以將數據在可視性枚舉值和布爾值(或者是非空布爾值)進行轉換。在一個方向上,true被轉換為Visible,而false和null被映射為Collapsed。另一個方向上,Visible被映射為true,而Collapsed被映射為false。這對于以下的情況比較有用,即將一個XAML控件元素的可視性與另一個不相關的XAML控件元素的狀態關聯起來。比如,下面的XAML片段實現了一個Show Button check box,而不需要使用程序代碼(除值轉換器之外)。
??? 在這種情況下,button只有在check box的IsChecked屬性為true時可見。
圖21.3 應用程序欄展開頁面
注意:
? 如圖21.3所示,應用程序欄的第一個menu起到下面的作用:在用戶沒有登錄的情況下給出密碼提示,在用戶已經登錄的情況下給出密碼修改頁面。
? 正如之前所提到的,作為list box 控件數據內容的NotesList集合與普通的集合不同(如List<Note>),它是一個可觀察的集合。
??? 在發生任何改變時(比如新增條目或者刪除條目),可觀察的集合會觸發一個CollectionChanged事件。數據綁定自動將此消息發送給目標控件(本頁面的list box),從而保持一致性。
??? 盡管可觀察的集合可以處理list box控件中條目的增加和刪除,但是每個Note條目必須在其屬性改變時發送通知,確保它反應在數據綁定的list box中。如列表21.9所示,Note通過實現INotifyPropertyChanged接口來完成此功能。
?INotifyPropertyChanged只有一個成員- PropertyChanged事件。如果其中任何一個屬性在一個合適的時間被改變,那么這個事件就會被觸發,數據綁定負責目標控件的數據刷新。
?被觸發的PropertyChanged事件由OnPropertyChanged helper方法來處理。為了避免bug,將一個handler變量賦值給event handler字段。否則,如果當前線程在檢查handler是否為空并調用它時,另一個線程對其進行刪除操作,那么NullReferenceException異常便會拋出(在沒有listener的情況下,event handler字段變為空)。
?Dependency屬性自動實現change-notification機制,其特性與INotifyPropertyChanged類似,但略有不同。因此,在使用Dependency屬性時,不需要額外的代碼,就可以完成與數據綁定配合的change notification。
?某些屬性會因為額外的屬性發生改變而觸發PropertyChanged事件。比如,當EncryptedContent被設置為一個新值的時候,PropertyChanged會因為readonly Title屬性而被觸發。這是因為Title的值是基于EncryptedContent的值,所以EncryptedContent的改變會導致Title的改變。
?可觀察集合通過實現INotifyCollectionChanged接口來完成出色的功能,INotifyCollectionChanged接口與INotifyPropertyChanged類似,包含了一個CollectionChanged事件。但是,讓用戶自己寫collection 類,并且實現INotifyCollectionChanged接口,而不是單純地使用ObservableCollection類,這種情況也是非常少見的。
?
The Details Page
??? 詳細頁面如圖21.4所示,當用戶點擊主頁面上的list box控件中的記錄時,便會彈出。該頁面顯示了一條記錄的全部內容,允許用戶對其進行編輯、刪除或者利用其內容發送郵件。另外,通過它還可以進入每條記錄的設置頁面,用來控制字體的顏色和大小。在瀏覽模式中,應用程序欄可見。在編輯模式中,應用程序欄隱藏。
??? 該頁面的text box基本占據了整個屏幕,它已經被用戶自定義了,我們移除了它的邊界,無論text box是否獲得焦點,其背景色一直可見。這種風格來源于
%ProgramFiles%\Microsoft SDKs\Windows Phone\v7.0\Design\System.Windows. xaml,不是新創建的。
注意:
?該頁面使用了navigatingFrom標志來檢查頁面是否處于被導航的狀態。那是因為OnNavigatedFrom后,Loaded事件會被再次觸發,此時如果將焦點給text box的話,會導致屏幕鍵盤閃現。
?本頁面的設置頁面的代碼會在下一章詳述,因為它和本應用程序使用的方式相同。
?在導航到別的頁面時,頁面的Loaded事件被錯誤觸發!這是當前Windows Phone版本的一個bug。為了避免這種閃屏或其他的問題,考慮在OnNavigatedFrom中設置一個標志,在Loaded事件中進行檢查。那樣的話,我們就可以確保頁面加載邏輯只在頁面加載時執行。
轉載于:https://www.cnblogs.com/dearsj001/archive/2012/08/09/101App4WP7_Passwords.html
總結
以上是生活随笔為你收集整理的《101 Windows Phone 7 Apps》读书笔记-PASSWORDS SECRETS的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tmux之简介
- 下一篇: 对高级软件工程课程的展望 by 吴双志