基于cryptopp -- A Password Manager密码管理系统

来源:互联网 发布:机智交易软件 编辑:程序博客网 时间:2024/04/29 00:48

系统设计安全目标

  • 私密性(confidentiality):消息内容不让其他人看到消息:只有该看的人才能看
  • 完整性(integrity):消息不被其他人篡改或者篡改之后可以被发现:看到的消息是正确的
  • 可用性(availability):加密后,解密仍然能够读到信息:想看随时看

基本功能

登录界面

提示用户输入用户名和master password

  • 检查文档是否存在

    • 不存在创建一个新的文档,并以输入的master password作为这个用户的master password
    • 存在则检查文档中的master password(需要先进行解密)和用户输入的是否一致,

      • 如果不一致则报错,保留在登录界面
      • 如果一致则进行完整性检查:将每一行的网站域名抽出来通过HMAC做哈希,将哈希以后的值和保存的对应哈希值最对比,如果有某一项不一致则报错,保留在登陆界面;如果一致就进入用户功能界面

用户功能界面

功能1:实现对于网站域名 + 哈希值 + 加密以后的密码的增加

  • 提示用户输入网站域名和密码
  • 检查文档中是否有相同的域名,如果有则报错;没有则将网站域名 + 通过HMAC算出的哈希值 + 加密以后的密码增加到文件尾部,并输出成功信息

功能2:实现对于网站域名 + 哈希值 + 加密以后的密码的删除

  • 提示用户输入网站域名
  • 检查文档中是否有相同的域名,如果没有则报错;有则将对应的记录从该文档中删除

功能3:实现对于输入网站域名后对于密码的查询

  • 提示用户输入网站域名
  • 检查文档中是否有相同的域名,如果没有则报错;有则将对应加密后的密码解密后输出出来

功能4:实现对于输入网站域名后对于密码的修改

  • 提示用户输入网站域名和密码
  • 检查文档中是否有相同的域名,如果没有则报错;有则将输入的密码进行加密后替换掉文档中的对应项

功能5:返回登录界面

完整代码:

#include <iostream>#include <string>#include <cstdio>#include <cstring>#include <fstream> #include <sstream>//AES#include "cryptopp563/filters.h" // StringSink, StringSource, StreamTransformationFilter#include "cryptopp563/aes.h" // AES#include "cryptopp563/modes.h" // CBC_Mode_*//PBKDF2#include "cryptopp563/base64.h" // Base64Decoder#include "cryptopp563/sha.h" // SHA1#include "cryptopp563/pwdbased.h" // PKCS5_PBKDF2_HMAC#include "cryptopp563/hex.h" // HexEncoder//HMAC#include "cryptopp563/hmac.h" // HMAC<T>using namespace std;using namespace CryptoPP;#define DEFAULT_STRING_SIZE (32)//十进制与十六进制之间相互转换string decToHex(byte num);//十进制转十六进制byte hexToDec(string num);//十六进制转十进制//CBC加密string CBC_encrypt(string str); string CBC_encrypt(byte* key, string source);//CBC解密string CBC_decrypt(string source);string CBC_decrypt(byte* key, string source);bool masterKey(string username, string password); //比对输入密码与txt密码是否一致void integrity(string username); //文件内容是否具备完整性//与key相关的哈希函数对domain进行加密string digest(string key, string domain); string deriveKey(string domain, string masterPassword);void addNewKVS(string username, string password); //增加KVSvoid deleteKVS(string username, string password); //删除KVSvoid searchPassword(string username, string password); //查询对应域名下的密码void changePassword(string username, string password); //修改对应域名下的密码int main (int argc, char const *argv[]){    string username; //用户名    string masterPassword; //密码    string filename; //用户名补充文件名     string masterPasswordInTxt;    /* 登录界面 */    while(1){        //输入用户名和密码        cout << "\nPlease input the username and password." << endl;        cin >> username >> masterPassword;        //依据用户名读取文件        filename = username + ".txt";        char *masterPasswordChar = (char*)masterPassword.data();        char *cname = (char*)filename.data();        ifstream in(cname);        if(in == NULL){            //用户不存在 新建以username命名的txt文件,储存masterPassword            cout << "Hello, new friend." <<endl;            in.close();            string passwordAfterEncrypt = CBC_encrypt(masterPasswordChar);            ofstream out(cname);            out << passwordAfterEncrypt <<endl;            out.close();            break;//新建文件完毕 跳出循环        }        else{            //用户已存在,对密码进行验证            getline(in, masterPasswordInTxt);            //cout << masterPasswordInTxt + " !"<< endl;            in.close();            if(masterKey(username, masterPassword)) {                //密码正确                cout << "Hello, " << username << "."<< endl;                integrity(username);                break;            }            else {                //密码错误                cout << "The password is wrong!" << endl;            }        }    }       /* 功能选择界面 */    int kind; // 功能类型    cout << "--------------------------------------------------------------" <<endl;    cout << "\nWelcome to Password Manager!\n" <<endl;    while(1){        cout << "--------------------------------------------------------------" <<endl;        cout << "1.Add a domain / password;" <<endl;        cout << "--------------------------------------------------------------" <<endl;        cout << "2.Remove a domain / password;" <<endl;        cout << "--------------------------------------------------------------" <<endl;        cout << "3.Check the corresponding password according to the domain;" <<endl;        cout << "--------------------------------------------------------------" <<endl;        cout << "4.Modify the corresponding password according to the domain;" <<endl;        cout << "--------------------------------------------------------------" <<endl;        cout << "5.Exit." <<endl;        cout << "--------------------------------------------------------------" <<endl;        cout << "Please input the number between 1 and 5." << endl;        cin >> kind;        while(kind < 1 || kind > 5){            cout << "Please input the right number.";            cin >> kind;        }        if(kind == 1){            addNewKVS(username, masterPassword);        }        else if(kind == 2){            deleteKVS(username, masterPassword);        }        else if(kind == 3){            searchPassword(username, masterPassword);        }        else if(kind == 4){            changePassword(username, masterPassword);        }        else{            break;        }    }    system("pause");    return 0;}string CBC_encrypt(string str) {    // 初始化密钥和初始向量    byte key[CryptoPP::AES::DEFAULT_KEYLENGTH];    byte iv[CryptoPP::AES::BLOCKSIZE];    memset(key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH);    memset(iv, 0x00, CryptoPP::AES::BLOCKSIZE);    //进行CBC加密    string ciphertext;    CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);    StreamTransformationFilter stfEncryptor(cbcEncryption, new StringSink(ciphertext));    stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str.c_str()), str.length() + 1);    stfEncryptor.MessageEnd();    // 获得加密结果    string result;    for(int i = 0; i < ciphertext.size(); i++)         result.append(decToHex(0xFF & static_cast<byte>(ciphertext[i])));    return result;}void integrity(string username) {    string masterPassword, domain, hash, password;    //打开文件    string filename;    filename = username + ".txt";    char *cname = (char*)filename.data();    ifstream in(cname);    in >> masterPassword;    //若密码长度不为default_string_size的倍数则密码不完整    if(masterPassword.size() % DEFAULT_STRING_SIZE != 0) {        cout << "Fatal error: File is modified improperly" << endl;        exit(0);    }    //循环读取所有记录    while(in >> domain >> hash >> password) {        if(password.size() % DEFAULT_STRING_SIZE != 0) {            //若密码长度不为default_string_size的倍数则密码不完整            cout << "Fatal error: File is modified improperly" << endl;            exit(0);        }        else if(strcmp(hash.c_str(), digest(deriveKey(domain, CBC_decrypt(masterPassword)), domain).c_str()) != 0) {            //若域名哈希后与储存的对应值不一样则文件不完整            cout << "Fatal error: File is modified improperly" << endl;            exit(0);        }    }    in.close();}string decToHex(byte num) {    char result[3] = {'0', '0'};    int i = 2;    while(num > 0 && i-- > 0) {        result[i] += num % 16;        if(result[i] > '9')            result[i] += ('A' - 10 - '0');        num /= 16;    }    return result;}byte hexToDec(string num) {    byte result = 0;    result += 16 * (num[0] < 'A' ? num[0] - '0' : num[0] - 'A' + 10);    result += num[1] < 'A' ? num[1] - '0' : num[1] - 'A' + 10;    return result;}bool masterKey(string username, string password) {    //打开文件    string filename;    filename = username + ".txt";    char *cname = (char*)filename.data();    ifstream in(cname);    //读取密码    string passwordInTxt;    in >> passwordInTxt;    in.close();    //对读取到的密码进行解密    string decryptMasterKey = CBC_decrypt(passwordInTxt);    //比对两个密码是否一致    if(strcmp(decryptMasterKey.c_str(), password.c_str()) == 0)        return true;    else        return false;}string CBC_encrypt(byte* key, string source) {    // IV setup    byte iv[AES::BLOCKSIZE];    memset(iv, 0x00, AES::BLOCKSIZE);    // Create Cipher Text    string ciphertext;    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 unsigned char*>(source.c_str()), source.length() + 1);    stfEncryptor.MessageEnd();    // get result    string result;    for(int i = 0; i < ciphertext.size(); i++)         result.append(decToHex(0xFF & static_cast<byte>(ciphertext[i])));    return result;}string CBC_decrypt(string source) {    // check modified    if(source.size() % DEFAULT_STRING_SIZE != 0) {        cout << "Fatal error: File is modified improperly" << endl;        exit(0);    }    // get cipher text    string cipher;    for(int i = 0; i < source.length(); i += 2)         cipher.append(1, hexToDec(source.substr(i, 2)));    // Key and IV setup    byte key[AES::DEFAULT_KEYLENGTH], iv[AES::BLOCKSIZE];    memset(key, 0x00, AES::DEFAULT_KEYLENGTH);    memset(iv, 0x00, AES::BLOCKSIZE);    // decrypt    string decryptedtext;    AES::Decryption aesDecryption(key, AES::DEFAULT_KEYLENGTH);    CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);    StreamTransformationFilter stfDecryptor(cbcDecryption, new StringSink(decryptedtext));    stfDecryptor.Put(reinterpret_cast<const unsigned char*>(cipher.c_str()), cipher.size());    stfDecryptor.MessageEnd();    return decryptedtext;}string CBC_decrypt(byte* key, string source) {    // check modified    if(source.size() % DEFAULT_STRING_SIZE != 0) {        cout << "Fatal error: File is modified improperly" << endl;        exit(0);    }    // get cipher text    string cipher;    for(int i = 0; i < source.length(); i += 2)         cipher.append(1, hexToDec(source.substr(i, 2)));    // Key and IV setup    byte iv[AES::BLOCKSIZE];    memset(iv, 0x00, AES::BLOCKSIZE);    // decrypt    string decryptedtext;    AES::Decryption aesDecryption(key, AES::DEFAULT_KEYLENGTH);    CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);    StreamTransformationFilter stfDecryptor(cbcDecryption, new StringSink(decryptedtext));    stfDecryptor.Put(reinterpret_cast<const unsigned char*>(cipher.c_str()), cipher.size());    stfDecryptor.MessageEnd();    return decryptedtext;}string digest(string key, string domain) {    byte result[AES::DEFAULT_KEYLENGTH];    HMAC<SHA >((byte *)key.c_str(), key.size()).CalculateDigest(result, (byte *)domain.c_str(), domain.size());    string value;    for(int i = 0; i < AES::DEFAULT_KEYLENGTH; i++)         value.append(decToHex(result[i]));    return value;}string deriveKey(string domain, string masterPassword) {    byte derived[AES::DEFAULT_KEYLENGTH];    PKCS5_PBKDF2_HMAC<CryptoPP::SHA1> pbkdf2;    pbkdf2.DeriveKey(derived, sizeof(derived), 0, (byte *)masterPassword.c_str(), masterPassword.size(), (byte *)domain.c_str(), domain.size(), 1);    string result;    HexEncoder encoder(new StringSink(result));    encoder.Put(derived, sizeof(derived));    encoder.MessageEnd();    return result;}void addNewKVS(string username, string password) {    //输出提示信息,提示输入需要添加的域名和密码    string domainInput, passwordInput;    cout << "Please input the domain you want to add: ";    cin >> domainInput;    cout << "Please input the new password of the domain: ";    cin >> passwordInput;    string key = deriveKey(domainInput, password);    ofstream file;    file.open((username + ".txt").c_str(), ios::out|ios::app);    //对应输出域名,哈希后的域名,加密后的密码到文件中    file << domainInput << " " << digest(key, domainInput) << " " << CBC_encrypt((byte *)key.c_str(), passwordInput) << endl;    file.close();    cout << "Success!" << endl;}void deleteKVS(string username, string password) {    //提示输入需要删除的域名    string domainInput;    cout << "Please input the domain you want to delete: ";    cin >> domainInput;    bool find = false;    string masterPassword;    vector<string> domainVector, hashVector, passwordVector; //临时存储记录    string domain, hash, pw;    //打开文件,逐条记录比对域名是否与输入的域名一致    fstream file;    file.open((username + ".txt").c_str(), ios::in);    file >> masterPassword;    while(file >> domain >> hash >> pw) {        if(strcmp(domain.c_str(), domainInput.c_str()) == 0)             //域名是否与输入的域名一致,不放入存储向量中            find = true;        else {            domainVector.push_back(domain);            hashVector.push_back(hash);            passwordVector.push_back(pw);        }    }    file.close();    file.open((username + ".txt").c_str(), ios::out|ios::trunc);    file << masterPassword << endl;    //将记录从临时存储的向量中移回文件中    for(int i = 0; i < domainVector.size(); i++)         file << domainVector[i] << " " << hashVector[i] << " " << passwordVector[i] << endl;    file.close();    if(find)         cout << "Success!" << endl;    else        cout << "Can not find the record of the domain" << endl;}void searchPassword(string username, string password) {    //提示输入需要查询的域名    string domainInput;    cout << "Please input the domain you want to search: ";    cin >> domainInput;    bool find = false;    string masterPassword;    string domain, hash, pw;    ifstream file;    file.open((username + ".txt").c_str());    file >> masterPassword;    //逐条记录比对,若域名一致则找到,将密码解密出来并输出    while(file >> domain >> hash >> pw) {        if(strcmp(domain.c_str(), domainInput.c_str()) == 0) {            find = true;            string key = deriveKey(domainInput, password);            cout << "The password of domain is: " << CBC_decrypt((byte *)key.c_str(), pw) << endl;            break;        }    }       if(!find)         cout << "Can not find the record of the domain" << endl;}void changePassword(string username, string password) {    //提示输入需要修改的域名和密码    string domainInput, passwordInput;    cout << "Please input the domain to be changed: ";    cin >> domainInput;    cout << "Please input your new password: ";    cin >> passwordInput;    bool find = false;    string masterPassword;    //转存向量    vector<string> domainVector, hashVector, passwordVector;    string domain, hash, pw;    //打开对应文件    fstream file;    file.open((username + ".txt").c_str(), ios::in);    file >> masterPassword;    //逐条进行比对,若发现域名一致的记录则将新的密码加密后存入向量    while(file >> domain >> hash >> pw) {        if(strcmp(domain.c_str(), domainInput.c_str()) == 0) {            domainVector.push_back(domain);            hashVector.push_back(hash);            string key = deriveKey(domainInput, password);            passwordVector.push_back(CBC_encrypt((byte *)key.c_str(), passwordInput));            find = true;        }        else {            domainVector.push_back(domain);            hashVector.push_back(hash);            passwordVector.push_back(pw);        }    }    file.close();    file.open((username + ".txt").c_str(), ios::out|ios::trunc);    file << masterPassword << endl;    //将在向量内临时存储的内容移回文件    for(int i = 0; i < domainVector.size(); i++)         file << domainVector[i] << " " << hashVector[i] << " " << passwordVector[i] << endl;    file.close();    if(find)         cout << "Success!" << endl;    else        cout << "Can not find the record of the domain" << endl;}
0 0
原创粉丝点击