2017-02-26 19:29:50 +01:00
|
|
|
|
#include "PasswordManager.h"
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
//#include <botan/filters.h>
|
|
|
|
|
|
//#include <botan/pipe.h>
|
|
|
|
|
|
//#include <botan/sha2_64.h>
|
|
|
|
|
|
//#include <botan/hash.h>
|
|
|
|
|
|
//#include <botan/hmac.h>
|
|
|
|
|
|
//#include <botan/pbkdf2.h>
|
|
|
|
|
|
//#include <botan/rng.h>
|
|
|
|
|
|
//#include <botan/base64.h>
|
|
|
|
|
|
//#include <botan/loadstor.h>
|
|
|
|
|
|
//#include <botan/mem_ops.h>
|
|
|
|
|
|
#include <botan/auto_rng.h>
|
2017-02-26 19:29:50 +01:00
|
|
|
|
#include <botan/base64.h>
|
2018-11-04 11:24:13 +01:00
|
|
|
|
#include <botan/psk_db_sql.h>
|
|
|
|
|
|
#include <botan/sqlite3.h>
|
|
|
|
|
|
#include <botan/scrypt.h>
|
|
|
|
|
|
#include <boost/lexical_cast.hpp>
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
Botan::secure_vector<uint8_t> PasswordManager::KeyStrengthener::derive(const std::string &passphrase)
|
|
|
|
|
|
{
|
|
|
|
|
|
Botan::secure_vector<uint8_t> master_key(m_keySize);
|
|
|
|
|
|
m_hasher->derive_key(master_key.data(), master_key.size(), passphrase.c_str(), passphrase.length(), m_salt.data(), m_salt.size());
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
return master_key;
|
|
|
|
|
|
}
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
void PasswordManager::KeyStrengthener::saveParams(std::shared_ptr<Botan::Sqlite3_Database> db, const std::string &table_name)
|
|
|
|
|
|
{
|
|
|
|
|
|
auto sc = dynamic_cast<Botan::Scrypt*>(m_hasher.get());
|
|
|
|
|
|
size_t i1 = sc->N();
|
|
|
|
|
|
size_t i2 = sc->r();
|
|
|
|
|
|
size_t i3 = sc->p();
|
|
|
|
|
|
|
|
|
|
|
|
// SAVE parameters in database
|
|
|
|
|
|
auto stmt = db->new_statement("INSERT INTO " + table_name + "(id, algo, i1, i2, i3, ks, salt) VALUES(?1, ?2, ?3, ?4, ?5)");
|
|
|
|
|
|
stmt->bind(1, 1);
|
|
|
|
|
|
stmt->bind(2, "Scrypt");
|
|
|
|
|
|
stmt->bind(3, i1);
|
|
|
|
|
|
stmt->bind(4, i2);
|
|
|
|
|
|
stmt->bind(5, i3);
|
|
|
|
|
|
stmt->bind(6, m_keySize);
|
|
|
|
|
|
stmt->bind(7, Botan::base64_encode(m_salt));
|
|
|
|
|
|
stmt->spin();
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
}
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
// -------------------------
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
void PasswordManager::openDatabase(std::shared_ptr<Botan::Sqlite3_Database> db, std::string passphrase)
|
|
|
|
|
|
{
|
|
|
|
|
|
// std::string psk_db_file_name;
|
|
|
|
|
|
// auto db = std::make_shared<Botan::Sqlite3_Database>(psk_db_file_name);
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
KeyStrengthener ks;
|
|
|
|
|
|
// if (database exists)
|
|
|
|
|
|
if (isPskStoreInitialized(db)) {
|
|
|
|
|
|
ks = getKeyStrengthener(db);
|
2017-02-26 19:29:50 +01:00
|
|
|
|
}
|
2018-11-04 11:24:13 +01:00
|
|
|
|
else {
|
|
|
|
|
|
initializeNewPskStore(db);
|
|
|
|
|
|
ks = createKeyStrengthener();
|
|
|
|
|
|
ks.saveParams(db, m_secretAlgoTableName);
|
2017-02-26 19:29:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
Botan::secure_vector<uint8_t> master_key = ks.derive(passphrase);
|
|
|
|
|
|
m_pskDatabase = std::make_unique<Botan::Encrypted_PSK_Database_SQL>(master_key, db, m_passwordTableName);
|
|
|
|
|
|
}
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
void PasswordManager::closeDatabase()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_pskDatabase.reset();
|
|
|
|
|
|
}
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
void PasswordManager::set(const std::string &id, const std::string &passwd)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_pskDatabase) {
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
|
|
|
|
|
}
|
2018-11-04 11:24:13 +01:00
|
|
|
|
else {
|
|
|
|
|
|
throw PasswordManagerLockedException();
|
|
|
|
|
|
}
|
2017-02-26 19:29:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
std::string PasswordManager::get(const std::string &id, const std::string &passwd)
|
2017-02-26 19:29:50 +01:00
|
|
|
|
{
|
2018-11-04 11:24:13 +01:00
|
|
|
|
if (m_pskDatabase) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
throw PasswordManagerLockedException();
|
2017-02-26 19:29:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
void PasswordManager::remove(const std::string &id)
|
2017-02-26 19:29:50 +01:00
|
|
|
|
{
|
2018-11-04 11:24:13 +01:00
|
|
|
|
if (m_pskDatabase) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
throw PasswordManagerLockedException();
|
2017-02-26 19:29:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
void PasswordManager::initializeNewPskStore(std::shared_ptr<Botan::Sqlite3_Database> db)
|
2017-02-26 19:29:50 +01:00
|
|
|
|
{
|
2018-11-04 11:24:13 +01:00
|
|
|
|
// Create tables
|
|
|
|
|
|
// - psk_masterkey_algo
|
|
|
|
|
|
// - psk_passwd
|
|
|
|
|
|
std::string create_statement =
|
|
|
|
|
|
"CREATE TABLE IF NOT EXISTS " + m_secretAlgoTableName + "( \n"
|
|
|
|
|
|
" id INTEGER PRIMARY KEY \n"
|
|
|
|
|
|
" algo TEXT \n"
|
|
|
|
|
|
" i1 INTEGER \n"
|
|
|
|
|
|
" i2 INTEGER \n"
|
|
|
|
|
|
" i3 INTEGER \n"
|
|
|
|
|
|
" ks INTEGER \n"
|
|
|
|
|
|
" salt TEXT \n"
|
|
|
|
|
|
");";
|
|
|
|
|
|
db->create_table(create_statement);
|
|
|
|
|
|
|
2017-02-26 19:29:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
bool PasswordManager::isPskStoreInitialized(std::shared_ptr<Botan::Sqlite3_Database> db)
|
2017-02-26 19:29:50 +01:00
|
|
|
|
{
|
2018-11-04 11:24:13 +01:00
|
|
|
|
// Is the table with the secret data present and filled?
|
|
|
|
|
|
auto stmt = db->new_statement("SELECT name FROM sqlite_master WHERE type='table' AND name=?1");
|
|
|
|
|
|
stmt->bind(1, m_secretAlgoTableName);
|
|
|
|
|
|
bool ok = stmt->step();
|
|
|
|
|
|
if (ok) {
|
|
|
|
|
|
auto stmt = db->new_statement("SELECT algo FROM " + m_secretAlgoTableName + " WHERE id=1");
|
|
|
|
|
|
return stmt->step();
|
2017-02-26 19:29:50 +01:00
|
|
|
|
}
|
2018-11-04 11:24:13 +01:00
|
|
|
|
return false;
|
2017-02-26 19:29:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
PasswordManager::KeyStrengthener PasswordManager::getKeyStrengthener(std::shared_ptr<Botan::Sqlite3_Database> db)
|
2017-02-26 19:29:50 +01:00
|
|
|
|
{
|
2018-11-04 11:24:13 +01:00
|
|
|
|
auto stmt = db->new_statement("SELECT algo, i1, i2, i3, ks, salt FROM " + m_secretAlgoTableName + " WHERE id=1");
|
|
|
|
|
|
if (stmt->step()) {
|
|
|
|
|
|
std::string algo = stmt->get_str(0);
|
|
|
|
|
|
size_t i1 = boost::lexical_cast<size_t>(stmt->get_str(1));
|
|
|
|
|
|
size_t i2 = boost::lexical_cast<size_t>(stmt->get_str(2));
|
|
|
|
|
|
size_t i3 = boost::lexical_cast<size_t>(stmt->get_str(3));
|
|
|
|
|
|
size_t ks = boost::lexical_cast<size_t>(stmt->get_str(4));
|
|
|
|
|
|
|
|
|
|
|
|
auto pwh_fam = Botan::PasswordHashFamily::create(algo);
|
|
|
|
|
|
return KeyStrengthener(
|
|
|
|
|
|
pwh_fam->from_params(i1, i2, i3),
|
|
|
|
|
|
Botan::base64_decode(stmt->get_str(5)),
|
|
|
|
|
|
ks
|
|
|
|
|
|
);
|
2017-02-26 19:29:50 +01:00
|
|
|
|
}
|
2018-11-04 11:24:13 +01:00
|
|
|
|
else {
|
2017-02-26 19:29:50 +01:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-04 11:24:13 +01:00
|
|
|
|
PasswordManager::KeyStrengthener PasswordManager::createKeyStrengthener()
|
2017-02-26 19:29:50 +01:00
|
|
|
|
{
|
2018-11-04 11:24:13 +01:00
|
|
|
|
// std::unique_ptr<Botan::PasswordHash> pwh;
|
|
|
|
|
|
|
|
|
|
|
|
size_t key_size = 64;
|
|
|
|
|
|
Botan::secure_vector<uint8_t> salt(key_size);
|
|
|
|
|
|
Botan::AutoSeeded_RNG rng;
|
|
|
|
|
|
rng.randomize(salt.data(), salt.size());
|
|
|
|
|
|
|
|
|
|
|
|
const std::string algo = "Scrypt";
|
|
|
|
|
|
auto pwh_fam = Botan::PasswordHashFamily::create(algo);
|
|
|
|
|
|
return KeyStrengthener(
|
|
|
|
|
|
pwh_fam->tune(key_size, std::chrono::seconds(2), 130),
|
|
|
|
|
|
salt,
|
|
|
|
|
|
key_size
|
|
|
|
|
|
);
|
2017-02-26 19:29:50 +01:00
|
|
|
|
}
|