From 97c9ff702f002925dcd33869d0e22eda18390e2e Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 16 May 2018 09:47:31 +0200 Subject: Store node encryption key with user data, fix encryption bug when using additional data --- src/Database.cpp | 12 ++++++------ src/DatabaseStorage.cpp | 44 ++++++++++++++++++++++++++------------------ src/Encryption.cpp | 4 ++-- 3 files changed, 34 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/Database.cpp b/src/Database.cpp index fff74f4..df11b3c 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -90,10 +90,10 @@ namespace odhtdb } Database::Database(const char *bootstrapNodeAddr, u16 port, const boost::filesystem::path &storageDir, DatabaseCallbackFuncs callbackFuncs) : + databaseStorage(this, storageDir), onCreateNodeCallbackFunc(callbackFuncs.createNodeCallbackFunc), onAddNodeCallbackFunc(callbackFuncs.addNodeCallbackFunc), onAddUserCallbackFunc(callbackFuncs.addUserCallbackFunc), - databaseStorage(this, storageDir), shuttingDown(false) { node.run(port , { @@ -443,7 +443,7 @@ namespace odhtdb serializer.add(newActionCounter); DataView encryptionKey(nodeInfo.getNodeEncryptionKey()->data, ENCRYPTION_KEY_BYTE_SIZE); - Encryption encryptedBody(dataToAdd, DataView(), encryptionKey); + Encryption encryptedBody(dataToAdd, encryptionKey); OwnedMemory requestData = combine(serializer, encryptedBody); string signedRequestData = userToPerformActionWith.getPrivateKey().sign(requestData.getView()); OwnedMemory stagedAddObject = combine(userToPerformActionWith.getPublicKey(), signedRequestData); @@ -643,14 +643,14 @@ namespace odhtdb return databaseStorage.storeUserWithoutNodes(username, password); } - void Database::storeUserPasswordEncrypted(const Hash &nodeHash, const string &username, const string &password, const Signature::KeyPair &keyPair) + void Database::storeNodeInfoForUserEncrypted(const DatabaseNode &nodeInfo, const string &username, const string &password, const Signature::KeyPair &keyPair) { - return databaseStorage.storeUserPasswordEncrypted(nodeHash, username, password, keyPair); + return databaseStorage.storeNodeInfoForUserEncrypted(nodeInfo, username, password, keyPair); } - MapHash Database::getStoredUserNodeDataDecrypted(const string &username, const string &password) + MapHash Database::getStoredNodeUserInfoDecrypted(const string &username, const string &password) const { - return databaseStorage.getStoredUserNodeDataDecrypted(username, password); + return databaseStorage.getStoredNodeUserInfoDecrypted(username, password); } vector Database::getUserGroups(const Hash &nodeHash, const Signature::PublicKey &userPublicKey) const diff --git a/src/DatabaseStorage.cpp b/src/DatabaseStorage.cpp index 7b316f7..016c498 100644 --- a/src/DatabaseStorage.cpp +++ b/src/DatabaseStorage.cpp @@ -117,7 +117,7 @@ namespace odhtdb "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 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 TABLE IF NOT EXISTS NodeEncryptedUserData(node INTEGER NOT NULL, usernameId INTEGER NOT NULL, userPublicKey BLOB NOT NULL, nonce BLOB NOT NULL, nodeAndUserPrivateKeyEncrypted 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);" @@ -851,12 +851,12 @@ namespace odhtdb DataView usernameView((void*)username.data(), username.size()); DataView saltView((void*)passwordSalt, PASSWORD_SALT_LEN); - Encryption encryptedPassword(saltView, {}, hashedPasswordView); + 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) + i64 DatabaseStorage::getStoredUserId(const string &username, const DataView &hashedPassword) const { DataView usernameView((void*)username.data(), username.size()); SqlQuery userQuery(sqliteDb, "SELECT id, nonce, encryptedPassword FROM NodeEncryptedUser WHERE username = ?", { usernameView }); @@ -882,12 +882,16 @@ namespace odhtdb } } - void DatabaseStorage::storeUserPasswordEncrypted(const Hash &nodeHash, const string &username, const string &password, const Signature::KeyPair &keyPair) + void DatabaseStorage::storeNodeInfoForUserEncrypted(const DatabaseNode &nodeInfo, 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); + + sibs::SafeSerializer serializer; + serializer.add((const u8*)privateKeyView.data, privateKeyView.size); + serializer.add((const u8*)nodeInfo.getNodeEncryptionKey()->data, nodeInfo.getNodeEncryptionKey()->size); + Encryption encryptedNodeUserPrivateKey(DataView(serializer.getBuffer().data(), serializer.getBuffer().size()), hashedPasswordView); SqlTransaction transaction(sqliteDb); DataView usernameView((void*)username.data(), username.size()); @@ -900,7 +904,7 @@ namespace odhtdb catch(DatabaseStorageNoSuchStoredUser &e) { DataView saltView((void*)passwordSalt, PASSWORD_SALT_LEN); - Encryption encryptedPassword(saltView, {}, hashedPasswordView); + Encryption encryptedPassword(saltView, hashedPasswordView); SqlExec addUserSql(sqliteDb, "INSERT INTO NodeEncryptedUser(username, nonce, encryptedPassword) VALUES(?, ?, ?)"); addUserSql.execWithArgs({ usernameView, encryptedPassword.getNonce(), encryptedPassword.getCipherText() }); @@ -912,25 +916,25 @@ namespace odhtdb encryptedUserRowId = userQuery.getInt64(0); } - SqlExec sqlExec(sqliteDb, "INSERT INTO NodeEncryptedUserData(node, usernameId, userPublicKey, nonce, userPrivateKeyEncrypted) VALUES(?, ?, ?, ?, ?)"); + SqlExec sqlExec(sqliteDb, "INSERT INTO NodeEncryptedUserData(node, usernameId, userPublicKey, nonce, nodeAndUserPrivateKeyEncrypted) VALUES(?, ?, ?, ?, ?)"); sqlExec.execWithArgs({ - DataView(nodeHash.getData(), nodeHash.getSize()), + DataView(nodeInfo.getRequestHash()->getData(), nodeInfo.getRequestHash()->getSize()), encryptedUserRowId, DataView((void*)keyPair.getPublicKey().getData(), PUBLIC_KEY_NUM_BYTES), - encryptedPrivateKey.getNonce(), - encryptedPrivateKey.getCipherText() + encryptedNodeUserPrivateKey.getNonce(), + encryptedNodeUserPrivateKey.getCipherText() }); transaction.commit(); } - MapHash DatabaseStorage::getStoredUserNodeDataDecrypted(const string &username, const string &password) + MapHash DatabaseStorage::getStoredNodeUserInfoDecrypted(const string &username, const string &password) const { 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); - MapHash result; - SqlQuery query(sqliteDb, "SELECT node, userPublicKey, nonce, userPrivateKeyEncrypted FROM NodeEncryptedUserData WHERE usernameId = ?", { encryptedUserRowId }); + MapHash result; + SqlQuery query(sqliteDb, "SELECT node, userPublicKey, nonce, nodeAndUserPrivateKeyEncrypted FROM NodeEncryptedUserData WHERE usernameId = ?", { encryptedUserRowId }); while(query.next()) { Hash nodeHash; @@ -940,14 +944,18 @@ namespace odhtdb const DataView storedUserPublicKey = query.getBlob(1); Signature::PublicKey userPublicKey((const char*)storedUserPublicKey.data, storedUserPublicKey.size); const DataView storedNonce = query.getBlob(2); - const DataView storedPrivateKeyEncrypted = query.getBlob(3); + const DataView storedNodeUserPrivateKeyEncrypted = query.getBlob(3); try { // TODO: We can bypass decrypting several times by storing several nodes private key user the same field (as a blob) - Decryption decryptedStoredPrivateKey(storedPrivateKeyEncrypted, storedNonce, hashedPasswordView); - Signature::PrivateKey userPrivateKey((const char*)decryptedStoredPrivateKey.getDecryptedText().data, decryptedStoredPrivateKey.getDecryptedText().size); - Signature::KeyPair keyPair(userPublicKey, userPrivateKey); - result[nodeHash] = keyPair; + Decryption decryptedStoredNodeUserPrivateKey(storedNodeUserPrivateKeyEncrypted, storedNonce, hashedPasswordView); + if(decryptedStoredNodeUserPrivateKey.getDecryptedText().size != PRIVATE_KEY_NUM_BYTES + ENCRYPTION_KEY_BYTE_SIZE) + throw DatabaseStorageException("Encrypted data size is of unexpected size"); + Signature::PrivateKey userPrivateKey((const char*)decryptedStoredNodeUserPrivateKey.getDecryptedText().data, PRIVATE_KEY_NUM_BYTES); + shared_ptr keyPair = make_shared(userPublicKey, userPrivateKey); + shared_ptr nodeEncryptionKey = make_shared(new u8[ENCRYPTION_KEY_BYTE_SIZE], ENCRYPTION_KEY_BYTE_SIZE); + memcpy(nodeEncryptionKey->data, (char*)decryptedStoredNodeUserPrivateKey.getDecryptedText().data + PRIVATE_KEY_NUM_BYTES, ENCRYPTION_KEY_BYTE_SIZE); + result[nodeHash] = { nodeEncryptionKey, keyPair }; } catch(DecryptionException &e) { diff --git a/src/Encryption.cpp b/src/Encryption.cpp index ff37270..d4763b8 100644 --- a/src/Encryption.cpp +++ b/src/Encryption.cpp @@ -7,7 +7,7 @@ namespace odhtdb { static_assert(ENCRYPTION_CHECKSUM_BYTE_SIZE == crypto_aead_xchacha20poly1305_ietf_ABYTES, "Encryption checksum key size has changed for some reason, oops..."); - Encryption::Encryption(const DataView &data, const DataView &additionalData, const DataView &_key) + Encryption::Encryption(const DataView &data, const DataView &_key) { cipherTextLength = crypto_aead_xchacha20poly1305_ietf_ABYTES + data.size; cipherText = new unsigned char[cipherTextLength]; @@ -22,7 +22,7 @@ namespace odhtdb generateKey(key); randombytes_buf(nonce, ENCRYPTION_NONCE_BYTE_SIZE); - if(crypto_aead_xchacha20poly1305_ietf_encrypt(cipherText, &cipherTextLength, (const unsigned char*)data.data, data.size, (const unsigned char*)additionalData.data, additionalData.size, nullptr, nonce, key) < 0) + if(crypto_aead_xchacha20poly1305_ietf_encrypt(cipherText, &cipherTextLength, (const unsigned char*)data.data, data.size, nullptr, 0, nullptr, nonce, key) < 0) throw EncryptionException("Failed to encrypt data"); } -- cgit v1.2.3