1. 程式人生 > >加密專案開發筆記(4)——PC後續

加密專案開發筆記(4)——PC後續

    在做完PC軟體的基礎功能後,接下來就是後續的功能完善和進一步拓展了

2018-10-28更新

  • 加入U盤認證功能
  • 加入拖拽檔案功能
  • 加入MD5碼完整性校驗
  • 解決在接收伺服器金鑰時UI無響應的情況
  • 加入頂欄選單
  • U盤認證

        U盤認證作為我一開始就放入這個軟體的代辦事項,在基礎功能完成後我第一個想實現的就是它了。本來在初次構思這個功能的時候我是想通過python的某些系統模組來獲取U盤的唯一識別碼,再將這個識別碼作為解密因子的一部分,結果上網查詢發現對於U盤的唯一識別碼的獲取是十分模糊的, 特別是對於Python語言來說這更加困難(將Python和U盤作為關鍵詞搜尋搜到的幾乎全是偷U盤檔案的。。),所以就打算自己設計一個演算法來實現U盤身份獲取的唯一性。

        首先我想到是在U盤記憶體放一個數據檔案儲存金鑰因子,但是我認為只用這個是不夠的,盜取U盤檔案的成本還是很低的,所以應該還需要一個穩定的標誌來輔助,我想到了U盤的一個天然的唯一識別符號——U盤容量,然或曰劣質U盤有可能會突然縮水,但是以我的想法這種概率應該是小於使用者誤刪金鑰因子檔案的概率。得到U盤的容量應當是非常容易的,得到後將其轉化為字串再與之前的金鑰因子拼接,然後進行某些hash加密得到一段二進位制字串將其作為整個U盤的認證符號。

        為了實現以上演算法,在這裡我使用了兩個系統模組——pstuil和win32api,其中psutil一般是用來獲取當前計算機的各類硬體資訊的,包括記憶體使用率CPU佔用率等等當然也包括磁碟資訊啦。然後win32api是用來呼叫Windows的一些系統API的;其中在這個演算法中psutil用來檢測U盤的插入情況以及其容量資訊,win32api用來隱藏金鑰因子檔案。

        首先用psutil的disk_partitions方法得到當前磁碟資訊List,取其長度,再提示使用者插入U盤,檢測長度的改變以及是否插入的是U盤,再獲得U盤的掛載點並利用其獲得U盤總容量(以位元組為單位)並儲存;接著在U盤根目錄建立資料夾,以及資料夾裡的檔案,將一段經過序列化的隨機字串存入其中,之後再利用win32api的SetFileAttributes方法設定隱藏檔案、資料夾;最後將隨機字串和容量拼接再使用hash加密得到金鑰因子,傳入主函式中。

        在這之中需要注意的是當檔案設定為隱藏後,就無法以寫方式打開了(系統管理員可開啟),即使設定Attributes時設定了NOMAL標籤,不懂為什麼,不過這確實才是我想要的,金鑰檔案被生成後應該需要被避免被修改。

        拖拽檔案是一個炫酷的功能(對於菜鳥來說),所以想做個出來,網上一搜大一片案例,看起來確實很簡單,總體的思路就是繼承wx.FileDropTarget類,然後處理一下初始化函式,再重寫一下OnDropFiles函式,這個函式在檔案被拖拽並放下時被呼叫,在裡面寫上對拖拽物件的處理。需要注意的是,這個繼承類一般在Frame內例項化,一般是傳給他需要接收檔案資訊的控制元件作為初始化引數,然後用控制元件的SetDropTarget函式來設定拖拽物件到指定控制元件,在這裡我直接使用主Panel作為DropTarget,路徑編輯框作為拖拽類引數。  

        MD5碼校驗的操作也算比較簡單,只需呼叫hashlib的MD5函式獲得處理類,然後用處理類的update方法匯入需要加密的bytes串,再利用其digest函式獲得MD5碼串,發現多長的bytes串都是儲存成16位的MD5碼,然後放到密文的末尾就好。 

  • 拖拽檔案 

  • MD5碼校驗

  • 解決在接收伺服器金鑰時UI無響應的情況

         這個問題之前一直沒怎麼在意,因為認為只是沒用單獨的執行緒去執行認證函式而已,然後就用Thread把他放進了一個單獨的執行緒裡,再使用了join函式讓主執行緒等待其拿到Key,結果發現介面還是會無響應,嗶了狗了,再試了試獨特的操作把join去掉看看還會不會卡,結果還卡,然後發現彈MessageBox的地方確實會卡住,然後看網上文章很多都說什麼對UI的操作要放在主執行緒裡,照做了(還單獨為彈MessageBox寫了個函式),結果還是會在接收金鑰時卡住,然後再找文章,發現了DelayedResult這個函式,據文章上所說(這個文章好長。。看了半天看不到重點很捉急,不過不得不承認寫的非常有條理),這是一個專門用來處理wxPython中的多執行緒處理的,不過不知道它的原理跟自己搞一個多執行緒有什麼區別。

        DelayedResult是wx.lib中的一個函式,引數很多,借文章的程式碼:

startWorker(consumer,
            workerFn,
            cargs=(), ckwargs={},
            wargs=(), wkwargs={},
            jobID=None,
            group=None,
            daemon=False,
            sendReturn=True,
            senderArg=None)

         其中,workerFn是需要作為獨立執行緒執行的函式;consumer是執行緒執行後執行的回撥函式,需要注意的是此函式的第一個引數會被傳入一個DelayedResult物件,所以consumer函式應該在定義時設定好,接到DelayedResult物件後可以在函式體中呼叫其.get()方法來獲取執行緒的返回值。daemon是守護執行緒(執行緒是否隨主執行緒一起結束),sendReturn就是是否chuandi返回值了,引數列表是誰的看其引數名首字母。整個函式非常簡便,充分展現了封裝性,在做這個函式時我發現之前做的倒計時執行緒沒什麼用處了,就把它的相關程式碼全刪除了。 

  • 加入頂欄選單

       沒什麼說的,略。

總結

    以上功能寫了整一天,經過這次更新,總程式碼超過了300行,也算是個有點意思的專案了吧,就是寫的程式碼愈多愈感覺程式碼缺少條理性,也就是所謂的程式設計結構,或者說其面向物件的思想沒有充分貫徹到位吧(雖然一個main裡都寫了三個類了!),不過接下來一段時間都可以鬆口氣了。