From cd4ff393e72331195687c1223aaaa432be3e5d0e Mon Sep 17 00:00:00 2001 From: dec05eba <0xdec05eba@gmail.com> Date: Fri, 27 Apr 2018 04:15:33 +0200 Subject: Add local user storage function (locally stored encrypted user private key) --- src/Database.cpp | 9 ++-- src/DatabaseStorage.cpp | 125 ++++++++++++++++++++++++--------------------- src/Encryption.cpp | 4 +- src/LocalUser.cpp | 5 +- src/LocalUserEncrypted.cpp | 6 +-- src/PasswordHash.cpp | 7 ++- 6 files changed, 81 insertions(+), 75 deletions(-) (limited to 'src') diff --git a/src/Database.cpp b/src/Database.cpp index d4ae190..9b01f72 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -127,10 +127,7 @@ namespace odhtdb } timestampSynced = false; }); - - // TODO: Catch std::system_error instead of this if-statement - if(ntpThread->joinable()) - ntpThread->detach(); + ntpThread->detach(); } } @@ -235,13 +232,13 @@ namespace odhtdb //node.listen(ADD_DATA_HASH, bind(&Database::listenAddData, this, _1)); } - unique_ptr Database::create(const string &ownerName, const std::string &ownerPlainPassword, const string &nodeName) + unique_ptr Database::create(const string &ownerName, const string &nodeName) { // TODO: Should this be declared static? is there any difference in behavior/performance? boost::uuids::random_generator uuidGen; auto adminGroupId = uuidGen(); auto adminGroup = new Group("administrator", adminGroupId.data, ADMIN_PERMISSION); - LocalUser *nodeAdminUser = LocalUser::create(Signature::KeyPair(), ownerName, adminGroup, ownerPlainPassword); + LocalUser *nodeAdminUser = LocalUser::create(Signature::KeyPair(), ownerName, adminGroup); // Header sibs::SafeSerializer serializer; diff --git a/src/DatabaseStorage.cpp b/src/DatabaseStorage.cpp index c507f02..7ce4919 100644 --- a/src/DatabaseStorage.cpp +++ b/src/DatabaseStorage.cpp @@ -43,7 +43,8 @@ namespace odhtdb groupsFilePath(storagePath / "groups"), usersFilePath(storagePath / "users"), dataFilePath(storagePath / "data"), - metadataFilePath(storagePath / "metadata") + metadataFilePath(storagePath / "metadata"), + localUsersFilePath(storagePath / "local_users") { boost::filesystem::create_directories(storagePath); @@ -55,11 +56,12 @@ namespace odhtdb loadGroupsFromFile(); loadUsersFromFile(); loadDataFromFile(); + loadLocalUsersFromFile(); //loadQuarantineFromFile(); } catch(FileException &e) { - Log::warn("Failed to load data from file: %s, reason: %s. Ignoring...", dataFilePath.string().c_str(), e.what()); + Log::warn("Failed to load storage data, reason: %s. Ignoring...", e.what()); if(!metadataLoaded) { sibs::SafeSerializer metadataSerializer; @@ -136,11 +138,11 @@ namespace odhtdb Hash nodeHash; deserializer.extract((u8*)nodeHash.getData(), HASH_BYTE_SIZE); - Signature::MapPublicKey *publicKeyUserDataMap = nullptr; + Signature::MapPublicKey *publicKeyUserDataMap = nullptr; auto publicKeyUserDataMapIt = nodePublicKeyUserDataMap.find(nodeHash); if(publicKeyUserDataMapIt == nodePublicKeyUserDataMap.end()) { - publicKeyUserDataMap = new Signature::MapPublicKey(); + publicKeyUserDataMap = new Signature::MapPublicKey(); nodePublicKeyUserDataMap[nodeHash] = publicKeyUserDataMap; } else @@ -156,8 +158,6 @@ namespace odhtdb else groupByIdMap = groupByIdMapIt->second; - User::Type userType = deserializer.extract(); - u8 usernameSize = deserializer.extract(); string username; username.resize(usernameSize); @@ -167,18 +167,7 @@ namespace odhtdb deserializer.extract(userPublicKeyRaw, PUBLIC_KEY_NUM_BYTES); Signature::PublicKey userPublicKey((const char*)userPublicKeyRaw, PUBLIC_KEY_NUM_BYTES); - UserData *userData = new UserData(); - if(userType == User::Type::LOCAL) - { - EncryptedPrivateKey encryptedPrivateKey; - deserializer.extract(encryptedPrivateKey.nonce, ENCRYPTION_NONCE_BYTE_SIZE); - deserializer.extract(encryptedPrivateKey.encryptedPrivateKey, 16 + PRIVATE_KEY_NUM_BYTES); - userData->user = LocalUserEncrypted::create(userPublicKey, encryptedPrivateKey, username, nullptr); - } - else - { - userData->user = RemoteUser::create(userPublicKey, username, nullptr); - } + User *user = RemoteUser::create(userPublicKey, username, nullptr); u8 numGroups = deserializer.extract(); for(int i = 0; i < numGroups; ++i) @@ -194,10 +183,10 @@ namespace odhtdb errMsg += " does not exist"; throw DatabaseStorageCorrupt(errMsg); } - userData->user->addToGroup(groupIt->second); + user->addToGroup(groupIt->second); } - (*publicKeyUserDataMap)[userData->user->getPublicKey()] = userData; + (*publicKeyUserDataMap)[user->getPublicKey()] = user; } } @@ -295,6 +284,32 @@ namespace odhtdb } } + void DatabaseStorage::loadLocalUsersFromFile() + { + if(!boost::filesystem::exists(localUsersFilePath)) return; + + OwnedMemory localUsersFileContent = fileGetContent(localUsersFilePath); + sibs::SafeDeserializer deserializer((u8*)localUsersFileContent.data, localUsersFileContent.size); + + while(!deserializer.empty()) + { + u8 usernameSize = deserializer.extract(); + string username; + username.resize(usernameSize); + deserializer.extract((u8*)&username[0], usernameSize); + + u8 userPublicKeyRaw[PUBLIC_KEY_NUM_BYTES]; + deserializer.extract(userPublicKeyRaw, PUBLIC_KEY_NUM_BYTES); + Signature::PublicKey userPublicKey((const char*)userPublicKeyRaw, PUBLIC_KEY_NUM_BYTES); + + EncryptedPrivateKey encryptedPrivateKey; + deserializer.extract(encryptedPrivateKey.nonce, ENCRYPTION_NONCE_BYTE_SIZE); + deserializer.extract(encryptedPrivateKey.encryptedPrivateKey, ENCRYPTION_CHECKSUM_BYTE_SIZE + PRIVATE_KEY_NUM_BYTES); + + nameLocalUsersMap[username] = LocalUserEncrypted::create(userPublicKey, encryptedPrivateKey, username); + } + } + void DatabaseStorage::loadMetadataFromFile() { OwnedMemory metadataFileContent = fileGetContent(metadataFilePath); @@ -449,11 +464,11 @@ namespace odhtdb bool DatabaseStorage::addUser(const Hash &nodeHash, User *user) { - Signature::MapPublicKey *publicKeyUserDataMap = nullptr; + Signature::MapPublicKey *publicKeyUserDataMap = nullptr; auto publicKeyUserDataMapIt = nodePublicKeyUserDataMap.find(nodeHash); if(publicKeyUserDataMapIt == nodePublicKeyUserDataMap.end()) { - publicKeyUserDataMap = new Signature::MapPublicKey(); + publicKeyUserDataMap = new Signature::MapPublicKey(); nodePublicKeyUserDataMap[nodeHash] = publicKeyUserDataMap; } else @@ -462,20 +477,7 @@ namespace odhtdb if(publicKeyUserDataMap->find(user->getPublicKey()) != publicKeyUserDataMap->end()) return false; - UserData *userData = new UserData(); - userData->user = user; - if(user->getType() == User::Type::LOCAL) - { - LocalUser *localUser = static_cast(user); - //DataView plainPassword((void*)localUser->getPlainPassword().data(), localUser->getPlainPassword().size()); - OwnedMemory hashedPassword = hashPassword(DataView((void*)localUser->getPlainPassword().data(), localUser->getPlainPassword().size()), DataView(passwordSalt, PASSWORD_SALT_LEN)); - memcpy(userData->hashedPassword, hashedPassword.data, hashedPassword.size); - } - else - { - memset(userData->hashedPassword, 0, HASHED_PASSWORD_LEN); - } - (*publicKeyUserDataMap)[user->getPublicKey()] = userData; + (*publicKeyUserDataMap)[user->getPublicKey()] = user; // TODO: Instead of directly saving user to file, maybe user should be added to buffer and then save to file after we have several users (performance improvement) @@ -483,23 +485,10 @@ namespace odhtdb serializer.add((u8*)nodeHash.getData(), HASH_BYTE_SIZE); - serializer.add(user->getType()); - serializer.add((u8)user->getName().size()); serializer.add((u8*)user->getName().data(), user->getName().size()); serializer.add((u8*)user->getPublicKey().getData(), PUBLIC_KEY_NUM_BYTES); - if(user->getType() == User::Type::LOCAL) - { - LocalUser *localUser = static_cast(user); - static_assert(HASHED_PASSWORD_LEN == ENCRYPTION_KEY_BYTE_SIZE, "Encryption key size has changed but hashed password size hasn't"); - Encryption encryptedPrivateKey(DataView((void*)localUser->getPrivateKey().getData(), localUser->getPrivateKey().getSize()), - DataView(), - DataView(userData->hashedPassword, HASHED_PASSWORD_LEN)); - serializer.add((u8*)encryptedPrivateKey.getNonce().data, ENCRYPTION_NONCE_BYTE_SIZE); - assert(16 + PRIVATE_KEY_NUM_BYTES == encryptedPrivateKey.getCipherText().size); - serializer.add((u8*)encryptedPrivateKey.getCipherText().data, encryptedPrivateKey.getCipherText().size); - } serializer.add((u8)user->getGroups().size()); for(Group *group : user->getGroups()) @@ -520,7 +509,7 @@ namespace odhtdb return nullptr; } - Group* DatabaseStorage::getGroupById(const Hash &nodeHash, uint8_t groupId[GROUP_ID_LENGTH]) + Group* DatabaseStorage::getGroupById(const Hash &nodeHash, uint8_t groupId[GROUP_ID_LENGTH]) const { auto groupByIdMapIt = nodeGroupByIdMap.find(nodeHash); if(groupByIdMapIt != nodeGroupByIdMap.end()) @@ -532,24 +521,46 @@ namespace odhtdb return nullptr; } - User* DatabaseStorage::getUserByPublicKey(const Hash &nodeHash, Signature::PublicKey &userPublicKey) + User* DatabaseStorage::getUserByPublicKey(const Hash &nodeHash, const Signature::PublicKey &userPublicKey) const { auto publicKeyUserDataMapIt = nodePublicKeyUserDataMap.find(nodeHash); if(publicKeyUserDataMapIt != nodePublicKeyUserDataMap.end()) { auto it = publicKeyUserDataMapIt->second->find(userPublicKey); if(it != publicKeyUserDataMapIt->second->end()) - return it->second->user; + return it->second; } return nullptr; } - const Signature::MapPublicKey* DatabaseStorage::getUsersData(const Hash &nodeHash) const + bool DatabaseStorage::storeLocalUser(const string &username, const Signature::PublicKey &publicKey, const Signature::PrivateKey &privateKey, const string &password) { - auto publicKeyUserDataMapIt = nodePublicKeyUserDataMap.find(nodeHash); - if(publicKeyUserDataMapIt != nodePublicKeyUserDataMap.end()) - return publicKeyUserDataMapIt->second; - return nullptr; + auto it = nameLocalUsersMap.find(username); + if(it != nameLocalUsersMap.end()) + return false; + + OwnedMemory hashedPassword = hashPassword(DataView((void*)password.data(), password.size()), DataView((void*)passwordSalt, PASSWORD_SALT_LEN)); + DataView privateKeyView((void*)privateKey.getData(), PRIVATE_KEY_NUM_BYTES); + DataView hashedPasswordView(hashedPassword.data, hashedPassword.size); + Encryption encryptedPrivateKey(privateKeyView, {}, hashedPasswordView); + + EncryptedPrivateKey userEncryptedPrivateKey; + memcpy(userEncryptedPrivateKey.nonce, encryptedPrivateKey.getNonce().data, ENCRYPTION_NONCE_BYTE_SIZE); + assert(sizeof(userEncryptedPrivateKey.encryptedPrivateKey) == encryptedPrivateKey.getCipherText().size); + memcpy(userEncryptedPrivateKey.encryptedPrivateKey, encryptedPrivateKey.getCipherText().data, encryptedPrivateKey.getCipherText().size); + + LocalUserEncrypted *localUserEncrypted = LocalUserEncrypted::create(publicKey, userEncryptedPrivateKey, username); + nameLocalUsersMap[username] = localUserEncrypted; + + sibs::SafeSerializer serializer; + serializer.add((u8)username.size()); + serializer.add((const u8*)username.data(), username.size()); + serializer.add((const u8*)publicKey.getData(), PUBLIC_KEY_NUM_BYTES); + serializer.add((const u8*)encryptedPrivateKey.getNonce().data, ENCRYPTION_NONCE_BYTE_SIZE); + serializer.add((const u8*)encryptedPrivateKey.getCipherText().data, ENCRYPTION_CHECKSUM_BYTE_SIZE + PRIVATE_KEY_NUM_BYTES); + + fileAppend(localUsersFilePath, DataView(serializer.getBuffer().data(), serializer.getBuffer().size())); + return true; } const dht::crypto::Identity& DatabaseStorage::getIdentity() const diff --git a/src/Encryption.cpp b/src/Encryption.cpp index e67c719..1d6bfc0 100644 --- a/src/Encryption.cpp +++ b/src/Encryption.cpp @@ -7,8 +7,8 @@ namespace odhtdb { Encryption::Encryption(const DataView &data, const DataView &additionalData, const DataView &_key) { - cipherText = new unsigned char[crypto_aead_xchacha20poly1305_ietf_ABYTES + data.size]; cipherTextLength = crypto_aead_xchacha20poly1305_ietf_ABYTES + data.size; + cipherText = new unsigned char[cipherTextLength]; if(_key.data) { @@ -46,8 +46,8 @@ namespace odhtdb Decryption::Decryption(const DataView &data, const DataView &nonce, const DataView &key) { - decryptedText = new unsigned char[data.size]; decryptedTextLength = data.size; + decryptedText = new unsigned char[decryptedTextLength]; if(nonce.size < ENCRYPTION_NONCE_BYTE_SIZE) throw DecryptionException("Nonce is not big enough"); diff --git a/src/LocalUser.cpp b/src/LocalUser.cpp index 660d09a..665f05d 100644 --- a/src/LocalUser.cpp +++ b/src/LocalUser.cpp @@ -2,10 +2,9 @@ namespace odhtdb { - LocalUser::LocalUser(const Signature::KeyPair &_keyPair, const std::string &name, Group *group, const std::string &_plainPassword) : + LocalUser::LocalUser(const Signature::KeyPair &_keyPair, const std::string &name, Group *group) : User(User::Type::LOCAL, name, group), - keyPair(_keyPair), - plainPassword(_plainPassword) + keyPair(_keyPair) { } diff --git a/src/LocalUserEncrypted.cpp b/src/LocalUserEncrypted.cpp index 1c22488..a414c89 100644 --- a/src/LocalUserEncrypted.cpp +++ b/src/LocalUserEncrypted.cpp @@ -7,19 +7,19 @@ namespace odhtdb EncryptedPrivateKey::EncryptedPrivateKey() { memset(nonce, 0, ENCRYPTION_NONCE_BYTE_SIZE); - memset(encryptedPrivateKey, 0, 16 + PRIVATE_KEY_NUM_BYTES); + memset(encryptedPrivateKey, 0, ENCRYPTION_CHECKSUM_BYTE_SIZE + PRIVATE_KEY_NUM_BYTES); } EncryptedPrivateKey::EncryptedPrivateKey(const EncryptedPrivateKey &other) { memcpy(nonce, other.nonce, ENCRYPTION_NONCE_BYTE_SIZE); - memcpy(encryptedPrivateKey, other.encryptedPrivateKey, 16 + PRIVATE_KEY_NUM_BYTES); + memcpy(encryptedPrivateKey, other.encryptedPrivateKey, ENCRYPTION_CHECKSUM_BYTE_SIZE + PRIVATE_KEY_NUM_BYTES); } Signature::PrivateKey EncryptedPrivateKey::decrypt(const DataView &plainPassword, const DataView &salt) const { OwnedMemory hashedPassword = hashPassword(plainPassword, salt); - Decryption decryptedPrivateKey(DataView((void*)encryptedPrivateKey, 16 + PRIVATE_KEY_NUM_BYTES), + Decryption decryptedPrivateKey(DataView((void*)encryptedPrivateKey, ENCRYPTION_CHECKSUM_BYTE_SIZE + PRIVATE_KEY_NUM_BYTES), DataView((void*)nonce, ENCRYPTION_NONCE_BYTE_SIZE), DataView(hashedPassword.data, hashedPassword.size)); return { (const char*)decryptedPrivateKey.getDecryptedText().data, decryptedPrivateKey.getDecryptedText().size }; diff --git a/src/PasswordHash.cpp b/src/PasswordHash.cpp index f6d3713..329733b 100644 --- a/src/PasswordHash.cpp +++ b/src/PasswordHash.cpp @@ -10,12 +10,11 @@ namespace odhtdb const uint32_t tCost = 2; const uint32_t mCost = 1 << 16; const uint32_t parallelism = 1; - const uint32_t HASHLEN = 32; - result.data = new uint8_t[HASHLEN]; - result.size = HASHLEN; + result.data = new uint8_t[HASH_PASSWORD_LENGTH]; + result.size = HASH_PASSWORD_LENGTH; - if(argon2i_hash_raw(tCost, mCost, parallelism, plainPassword.data, plainPassword.size, salt.data, salt.size, result.data, HASHLEN) != ARGON2_OK) + if(argon2i_hash_raw(tCost, mCost, parallelism, plainPassword.data, plainPassword.size, salt.data, salt.size, result.data, HASH_PASSWORD_LENGTH) != ARGON2_OK) throw std::runtime_error("Failed to hash password"); return result; -- cgit v1.2.3