軟件的功能描述:安全
軟件的架構圖:架構
登陸功能:
檢查用戶是否第一次使用該系統。函數
若是是,則根據用戶的密碼做爲master password,經過AES加密後存儲起來(使用的是代碼中固定的initKey和initIv),保存在相應的文件中,如Wsine.dat文件,一個用戶一個數據文件。網站
若是否,加載用戶的數據,對於master password進行AES解密操做(使用的是代碼中固定的initKey和initIv),與登錄密碼相比較,判斷是否登錄成功。編碼
完整性檢查:
當用戶登陸成功的時候,加載用戶保存的域名密鑰對,對於每一個域名計算它的哈希值(使用的是master password擴展後的key),與記錄的哈希值進行比較,若是有任一不匹配,則說明文件被人爲修改過,完整性被破壞。不然爲完整文件。加密
插入鍵值對:
登錄成功的狀況下,查找該域名是否已經存儲。
若是否,對master password經過pbkdf2放縮至16位(使用的pwd是initKey),計算域名的哈希值(使用的是master password擴展後的key),將網站密碼進行AES加密(使用的是master password擴展後的key和代碼中固定的initIv),加密後添加到用戶數據中。
若是是,提示域名密碼對已存在。命令行
刪除鍵值對:
登錄成功的狀況下,查找該域名是否已經存儲。code
若是是,將該域名對移除。orm
若是否,提示域名密碼對不存在。blog
查詢鍵值對:
登錄成功的前提下,查找該域名是否已經存儲。
若是是,對master password經過pbkdf2放縮至16位(使用的pwd是initKey),將網站密碼進行AES解密(使用的是master password擴展後的key和代碼中固定的initIv),解密後返回給用戶。
若是否,提示域名密碼對不存在。
修改鍵值對:
登錄成功的前提下,查找該域名是否已經存儲。
若是是,對master password經過pbkdf2放縮至16位(使用的pwd是initKey),將新的網站密碼進行AES加密(使用的是master password擴展後的key和代碼中固定的initIv),替換掉原來的網站密碼。
若是否,提示域名密碼對不存在。
IO操做:
因爲使用到了文件存儲,所以須要進行IO操做,AES加密後的結果有不可輸出的字符存在,所以所有的保存到文件中的hash值和password值都使用16進制數來保存,加載的時候須要對其進行從新編碼。
該軟件的實現方式遵循UNIX的命令行準則,使用get_opt()接口來進行命令行參數解析,使用assert進行參數檢查,使用try catch進行運行時檢查。
對於實驗中使用到的密碼管理的接口,都封裝到了PasswordManagerHelper類中。
類圖一覽:
重要參數解析:
AES加密函數:
string PasswordManagerHelper::AESCBCEncrypt(const string& plaintext, const byte *key, const byte *iv) { string ciphertext; try { AES::Encryption aesEncryption(key, AES::DEFAULT_KEYLENGTH); CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv); StreamTransformationFilter stfEncryptor(cbcEncryption, new StringSink(ciphertext)); stfEncryptor.Put(reinterpret_cast<const byte*>(plaintext.c_str()), plaintext.length() + 1); stfEncryptor.MessageEnd(); } catch (const CryptoPP::Exception& e) { cerr << e.what() << endl; exit(1); } return ciphertext; }
該函數對原文進行加密操做,須要傳入一個key和一個initialization vector,使用的塊加密模式是CBC模式。
AES解密函數:
string PasswordManagerHelper::AESCBCDecrypt(const string& ciphertext, const byte *key, const byte *iv) { string plaintext; try { AES::Decryption aesDecryption(key, AES::DEFAULT_KEYLENGTH); CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv); StreamTransformationFilter stfDecryptor(cbcDecryption, new StringSink(plaintext)); stfDecryptor.Put(reinterpret_cast<const byte*>(ciphertext.c_str()), ciphertext.size()); stfDecryptor.MessageEnd(); } catch (const CryptoPP::Exception& e) { cerr << e.what() << endl; exit(1); } return plaintext; }
該函數是對密文進行解密操做,須要傳入一個key和一個initialization vector,使用的塊解密模式是CBC。
擴展key函數:
string PasswordManagerHelper::expandKey(const string& key, const string& pwd) { string decoderPwd, decoderIv, result; try { Base64Decoder decoder1(new StringSink(decoderPwd)); decoder1.Put((const byte*)pwd.data(), pwd.size()); decoder1.MessageEnd(); Base64Decoder decoder2(new StringSink(decoderIv)); decoder2.Put((const byte*)key.data(), key.size()); decoder2.MessageEnd(); int c = 100; byte derived[8]; PKCS5_PBKDF2_HMAC<CryptoPP::SHA1> pbkdf2; pbkdf2.DeriveKey(derived, sizeof(derived), 0, (byte*)decoderPwd.data(), decoderPwd.size(), (byte*)decoderIv.data(), decoderIv.size(), c); HexEncoder encoder(new StringSink(result)); encoder.Put(derived, sizeof(derived)); encoder.MessageEnd(); } catch (const CryptoPP::Exception& e) { cerr << e.what() << endl; exit(1); } return result; }
該函數使用pbkdf2進行擴展,這裏須要一個pwd進行擴展,使用的方式是SHA1,雖然比較短可是截止到我作實驗爲止世界上尚未人破解,那麼久認爲它是安全的。在本次實驗選擇使用initKey來擴展,返回值是擴展後的結果,對輸入的值進行了解碼和從新編碼,選擇使用16進制。
Hash函數:
string PasswordManagerHelper::hash(const string& message, const string& key) { string mac, encoded; try { HMAC<SHA1> hmac((byte*)key.c_str(), key.length()); StringSource(message, true, new HashFilter(hmac, new StringSink(mac))); encoded.clear(); StringSource(mac, true, new Base64Encoder(new StringSink(encoded))); } catch (const CryptoPP::Exception& e) { cerr << e.what() << endl; exit(1); } return encoded; }
該函數經過hmac一個使用了key的hash函數進行哈希計算,輸出的值通過從新編碼後再返回。
查看一下軟件的版本和使用方法
這裏列出的該軟件所有的使用方法和版辦號,目前的版本號比較低,推出以後版本號會變成1.0正式版
新用戶登陸
新用戶登陸,新建一個數據文件用戶存儲,新用戶與否取決因而否有用戶數據。用戶數據的首行存儲的是用戶名和通過AES加密後的16進制用戶密碼
嘗試錯誤密碼:
說明了100分纔是該用戶的正確登錄密碼,0分是不行的。
添加域名和密碼:
添加鍵值對,存儲的格式是域名,哈希值的16進制,網站密碼通過AES加密的16進制形式
嘗試重複添加相同的域名:
由於已經存儲過了,因此會提示已存在
刪除域名密碼對:
查看本來就有的用戶數據,而後刪除其中一條,而後再從新查看,發現刪除成功。
嘗試刪除不存在的域名:
對於不存在的域名,沒法刪除,提示不存在
查詢指定域名的密碼:
成功查詢到記錄的密碼
查詢不存在的域名:
查詢失敗。好想買一個.com域名
修改指定域名的密碼:
對比先後兩次能夠發現,指定域名的存儲密碼已經改變
修改不存在的域名:
會提示修改失敗,域名不存在
人爲修改用戶數據:
先手動修改一下數據,而後登錄系統會提示數據已經被修改過,可能已經不安全了,再也不讀取這份文件,保證了完整性。
密性指的是密碼的安全不能暴露在文本中,須要通過加密後存儲。完整性指的是加密後的數據不能被別人修改過,須要驗證這一點藉助了哈希函數的幫忙
使用了Crytopp來進行加密和解密的操做,基本上都是使用庫函數操做,可是私密性和完整性在上述的說明已經很好地體現了。
使用了UNIX的CLI標準這點是比較高興的。
傳送門:下載