Crypto++是一个免费的加解密类库,集成了很多的加解密算法,如des, aes, rsa等基础加密算法。本文主要谈一下本人最近实现的一个密码管理器,编译环境是32位Ubuntu,主要实现了多用户系统,可以创建用户、创建完成之后将密码经过HMAC存入用户文件、用户登录后需要对用户文件进行完整性检测保证外部修改、添加删除修改查看密码记录、记录以(域名、aes加密后密码、前两者结合的HMAC)形式存入文件。
由于管理器采用终端显示设计,就是说不同的代码段会不停地被调用。如果程序设计得不好的话,容易造成函数的嵌套调用,甚至栈空间无法释放,内存泄露等问题。为了避免这个问题,使用函数指针来规划整一个程序,有点像回调函数的感觉。整个管理器在运行时维护一个函数指针,每一次的函数调用都由这个指针来指定,而且保证每一个函数都执行完毕,避免函数变量占用栈空间。
typedef void (*func)();<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
整体流程:
int main(){ printWelcome(); processor(); // run the procession return 0; }
func iter_func = main_page; // the processor interface void processor(){ while( iter_func != NULL){ (*iter_func)(); } //quit cout << "bye!\n" << endl; }
HMAC只能用来进行校验,不能用来加密,因此可以用来做密码验证的作用,类似于md5。
// check hmac of a domain with its password string check_hmac(string infor, string key){ string mac, encoder; string derived; HexDecoder decoder (new StringSink(derived)); decoder.Put((const byte*)key.data(), key.size()); decoder.MessageEnd(); try{ HMAC<SHA256> hmac((const byte*)derived.data(), derived.size()); StringSource(infor, true, new HashFilter(hmac, new StringSink(mac))); }catch(const CryptoPP::Exception& e){ cerr << e.what() << endl; exit(1); } encoder.clear(); StringSource(mac, true, new HexEncoder(new StringSink(encoder))); return encoder; //return HMAC }
AES算法有较强的安全性,可以用来做密码的加密。当需要查询密码时,可以采用解密方式解出来。
string aes_decrypt(string password, string key){ // decrypt the password string recovered; string derived; HexDecoder decoder(new StringSink(derived)); decoder.Put( (byte*)key.data(),key.size() ); decoder.MessageEnd(); string cipher; HexDecoder decoder2(new StringSink(cipher)); decoder2.Put( (byte*)password.data(), password.size() ); decoder2.MessageEnd(); try{ CFB_Mode< AES >::Decryption d; d.SetKeyWithIV((byte*)derived.data(), derived.size(),iv); StringSource s(cipher, true, new StreamTransformationFilter(d,new StringSink(recovered))); }catch(const CryptoPP::Exception& e){ cerr << e.what() << endl; exit(1); } return recovered; } string aes_encrypt(string password, string key){ //to do string cipher, encoded; string derived; HexDecoder decoder(new StringSink(derived)); decoder.Put((byte*)key.data(), key.size() ); decoder.MessageEnd(); try{ CFB_Mode< AES >::Encryption e; e.SetKeyWithIV((byte*)derived.data(), derived.size(), iv); StringSource(password, true, new StreamTransformationFilter(e, new StringSink(cipher)) ); }catch(const CryptoPP::Exception& e){ cerr << e.what() << endl; exit(1); } encoded.clear(); StringSource(cipher, true,new HexEncoder(new StringSink(encoded)) ); return encoded; }
完整代码放在https://github.com/Jreffery/PasswordManager,有兴趣的朋友可以看一下。