如何用神經網路來恢復破損的密碼?

renlytime發表於2016-03-10

在這份教程中,我們將會學習到如何使用神經網路來恢復破損的密碼。如果你對 DiscreteHopfield 網路演算法不是很瞭解的話,你可以通過閱讀這篇 教程 來加強了解。

在開始實驗之前,我們需要先設定一個種子引數使所有實驗結果都可以重現。但是,沒有這個引數程式也能正常工作。

如果所安裝的Python版本或庫版本過低,導致你無法重現上面的結果,你可以自行安裝我們在這份教程中所需要的庫。

所有的程式碼同樣在Python2.7的環境中編譯通過。

資料轉換

在建立用於儲存和恢復密碼的神經網路之前,我們需要先轉換輸入輸出的資料。但是,僅僅對其編碼是不夠的,我們應當為輸入資料設定一個固定長度以確保字串之間的長度一致。我們也要預先決定使用什麼編碼方式,為了簡單易懂,我們選擇ASCII碼。現在讓我們來定義用於將資料轉換成二進位制列表的函式吧。

這個函式需要傳入兩個引數,第一個是我們需要對其編碼的字串,第二個則為設定傳入字串的最大長度。只有傳入字串的長度小於最大長度,程式才會繼續執行。

然我們來看看 str2bin 的 輸出情況

ASCII 編碼使用八個位元組來存放一個字元,而我們這裡將每個字串最大長度設定為5。所以我們的向量長度等於40。從第一個輸出結果可以看到,第一組八個符號 00100000 在 ASCII 表中表示空格。

在完成密碼恢復過程的預處理之前,我們得到的總是一個 二進位制的的列表。所以在我們將資料存到神經網路裡面之前,我們需要在定義個函式用來將列表中二進位制轉回字串。(差不多與前一個函式功能相反)

如果函式的返回值為 ‘test’ 則說明我們的函式正確執行。

注意!如果二進位制列表中是以空格開始,那麼在轉換時這些空格將會被刪去,我們就假定密碼不會以空格開始吧。

將密碼儲存到神經網路中

Now we are ready to save the password into the network. For this task we are going to define another function that create network and save password inside of it. Let’s define this function and later we will look at it step by step.

我們已經做好將密碼儲存至神經網路中的準備了。現在我們將會針對這個過程在定義一個函式去建立神經網路並將密碼存入其中。現在先來看看這個函式吧,稍後我們將會對其逐步分析。

如果你已經讀過 Discrete Hopfield Network tutorial , 你就會知道如果我們只新增一個向量到神經網路中,則會複製這個向量,或者會將整個矩陣逆轉。為了保障安全性,我們可以在網路中新增一些噪聲。我們可以再新增一個 noise_level 的引數到函式中。這個引數將會控制隨機產生的二進位制向量數量。 使用二項分佈將每次迭代產生噪音向量的概率控制在55%。然後我們就可將噪音頂點和傳過來的密碼存入矩陣,最後我們將所有資料存入 Discrete Hopfield Network 中。

然後函式將會返回一個訓練過的網路供以後使用。

但是我們為什要使用隨進二進位制向量來代替隨機解碼過的字串呢?問題在於兩個向量往往非常相似。現在可以來檢查下兩種方法,然後比較他們的  Hamming 距離。但是在開始之前,我們需要定義一個用來比較向量距離的函式。

此外,你還能看到 generate_password 這個我們將會用來幫助測試的函式。讓我們來檢查兩個隨機產出的密碼向量之間的 Hamming 距離吧。

正如你所看到的那樣,兩個隨機產生的向量的相似度非常高(大約 70% 位元組都是一樣的(((100 * (240 – 70) / 240))))。但是將我們隨機產生的密碼和二進位制的向量進行比較,就能很容易發現不同。

Hamming 距離比上一個來得要大。 有大約55%的位元組不一致。

這種差距可以幫助我們簡化恢復從神經網路輸入的向量這一過程。所以我們使用隨機產生二進位制向量取代隨機產生字元。

當然,存入沒有經過隨機生成的噪音向量要好比將隨機產生的密碼轉換成二進位制向量要好,但是如果你使用錯誤的隨機輸入模式可能會覆蓋掉正確的向量。

從神經網路中恢復密碼

現在我們可以定義一個函式來從神經網路中恢復密碼了。

函式需要兩個引數,第一個引數用來指定一個網路模板,用來恢復破損的密碼。而第二個引數是指破損的密碼的字串。

終於可以來測試從神經網路中恢復密碼啦!

現在一切執行正常,即使在程式碼多次執行之後你也不會有任何問題出現。神經網路現在能夠自行產生字串。這個字串除了一些符號而外,幾乎和我們的密碼一模一樣。這個問題是因為當神經網路在輸入的時候產生了區域性最優解。我們不能在運算最優解的時候預防這種情況。你可以通過閱讀 tutorial about Discrete Hopfield Network 來了解這個問題的其他細節。

使用Monte Carlo進行測試

然我們來通過隨機產生的密碼來測試我們的程式吧。我們現在可以使用 Monte Carlo 來進行測試, 每一次我們都產生隨機密碼然後嘗試恢復這個密碼。

在你提交之後,你的輸出結果應該和下面一致。(如果你是一步一步跟著教程做的話)

著這個測試中我們可以在神經網路嘗試恢復同一個密碼時發現兩種解。這不是太好,但這個取決與我們在網路中所儲存的噪音。隨機化並不能給我們完美的結果。有時他甚至能從一個空字串中恢復出密碼,但這種情況並不多見。

最後,每一次迭代我們都總左邊擷取密碼並將用空格填充,現在我們來試試從右邊來擷取密碼,然後我們會得到以下結果。

結果和前面很像

另一個有趣的測試會發生在放你想要用空格來替代字元時。

還是和前面的結果很像

最後,我們不用空格來替代字元,我這次將其刪去,這次結果不是太好。

我猜在第一種情況下(不含一),我們只是很幸運,在刪去一個字元的同時並沒有使其他更多的字元被改變。所以,刪除字元並不是一個好主意。

所有需要實驗的函式你都能在 github 找到。

潛在問題

這裡有些可能會在 Discrete Hopfile Network 發生的問題

1. 我們在最後一個實驗中我們發現字元的位移要比字元的缺失更難恢復,所以最好用空格代替缺失的字元。
2. 是可能從空字串中恢復出密碼的。
3. 相似的二進位制碼代表不同的字元是個大問題,有時你會發現兩個不同的字元在轉換為二進位制後只有一個位元組不同。我們可以使用 One Hot Encoder 來解決這個問題。但是這樣會給我們帶來更多的問題。舉個例子,我們使用一個包含 94 個字元的字元列表作為密碼,如果你對每一個字元都進行解碼,我們將會得到一個有 93 個0和一個有效數字組成的向量。問題在於我們總是需要一個有效數字來恢復密碼,不過這個發生的可能性很低。

總結

儘管存在一些問題,使用神經網路來恢復密碼是確實可行的。通過 Monte Carlo 實驗我們可以知道只有少數的字元存在不能正確恢復的可能性。

在你充分了解這個程式的限制以後,即使只是簡單的神經網路也可以發揮出強大的功能。

下載程式碼

你可以從 github repository 看到所有的程式碼和測試。

相關文章