From 585d084fd3a5da06e04a5c95e41733009799a20e Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 15 May 2018 20:39:12 +0200 Subject: Allow storing user without nodes --- src/DataView.cpp | 5 +++ src/Database.cpp | 14 ++++++-- src/DatabaseStorage.cpp | 96 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 92 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/DataView.cpp b/src/DataView.cpp index b9cef47..a5232f3 100644 --- a/src/DataView.cpp +++ b/src/DataView.cpp @@ -7,4 +7,9 @@ namespace odhtdb { return size == other.size && memcmp(data, other.data, size) == 0; } + + bool DataView::operator != (const DataView &other) const + { + return !operator==(other); + } } diff --git a/src/Database.cpp b/src/Database.cpp index 17773ed..874b225 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -655,12 +655,22 @@ namespace odhtdb return true; } - void Database::storeUserPasswordEncrypted(const Hash &nodeHash, const std::string &username, const std::string &password, const Signature::KeyPair &keyPair) + bool Database::doesStoredUserExist(const string &username) const + { + return databaseStorage.doesStoredUserExist(username); + } + + void Database::storeUserWithoutNodes(const string &username, const string &password) + { + return databaseStorage.storeUserWithoutNodes(username, password); + } + + void Database::storeUserPasswordEncrypted(const Hash &nodeHash, const string &username, const string &password, const Signature::KeyPair &keyPair) { return databaseStorage.storeUserPasswordEncrypted(nodeHash, username, password, keyPair); } - vector Database::getStoredUserNodeDataDecrypted(const std::string &username, const std::string &password) + vector Database::getStoredUserNodeDataDecrypted(const string &username, const string &password) { return databaseStorage.getStoredUserNodeDataDecrypted(username, password); } diff --git a/src/DatabaseStorage.cpp b/src/DatabaseStorage.cpp index 66d6d89..3140c96 100644 --- a/src/DatabaseStorage.cpp +++ b/src/DatabaseStorage.cpp @@ -115,11 +115,13 @@ namespace odhtdb "CREATE TABLE IF NOT EXISTS NodeAddDataRaw(nodeId INTEGER NOT NULL, nodeAddDataId INTEGER NOT NULL, data BLOB NOT NULL, FOREIGN KEY(nodeId) REFERENCES Node(id), FOREIGN KEY(nodeAddDataId) REFERENCES NodeAddData(id));" "CREATE TABLE IF NOT EXISTS NodeUserActionGap(id INTEGER PRIMARY KEY, nodeUserId INTEGER NOT NULL, start INTEGER NOT NULL, range INTEGER NOT NULL, FOREIGN KEY(nodeUserId) REFERENCES NodeUser(id));" - "CREATE TABLE IF NOT EXISTS NodeEncryptedUserData(node INTEGER NOT NULL, username BLOB NOT NULL, userPublicKey BLOB NOT NULL, nonce BLOB NOT NULL, userPrivateKeyEncrypted BLOB NOT NULL, FOREIGN KEY(node, userPublicKey) REFERENCES NodeUser(node, publicKey));" + + "CREATE TABLE IF NOT EXISTS NodeEncryptedUser(id INTEGER PRIMARY KEY, username BLOB UNIQUE NOT NULL, nonce BLOB NOT NULL, encryptedPassword BLOB NOT NULL);" + "CREATE TABLE IF NOT EXISTS NodeEncryptedUserData(node INTEGER NOT NULL, usernameId INTEGER NOT NULL, userPublicKey BLOB NOT NULL, nonce BLOB NOT NULL, userPrivateKeyEncrypted BLOB NOT NULL, FOREIGN KEY(usernameId) REFERENCES NodeEncryptedUser(id), FOREIGN KEY(node, userPublicKey) REFERENCES NodeUser(node, publicKey));" "CREATE UNIQUE INDEX IF NOT EXISTS UniqueUserInNode ON NodeUser(node, publicKey);" "CREATE UNIQUE INDEX IF NOT EXISTS UniqueUserGroupAssoc ON NodeUserGroupAssoc(node, userPublicKey, groupId);" - "CREATE UNIQUE INDEX IF NOT EXISTS UniqueEncryptedUserDataInNode ON NodeEncryptedUserData(node, username);"); + "CREATE UNIQUE INDEX IF NOT EXISTS UniqueEncryptedUserDataInNode ON NodeEncryptedUserData(node, usernameId);"); sqlite_prepare_checked(sqliteDb, "INSERT INTO Node(nodeHash, timestamp, creatorPublicKey, adminGroupId) VALUES(?, ?, ?, ?)", &insertNodeStmt); sqlite_prepare_checked(sqliteDb, "INSERT INTO NodeUser(node, publicKey, latestActionCounter) VALUES(?, ?, 0)", &insertUserStmt); @@ -836,47 +838,99 @@ namespace odhtdb return query.getInt64(0); } - void DatabaseStorage::storeUserPasswordEncrypted(const Hash &nodeHash, const std::string &username, const std::string &password, const Signature::KeyPair &keyPair) + bool DatabaseStorage::doesStoredUserExist(const string &username) const + { + SqlQuery query(sqliteDb, "SELECT id from NodeEncryptedUser WHERE username = ?", { DataView((void*)username.data(), username.size()) }); + return query.next(); + } + + void DatabaseStorage::storeUserWithoutNodes(const string &username, const string &password) + { + OwnedMemory hashedPassword = hashPassword(DataView((void*)password.data(), password.size()), DataView((void*)passwordSalt, PASSWORD_SALT_LEN)); + DataView hashedPasswordView(hashedPassword.data, hashedPassword.size); + DataView usernameView((void*)username.data(), username.size()); + + DataView saltView((void*)passwordSalt, PASSWORD_SALT_LEN); + Encryption encryptedPassword(saltView, {}, hashedPasswordView); + SqlExec addUserSql(sqliteDb, "INSERT INTO NodeEncryptedUser(username, nonce, encryptedPassword) VALUES(?, ?, ?)"); + addUserSql.execWithArgs({ usernameView, encryptedPassword.getNonce(), encryptedPassword.getCipherText() }); + } + + i64 DatabaseStorage::getStoredUserId(const string &username, const DataView &hashedPassword) + { + DataView usernameView((void*)username.data(), username.size()); + SqlQuery userQuery(sqliteDb, "SELECT id, nonce, encryptedPassword FROM NodeEncryptedUser WHERE username = ?", { usernameView }); + if(!userQuery.next()) + { + string errMsg = "User with name "; + errMsg += username; + errMsg += " doesn't exist in storage"; + throw DatabaseStorageNoSuchStoredUser(errMsg); + } + + i64 encryptedUserRowId = userQuery.getInt64(0); + const DataView storedEncryptedPasswordNonce = userQuery.getBlob(1); + const DataView storedEncryptedPassword = userQuery.getBlob(2); + try + { + Decryption decryptedStoredPassword(storedEncryptedPassword, storedEncryptedPasswordNonce, hashedPassword); + return encryptedUserRowId; + } + catch(DecryptionException &e) + { + throw DatabaseStorageWrongPassword(e.what()); + } + } + + void DatabaseStorage::storeUserPasswordEncrypted(const Hash &nodeHash, const string &username, const string &password, const Signature::KeyPair &keyPair) { OwnedMemory hashedPassword = hashPassword(DataView((void*)password.data(), password.size()), DataView((void*)passwordSalt, PASSWORD_SALT_LEN)); DataView hashedPasswordView(hashedPassword.data, hashedPassword.size); DataView privateKeyView((void*)keyPair.getPrivateKey().getData(), PRIVATE_KEY_NUM_BYTES); Encryption encryptedPrivateKey(privateKeyView, {}, hashedPasswordView); - SqlQuery query(sqliteDb, "SELECT nonce, userPrivateKeyEncrypted FROM NodeEncryptedUserData WHERE username = ?", - { DataView((void*)username.data(), username.size()) }); - - if(query.next()) + SqlTransaction transaction(sqliteDb); + DataView usernameView((void*)username.data(), username.size()); + SqlQuery userQuery(sqliteDb, "SELECT id, nonce, encryptedPassword FROM NodeEncryptedUser WHERE username = ?", { usernameView }); + i64 encryptedUserRowId; + try { - const DataView storedNonce = query.getBlob(0); - const DataView storedPrivateKeyEncrypted = query.getBlob(1); - try - { - Decryption decryptedStoredPrivateKey(storedPrivateKeyEncrypted, storedNonce, hashedPasswordView); - } - catch(DecryptionException &e) - { - throw DatabaseStorageWrongPassword(e.what()); - } + encryptedUserRowId = getStoredUserId(username, hashedPasswordView); + } + catch(DatabaseStorageNoSuchStoredUser &e) + { + DataView saltView((void*)passwordSalt, PASSWORD_SALT_LEN); + Encryption encryptedPassword(saltView, {}, hashedPasswordView); + + SqlExec addUserSql(sqliteDb, "INSERT INTO NodeEncryptedUser(username, nonce, encryptedPassword) VALUES(?, ?, ?)"); + addUserSql.execWithArgs({ usernameView, encryptedPassword.getNonce(), encryptedPassword.getCipherText() }); + + SqlQuery userQuery(sqliteDb, "SELECT id FROM NodeEncryptedUser WHERE username = ?", { usernameView }); + if(!userQuery.next()) + throw DatabaseStorageException("Unexpected error when retrieving stored user"); + + encryptedUserRowId = userQuery.getInt64(0); } - SqlExec sqlExec(sqliteDb, "INSERT INTO NodeEncryptedUserData(node, username, userPublicKey, nonce, userPrivateKeyEncrypted) VALUES(?, ?, ?, ?, ?)"); + SqlExec sqlExec(sqliteDb, "INSERT INTO NodeEncryptedUserData(node, usernameId, userPublicKey, nonce, userPrivateKeyEncrypted) VALUES(?, ?, ?, ?, ?)"); sqlExec.execWithArgs({ DataView(nodeHash.getData(), nodeHash.getSize()), - DataView((void*)username.data(), username.size()), + encryptedUserRowId, DataView((void*)keyPair.getPublicKey().getData(), PUBLIC_KEY_NUM_BYTES), encryptedPrivateKey.getNonce(), encryptedPrivateKey.getCipherText() }); + transaction.commit(); } - vector DatabaseStorage::getStoredUserNodeDataDecrypted(const std::string &username, const std::string &password) + vector DatabaseStorage::getStoredUserNodeDataDecrypted(const string &username, const string &password) { OwnedMemory hashedPassword = hashPassword(DataView((void*)password.data(), password.size()), DataView((void*)passwordSalt, PASSWORD_SALT_LEN)); DataView hashedPasswordView(hashedPassword.data, hashedPassword.size); + i64 encryptedUserRowId = getStoredUserId(username, hashedPasswordView); vector result; - SqlQuery query(sqliteDb, "SELECT node, userPublicKey, nonce, userPrivateKeyEncrypted FROM NodeEncryptedUserData WHERE username = ?", { DataView((void*)username.data(), username.size()) }); + SqlQuery query(sqliteDb, "SELECT node, userPublicKey, nonce, userPrivateKeyEncrypted FROM NodeEncryptedUserData WHERE usernameId = ?", { encryptedUserRowId }); while(query.next()) { Hash nodeHash; -- cgit v1.2.3