Windows DPAPI 資料加密保護介面詳解

2021-08-16 21:48:36 字數 4235 閱讀 6811

dpapi是windows系統級對資料進行加解密的一種介面,無需自實現加解密**,微軟已經提供了經過驗證的高質量加解密演算法,提供了使用者態的介面,對金鑰的推導,儲存,資料加解密實現透明,並提供較高的安全保證。

dpapi提供了兩個使用者態介面,`cryptprotectdata`加密資料,`cryptunprotectdata`解密資料,加密後的資料由應用程式負責安全儲存,應用無需解析加密後的資料格式。但是,加密後的資料儲存需要一定的機制,因為該資料可以被其他任何程序用來解密,當然`cryptprotectdata`也提供了使用者輸入額外`資料`來參與對使用者資料進行加密的引數,但依然無法放於暴力破解。

總體來說,程式可以使用dpapi來對自己敏感的資料進行加解密,也可持久化儲存,程式或系統重啟後可解密密文獲取原文。如果應用程式,對此敏感資料只是暫存於記憶體,為了防止被黑客dump記憶體後進行破解,也對此資料無需進行持久化儲存,微軟還提供了加解密記憶體的介面`cryptprotectmemory`和`cryptunprotectmemory`。加解密記憶體的介面,並可指定`flag`對此記憶體加解密的宣告週期做控制,詳細見`memory加密及優缺點`章節。

dpapi使用的會話金鑰由masterkey和隨機數的hash推導產生,而masterkey的保護由使用者登入密碼hash,隨機數,和迭代次數通過可靠的[pbkdf2](金鑰推導演算法生成。其中迭代次數可以修改, `masterkeyiterationcount` 儲存在 `hkey_local_machine\software\microsoft\cryptography\protect\providers\guid` 允許系統管理員增加此迭代計數的金鑰中。但是,它不能減少到4000以下。  

為了防止篡改masterkey,它使用hmac進行雜湊。dpapi再次使用sha-1作為hmac和使用者的密碼來派生hmac金鑰。然後使用來自上面的密碼派生加密金鑰和triple-des來加密masterkey和masterkey的hmac。salt和迭代計數都是非秘密值,因此與加密的masterkey一起儲存,但未加密。這允許dpapi在給定使用者密碼的情況下輕鬆解密masterkey。

如上圖所示,會話金鑰的推導使用了masterkey,隨機數,和可選的系統登入密碼,使用者密碼推導生成。16位元組的隨機數,會以明文的形式儲存於加密後的blob中,masterkey是受推導的加密金鑰保護。

恢復金鑰是在使用者選擇從使用者的控制面板建立密碼重置磁碟(prd)時生成的。首先,dpapi生成乙個2048位rsa公鑰/私鑰對,它是恢復金鑰。然後使用公鑰將當前密碼加密並儲存在使用者的配置檔案中,同時將私鑰儲存到prd,prd實際上可以是任何可移動**,然後從記憶體中移除。私鑰只儲存在prd中,而其他任何地方都不存在,所以使用者將prd儲存在安全的地方非常重要。

如果使用者輸入錯誤的密碼,windows會詢問他們是否想要使用prd並重置密碼。如果他們選擇,執行嚮導會提示輸入新密碼,並使用prd上的私鑰解密舊密碼並進行更改。

data_blob datain;

data_blob dataout;

data_blob blobkey;

datain.pbdata = const_cast(cbdatain); //明文資料

datain.cbdata = nlen; //明文資料長度

if(key)

cryptprotect_promptstruct promp; //是否與使用者互動輸入可選的使用者密碼

promp.cbsize = sizeof(cryptprotect_promptstruct);

promp.szprompt = l"測試加密";

promp.dwpromptflags = cryptprotect_prompt_on_protect;

if(!cryptprotectdata(&datain, l"敏感資料", key ? &blobkey:null, null, &promp, 0, &dataout))

return false;

*enclen = dataout.cbdata;            //返回密文資料長度

*encdata = malloc(dataout.cbdata);   

memcpy(*encdata, dataout.pbdata, dataout.cbdata); //加密後資料

localfree(dataout.pbdata);

data_blob datain;

data_blob dataout;

data_blob blobkey;

lpwstr pdescrout = null;

if(key)

datain.pbdata = (byte *)const_cast(encdata); //待解密資料

cryptprotect_promptstruct promp; //是否與使用者互動輸入可選的使用者密碼

promp.cbsize = sizeof(cryptprotect_promptstruct);

datain.cbdata = enclen; //待解密資料長度

cryptprotect_promptstruct promp; //是否與使用者互動輸入可選的使用者密碼

promp.cbsize = sizeof(cryptprotect_promptstruct);

promp.szprompt = l"測試解密";

promp.dwpromptflags = cryptprotect_prompt_on_unprotect;

if (!cryptunprotectdata(&datain, &pdescrout, key ? &blobkey:null, null, &promp, 0, &dataout))

return false;

*nlen = dataout.cbdata;

*cbdatain = malloc(dataout.cbdata);

memcpy(*cbdatain, dataout.pbdata, dataout.cbdata); //解密後的資料明文

localfree(dataout.pbdata);

- 加密前提示設定加密等級

- 加密等級分類

- 加密等級設定為高時輸入使用者密碼

- 解密時要求輸入使用者密碼

- 輸入錯誤的使用者密碼提示

memory加解密微軟也提供了兩個介面,cryptprotectmemory記憶體加密,cryptunprotectmemory記憶體解密。一般用於即時加解密使用者敏感的資料,如使用者密碼等。記憶體加解密用於防止他人在您的程序檢視敏感資訊,如黑客遠端dump你的程序記憶體,分析和破解你的敏感資料。

通常,您使用cryptprotectmemory函式來加密您的程序正在執行時將要解密的敏感資訊。請勿使用此功能儲存稍後要解密的資料; 如果計算機重新啟動,您將無法解密資料。要將加密資料儲存到檔案以便稍後解密,請使用cryptprotectdata函式。

加解密提供了三種標誌

flag

說明cryptprotectmemory_same_process

只能在當前程序內加解密,程序重新執行會無法解密

cryptprotectmemory_cross_process

可以跨進行加解密,系統重啟後失效

cryptprotectmemory_same_logon

使用相同的登入憑據來加密和解密不同程序中的記憶體,系統重啟後失效

如果需要持儲存密文資料,可選用dpapi的介面。如果臨時快取下敏感資料,可選用對`memory`加解密的介面。

還有乙個致命的缺陷:最低系統版本要求vista及以上系統版本,所以win xp不支援該介面。

mysql資料庫加索引 mysql資料庫加索引

新增普通索引 alter table cmf cz czfjbxx add index index xz xz alter table cmf cz czfjbxx add index index zzyt zzyt alter table cmf cz czrxx add index index ...

SQLCipher android 資料庫加密

專案中引入了sqlcipher之後,會讓你的程式體積驟然增加,打成apk後大概會變大好幾m,是更側重於檔案大小,還是更側重於程式安全,你應該根據具體的需求做出合適的判斷。manifest 配置寫入檔案許可權 因為copy的資料庫檔案到建立的目錄下 module 下的build.gradle comp...

SQLCipher android 資料庫加密

專案中引入了sqlcipher之後,會讓你的程式體積驟然增加,打成apk後大概會變大好幾m,是更側重於檔案大小,還是更側重於程式安全,你應該根據具體的需求做出合適的判斷。manifest 配置寫入檔案許可權 因為copy的資料庫檔案到建立的目錄下 module 下的build.gradle comp...