aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksi Lindeman <0xdec05eba@gmail.com>2018-03-09 10:26:55 +0100
committerAleksi Lindeman <0xdec05eba@gmail.com>2018-03-09 10:27:06 +0100
commit230e61091b401b8b2bb9496d557a15660fb5072b (patch)
tree13b937d93105c069d6478480c8a9ada45ccc2434 /src
parent2ffb47d0043e57707474e5ae811f97c2e5e93f25 (diff)
Partially implement 'add' operation
Diffstat (limited to 'src')
-rw-r--r--src/Database.cpp247
-rw-r--r--src/DatabaseStorage.cpp63
-rw-r--r--src/Encryption.cpp42
-rw-r--r--src/Hash.cpp14
-rw-r--r--src/Signature.cpp13
5 files changed, 247 insertions, 132 deletions
diff --git a/src/Database.cpp b/src/Database.cpp
index bcf5580..d01ff7d 100644
--- a/src/Database.cpp
+++ b/src/Database.cpp
@@ -30,8 +30,14 @@ const int OPENDHT_INFOHASH_LEN = 20;
namespace odhtdb
{
- const u16 DATABASE_CREATE_PACKET_STRUCTURE_VERSION = 0;
- const u16 DATABASE_ADD_PACKET_STRUCTURE_VERSION = 0;
+ const u16 DATABASE_CREATE_PACKET_STRUCTURE_VERSION = 1;
+ const u16 DATABASE_ADD_PACKET_STRUCTURE_VERSION = 1;
+
+ class RequestQuarantineException : public runtime_error
+ {
+ public:
+ RequestQuarantineException() : runtime_error("Request quarantine, will be processed later (can be real of fake request)") {}
+ };
DataView combine(sibs::SafeSerializer &headerSerializer, const Encryption &encryptedData)
{
@@ -43,12 +49,27 @@ namespace odhtdb
return DataView(result, allocationSize);
}
- DatabaseCreateResponse::DatabaseCreateResponse(const shared_ptr<char*> &_key, const shared_ptr<Hash> &_hash) :
+ DataView combine(const Signature::PublicKey &publicKey, const string &signedEncryptedData)
+ {
+ usize allocationSize = publicKey.getSize() + signedEncryptedData.size();
+ char *result = new char[allocationSize];
+ memcpy(result, publicKey.getData(), publicKey.getSize());
+ memcpy(result + publicKey.getSize(), signedEncryptedData.data(), signedEncryptedData.size());
+ return DataView(result, allocationSize);
+ }
+
+ DatabaseCreateResponse::DatabaseCreateResponse(LocalUser *_nodeAdminUser, const shared_ptr<char*> &_key, const shared_ptr<Hash> &_hash) :
+ nodeAdminUser(_nodeAdminUser),
key(move(_key)),
hash(_hash)
{
}
+
+ const LocalUser* DatabaseCreateResponse::getNodeAdminUser() const
+ {
+ return nodeAdminUser;
+ }
const shared_ptr<char*> DatabaseCreateResponse::getNodeEncryptionKey() const
{
@@ -133,13 +154,19 @@ namespace odhtdb
node.listen(dhtKey.getNewDataListenerKey(), [this, hash, encryptionKey](const shared_ptr<Value> &value)
{
- return listenAddData(value, *hash, encryptionKey);
+ printf("Seed: New data listener received data...\n");
+ const Hash requestHash(value->data.data(), value->data.size());
+ if(requestHash == *hash)
+ return true;
+ //return listenCreateData(value, requestHash, encryptionKey);
+ else
+ return listenAddData(value, requestHash, encryptionKey);
});
u8 responseKey[OPENDHT_INFOHASH_LEN];
randombytes_buf(responseKey, OPENDHT_INFOHASH_LEN);
- // TODO: If this response key is spammed, generate a new one
+ // TODO: If this response key is spammed, generate a new one.
node.listen(InfoHash(responseKey, OPENDHT_INFOHASH_LEN), [this, hash, encryptionKey](const shared_ptr<Value> &value)
{
const Hash requestHash(value->data.data(), value->data.size());
@@ -171,16 +198,20 @@ namespace odhtdb
if(dataStartTimestamp == 0)
{
printf("Request: Sent create packet to requesting peer\n");
- node.put(InfoHash(requestResponseKey, OPENDHT_INFOHASH_LEN), Value(requestedData->createData, requestedData->createDataSize), [](bool ok)
+ node.put(InfoHash(requestResponseKey, OPENDHT_INFOHASH_LEN), Value((u8*)requestedData->data.data, requestedData->data.size), [](bool ok)
{
if(!ok)
- fprintf(stderr, "Failed to put response for old data\n");
+ fprintf(stderr, "Failed to put response for old data for 'create' data\n");
});
}
- else
+
+ for(auto requestedObject : requestedData->objects)
{
- assert(false);
- printf("TODO: Send 'add' packets to requesting remote peer\n");
+ node.put(InfoHash(requestResponseKey, OPENDHT_INFOHASH_LEN), Value((u8*)requestedObject->data.data, requestedObject->data.size), [](bool ok)
+ {
+ if(!ok)
+ fprintf(stderr, "Failed to put response for old data for 'add' data\n");
+ });
}
}
catch (sibs::DeserializeException &e)
@@ -203,39 +234,41 @@ namespace odhtdb
//node.listen(ADD_DATA_HASH, bind(&Database::listenAddData, this, _1));
}
- unique_ptr<DatabaseCreateResponse> Database::create(const LocalUser *owner, const std::string &name)
+ unique_ptr<DatabaseCreateResponse> Database::create(const std::string &ownerName, const std::string &nodeName)
{
+ LocalUser *nodeAdminUser = LocalUser::create(Signature::KeyPair(), ownerName);
+ auto adminGroup = new Group("administrator");
+ adminGroup->addUser(nodeAdminUser);
+
// Header
sibs::SafeSerializer serializer;
serializer.add(DATABASE_CREATE_PACKET_STRUCTURE_VERSION); // Packet structure version
// TODO: Append fractions to get real microseconds time
u64 timestampMicroseconds = ((u64)getSyncedTimestampUtc().seconds) * 1000000ull;
serializer.add(timestampMicroseconds);
- serializer.add((u8*)owner->getPublicKey().getData(), PUBLIC_KEY_NUM_BYTES);
+ serializer.add((u8*)nodeAdminUser->getPublicKey().getData(), PUBLIC_KEY_NUM_BYTES);
// Encrypted body
sibs::SafeSerializer encryptedSerializer;
- assert(owner->getName().size() <= 255);
- encryptedSerializer.add((u8)owner->getName().size());
- encryptedSerializer.add((u8*)owner->getName().data(), owner->getName().size());
- assert(name.size() <= 255);
- encryptedSerializer.add((u8)name.size());
- encryptedSerializer.add((u8*)name.data(), name.size());
+ assert(nodeAdminUser->getName().size() <= 255);
+ encryptedSerializer.add((u8)nodeAdminUser->getName().size());
+ encryptedSerializer.add((u8*)nodeAdminUser->getName().data(), nodeAdminUser->getName().size());
+ assert(nodeName.size() <= 255);
+ encryptedSerializer.add((u8)nodeName.size());
+ encryptedSerializer.add((u8*)nodeName.data(), nodeName.size());
try
{
Encryption encryptedBody(DataView(encryptedSerializer.getBuffer().data(), encryptedSerializer.getBuffer().size()));
DataView requestData = combine(serializer, encryptedBody);
shared_ptr<Hash> hashRequestKey = make_shared<Hash>(requestData.data, requestData.size);
- auto adminGroup = new Group("administrator");
- adminGroup->addUser(owner);
databaseStorage.createStorage(*hashRequestKey, adminGroup, timestampMicroseconds, (const u8*)requestData.data, requestData.size);
- stagedCreateObjects.emplace_back(make_unique<StagedCreateObject>(requestData, hashRequestKey));
+ stagedCreateObjects.emplace_back(make_unique<StagedObject>(requestData, hashRequestKey));
assert(encryptedBody.getKey().size == KEY_BYTE_SIZE);
char *key = new char[encryptedBody.getKey().size];
memcpy(key, encryptedBody.getKey().data, encryptedBody.getKey().size);
- return make_unique<DatabaseCreateResponse>(make_shared<char*>(key), hashRequestKey);
+ return make_unique<DatabaseCreateResponse>(nodeAdminUser, make_shared<char*>(key), hashRequestKey);
}
catch (EncryptionException &e)
{
@@ -243,17 +276,22 @@ namespace odhtdb
}
}
- void Database::add(const LocalUser *owner, const Key &key, DataView data)
+ void Database::add(const unique_ptr<DatabaseCreateResponse> &nodeInfo, DataView dataToAdd)
{
-#if 0
- if(nodeEncryptionKeys.find(key) == nodeEncryptionKeys.end())
- throw DatabaseAddException("Data for key needs to be created before data can be appended to it");
-
- unique_ptr<string> signedData = make_unique<string>(owner->getPrivateKey().sign(data));
+ sibs::SafeSerializer serializer;
+ serializer.add(DATABASE_ADD_PACKET_STRUCTURE_VERSION);
// TODO: Append fractions to get real microseconds time
- u64 timeMicroseconds = ((u64)getSyncedTimestampUtc().seconds) * 1000000ull;
- stagedAddObjects.emplace_back(StagedAddObject(key, move(signedData), timeMicroseconds, owner->getPublicKey()));
-#endif
+ u64 timestampMicroseconds = ((u64)getSyncedTimestampUtc().seconds) * 1000000ull;
+ serializer.add(timestampMicroseconds);
+
+ DataView encryptionKey(*nodeInfo->getNodeEncryptionKey(), KEY_BYTE_SIZE);
+ Encryption encryptedBody(dataToAdd, DataView(), encryptionKey);
+ DataView requestData = combine(serializer, encryptedBody);
+ string signedRequestData = nodeInfo->getNodeAdminUser()->getPrivateKey().sign(requestData);
+ free(requestData.data);
+ DataView stagedAddObject = combine(nodeInfo->getNodeAdminUser()->getPublicKey(), signedRequestData);
+ // TODO: Add add object to database storage here for local user
+ stagedAddObjects.emplace_back(make_unique<StagedObject>(stagedAddObject, nodeInfo->getRequestHash()));
}
void Database::commit()
@@ -268,6 +306,12 @@ namespace odhtdb
{
commitStagedCreateObject(stagedObject);
}
+
+ printf("Num objects to add: %zu\n", stagedAddObjects.size());
+ for(const auto &stagedObject : stagedAddObjects)
+ {
+ commitStagedAddObject(stagedObject);
+ }
}
catch (exception &e)
{
@@ -276,24 +320,23 @@ namespace odhtdb
for(const auto &stagedObject : stagedCreateObjects)
{
- free(stagedObject->encryptedBody.data);
+ free(stagedObject->data.data);
}
stagedCreateObjects.clear();
-#if 0
- printf("Num objects to add: %d\n", stagedAddObjects.size());
- for(StagedAddObject &stagedObject : stagedAddObjects)
+
+ for(const auto &stagedObject : stagedAddObjects)
{
- commitStagedAddObject(stagedObject);
+ free(stagedObject->data.data);
}
stagedAddObjects.clear();
-#endif
+
// TODO: Add node.listen here to get notified when remote peers got the commit, then we can say we can return
}
- void Database::commitStagedCreateObject(const unique_ptr<StagedCreateObject> &stagedObject)
+ void Database::commitStagedCreateObject(const unique_ptr<StagedObject> &stagedObject)
{
DhtKey dhtKey(*stagedObject->requestKey);
- Value createDataValue((u8*)stagedObject->encryptedBody.data, stagedObject->encryptedBody.size);
+ Value createDataValue((u8*)stagedObject->data.data, stagedObject->data.size);
node.put(dhtKey.getNewDataListenerKey(), move(createDataValue), [](bool ok)
{
// TODO: Handle failure to put data
@@ -302,48 +345,16 @@ namespace odhtdb
}/* TODO: How to make this work?, time_point(), false*/);
}
- void Database::commitStagedAddObject(const DataView &stagedObject)
+ void Database::commitStagedAddObject(const unique_ptr<StagedObject> &stagedObject)
{
-#if 0
- // TODO: Implement gas and price (refill when serving content (seeding) or by waiting. This is done to prevent spamming and bandwidth leeching)
- sibs::SafeSerializer headerSerializer;
- assert(stagedObject.key.hashedKey.size() == OPENDHT_INFOHASH_LEN);
- headerSerializer.add(stagedObject.key.hashedKey.data(), OPENDHT_INFOHASH_LEN);
- headerSerializer.add(stagedObject.timestamp);
-
- sibs::SafeSerializer bodySerializer;
- bodySerializer.add((u8*)stagedObject.creatorPublicKey.getData(), PUBLIC_KEY_NUM_BYTES);
- assert(stagedObject.data->size() < 0xFFFF - 120);
- bodySerializer.add((u16)stagedObject.data->size());
- bodySerializer.add((u8*)stagedObject.data->data(), stagedObject.data->size());
-
- EncryptedData encryptedData;
- if(encrypt(&encryptedData, (EncryptionKey*)nodeEncryptionKeys[stagedObject.key], bodySerializer.getBuffer().data(), bodySerializer.getBuffer().size()) < 0)
- throw CommitAddException("Failed to encrypt staged add object");
-
- Blob serializedData;
- combine(&serializedData, headerSerializer, encryptedData);
-
- // TODO: Verify if serializer buffer needs to survive longer than this scope
- Value addDataValue(move(serializedData));
- node.put(ADD_DATA_HASH, move(addDataValue), [](bool ok)
- {
- // TODO: Handle failure to put data
- if(!ok)
- fprintf(stderr, "Failed to put for all: %s, what to do?\n", "commitStagedAddObject");
- });
-
- // Post data for listeners of this key
- /*
- Value putKeyValue(serializer.getBuffer().data() + OPENDHT_INFOHASH_LEN, serializer.getBuffer().size() - OPENDHT_INFOHASH_LEN);
- node.put(stagedObject.key.hashedKey, move(putKeyValue), [](bool ok)
+ DhtKey dhtKey(*stagedObject->requestKey);
+ Value createDataValue((u8*)stagedObject->data.data, stagedObject->data.size);
+ node.put(dhtKey.getNewDataListenerKey(), move(createDataValue), [](bool ok)
{
// TODO: Handle failure to put data
if(!ok)
- fprintf(stderr, "Failed to put for listeners: %s, what to do?\n", "commitStagedAddObject");
- });
- */
-#endif
+ fprintf(stderr, "Failed to put: %s, what to do?\n", "commitStagedAddObject");
+ }/* TODO: How to make this work?, time_point(), false*/);
}
ntp::NtpTimestamp Database::getSyncedTimestampUtc() const
@@ -382,7 +393,7 @@ namespace odhtdb
throw sibs::DeserializeException("Unsigned encrypted body is too small (unable to extract nonce)");
auto adminGroup = new Group("administrator");
- auto creatorUser = RemoteUser::create(userPublicKey, ""); // Username is encrypted, we dont know it...
+ auto creatorUser = RemoteUser::create(userPublicKey, "ENCRYPTED USER NAME"); // Username is encrypted, we dont know it...
adminGroup->addUser(creatorUser);
databaseStorage.createStorage(hash, adminGroup, creationDate, value->data.data(), value->data.size());
@@ -400,42 +411,61 @@ namespace odhtdb
u8 nameLength = bodyDeserializer.extract<u8>();
string name;
name.resize(nameLength);
- bodyDeserializer.extract((u8*)&name[0], nameLength);
+ bodyDeserializer.extract((u8*)&name[0], nameLength); // TODO: Add this user name to storage added above
return { creationDate, adminGroup, move(name) };
}
DatabaseAddRequest Database::deserializeAddRequest(const std::shared_ptr<dht::Value> &value, const Hash &hash, const shared_ptr<char*> encryptionKey)
{
- /*
- StagedAddObject result;
-
sibs::SafeDeserializer deserializer(value->data.data(), value->data.size());
- u8 entryKeyRaw[OPENDHT_INFOHASH_LEN];
- deserializer.extract(entryKeyRaw, OPENDHT_INFOHASH_LEN);
- result.key.hashedKey = InfoHash(entryKeyRaw, OPENDHT_INFOHASH_LEN);
- result.timestamp = deserializer.extract<u64>();
-
char creatorPublicKeyRaw[PUBLIC_KEY_NUM_BYTES];
deserializer.extract((u8*)creatorPublicKeyRaw, PUBLIC_KEY_NUM_BYTES);
- Signature::PublicKey creatorPublicKey(creatorPublicKeyRaw, PUBLIC_KEY_NUM_BYTES);
+ Signature::PublicKey userPublicKey(creatorPublicKeyRaw, PUBLIC_KEY_NUM_BYTES);
- u16 dataSize = deserializer.extract<u16>();
- if(dataSize < SIGNED_HASH_SIZE)
- throw sibs::DeserializeException("Signed data is too small");
+ DataView signedData((void*)deserializer.getBuffer(), deserializer.getSize());
+ string unsignedData = userPublicKey.unsign(signedData);
+ sibs::SafeDeserializer deserializerUnsigned((u8*)unsignedData.data(), unsignedData.size());
- string signedData;
- signedData.resize(dataSize);
- deserializer.extract((u8*)&signedData[0], dataSize);
- result.data = make_unique<string>();
- result.data->resize(dataSize);
- result.data = make_unique<string>(creatorPublicKey.unsign(DataView((void*)signedData.data(), signedData.size())));
-
- return result;
- */
- Signature::PublicKey publicKey(nullptr, 0);
- DataView d;
- return { 0, 0, move(publicKey), d };
+ u16 packetStructureVersion = deserializerUnsigned.extract<u16>();
+ if(packetStructureVersion != DATABASE_CREATE_PACKET_STRUCTURE_VERSION)
+ {
+ string errMsg = "Received 'create' request with packet structure version ";
+ errMsg += to_string(packetStructureVersion);
+ errMsg += ", but our packet structure version is ";
+ errMsg += to_string(DATABASE_CREATE_PACKET_STRUCTURE_VERSION);
+ throw sibs::DeserializeException(errMsg);
+ }
+
+ u64 creationDate = deserializerUnsigned.extract<u64>();
+ // TODO: Append fractions to get real microseconds time
+ u64 timestampMicroseconds = ((u64)getSyncedTimestampUtc().seconds) * 1000000ull;
+ if(creationDate > timestampMicroseconds)
+ throw sibs::DeserializeException("Packet is from the future");
+
+ if(deserializerUnsigned.getSize() < NONCE_BYTE_SIZE)
+ throw sibs::DeserializeException("Unsigned encrypted body is too small (unable to extract nonce)");
+
+ const Hash *node = databaseStorage.getNodeByUserPublicKey(userPublicKey);
+ if(!node)
+ {
+ // The user (public key) could belong to a node but we might not have retrieved the node info yet since data may
+ // not be retrieved in order.
+ // Data in quarantine is processed when 'create' packet is received or removed after 60 seconds
+ databaseStorage.addToQuarantine(userPublicKey, creationDate, value->data.data(), value->data.size());
+ throw RequestQuarantineException();
+ }
+
+ auto creatorUser = databaseStorage.getUserByPublicKey(userPublicKey);
+ // TODO: Verify there isn't already data with same timestamp for this node. Same for quarantine
+ databaseStorage.appendStorage(*node, creatorUser, creationDate, value->data.data(), value->data.size());
+
+ u8 nonce[NONCE_BYTE_SIZE];
+ deserializerUnsigned.extract(nonce, NONCE_BYTE_SIZE);
+ DataView dataToDecrypt((void*)deserializerUnsigned.getBuffer(), deserializerUnsigned.getSize());
+ Decryption decryptedBody(dataToDecrypt, DataView(nonce, NONCE_BYTE_SIZE), DataView(*encryptionKey, KEY_BYTE_SIZE));
+
+ return { creationDate, creatorUser, move(decryptedBody) };
}
bool Database::listenCreateData(std::shared_ptr<dht::Value> value, const Hash &hash, const shared_ptr<char*> encryptionKey)
@@ -460,11 +490,12 @@ namespace odhtdb
printf("Got add data\n");
try
{
- if(databaseStorage.getStorage(hash))
- throw DatabaseStorageAlreadyExists("Add request hash is equal to hash already in storage (duplicate data?)");
- // TODO: Verify createObject timestamp is not in the future
- //StagedAddObject addObject = deserializeAddRequest(value);
- //DataView data((void*)addObject.data->data(), addObject.data->size());
+ DatabaseAddRequest addObject = deserializeAddRequest(value, hash, encryptionKey);
+ printf("Got add object, timestamp: %zu\n", addObject.timestamp);
+ }
+ catch (RequestQuarantineException &e)
+ {
+ fprintf(stderr, "Warning: Request was put in quarantine, will be processed later");
}
catch (exception &e)
{
diff --git a/src/DatabaseStorage.cpp b/src/DatabaseStorage.cpp
index 25d41fb..638eac0 100644
--- a/src/DatabaseStorage.cpp
+++ b/src/DatabaseStorage.cpp
@@ -1,13 +1,28 @@
#include "../include/DatabaseStorage.hpp"
+#include "../include/Group.hpp"
+#include "../include/User.hpp"
#include <cstring>
+#include <chrono>
using namespace std;
namespace odhtdb
{
+ DatabaseStorageObject::DatabaseStorageObject(DataView &_data, u64 _timestamp, const Signature::PublicKey &_creatorPublicKey) :
+ data(_data), createdTimestamp(_timestamp), creatorPublicKey(_creatorPublicKey)
+ {
+
+ }
+
+ DatabaseStorageQuarantineObject::DatabaseStorageQuarantineObject(DataView &_data, u64 _timestamp, const Signature::PublicKey &_creatorPublicKey) :
+ data(_data), createdTimestamp(_timestamp), creatorPublicKey(_creatorPublicKey)
+ {
+ auto time = chrono::high_resolution_clock::now().time_since_epoch();
+ storedTimestamp = chrono::duration_cast<chrono::microseconds>(time).count();
+ }
+
void DatabaseStorage::createStorage(const Hash &hash, Group *creatorGroup, u64 timestamp, const u8 *data, usize dataSize)
{
- /*
if(storageMap.find(hash) != storageMap.end())
{
string errMsg = "Database storage with hash ";
@@ -15,18 +30,22 @@ namespace odhtdb
errMsg += " already exists";
throw DatabaseStorageAlreadyExists(errMsg);
}
- */
DatabaseStorageObjectList *databaseStorageObjectList = new DatabaseStorageObjectList();
- databaseStorageObjectList->timestamp = timestamp;
+ databaseStorageObjectList->createdTimestamp = timestamp;
databaseStorageObjectList->groups.push_back(creatorGroup);
- databaseStorageObjectList->createData = new u8[dataSize];
- memcpy(databaseStorageObjectList->createData, data, dataSize);
- databaseStorageObjectList->createDataSize = dataSize;
+ databaseStorageObjectList->data = DataView(new u8[dataSize], dataSize);
+ memcpy(databaseStorageObjectList->data.data, data, dataSize);
storageMap[hash] = databaseStorageObjectList;
+
+ for(auto user : creatorGroup->getUsers())
+ {
+ userPublicKeyNodeMap[user->getPublicKey()] = hash;
+ publicKeyUserMap[user->getPublicKey()] = user;
+ }
}
- void DatabaseStorage::appendStorage(const Hash &hash, DataView &data, u64 timestamp, const Signature::PublicKey &creatorPublicKey)
+ void DatabaseStorage::appendStorage(const Hash &hash, const User *creatorUser, u64 timestamp, const u8 *data, usize dataSize)
{
auto it = storageMap.find(hash);
if(it == storageMap.end())
@@ -36,7 +55,18 @@ namespace odhtdb
errMsg += " not found. Storage for a hash needs to be created before data can be appended to it";
throw DatabaseStorageNotFound(errMsg);
}
- it->second->objects.push_back({data, timestamp, creatorPublicKey});
+
+ DataView storageData { new u8[dataSize], dataSize };
+ DatabaseStorageObject *databaseStorageObject = new DatabaseStorageObject(storageData, timestamp, creatorUser->getPublicKey());
+ it->second->objects.push_back(databaseStorageObject);
+ }
+
+ void DatabaseStorage::addToQuarantine(const Signature::PublicKey &creatorPublicKey, u64 timestamp, const u8 *data, usize dataSize)
+ {
+ DataView storageData { new u8[dataSize], dataSize };
+ memcpy(storageData.data, data, dataSize);
+ DatabaseStorageQuarantineObject *databaseQuarantineStorageObject = new DatabaseStorageQuarantineObject(storageData, timestamp, creatorPublicKey);
+ quarantineStorageMap[creatorPublicKey].emplace_back(databaseQuarantineStorageObject);
}
const DatabaseStorageObjectList* DatabaseStorage::getStorage(const Hash &hash) const
@@ -46,4 +76,21 @@ namespace odhtdb
return it->second;
return nullptr;
}
+
+ const Hash* DatabaseStorage::getNodeByUserPublicKey(const Signature::PublicKey &userPublicKey) const
+ {
+ auto it = userPublicKeyNodeMap.find(userPublicKey);
+ if(it != userPublicKeyNodeMap.end())
+ return &it->second;
+ return nullptr;
+ }
+
+ // Returns nullptr if no user with public key exists
+ const User* DatabaseStorage::getUserByPublicKey(const Signature::PublicKey &userPublicKey) const
+ {
+ auto it = publicKeyUserMap.find(userPublicKey);
+ if(it != publicKeyUserMap.end())
+ return it->second;
+ return nullptr;
+ }
}
diff --git a/src/Encryption.cpp b/src/Encryption.cpp
index c4e6a2c..238861f 100644
--- a/src/Encryption.cpp
+++ b/src/Encryption.cpp
@@ -1,16 +1,26 @@
#include "../include/Encryption.hpp"
#include <sodium/crypto_aead_xchacha20poly1305.h>
#include <sodium/randombytes.h>
-#include <string>
+#include <cstring>
namespace odhtdb
{
- Encryption::Encryption(const DataView &data, const DataView &additionalData)
+ Encryption::Encryption(const DataView &data, const DataView &additionalData, const DataView &_key)
{
- cipherText = new unsigned char[crypto_aead_xchacha20poly1305_ietf_ABYTES + data.size];
- crypto_aead_xchacha20poly1305_ietf_keygen(key);
+ cipherText = new unsigned char[crypto_aead_xchacha20poly1305_ietf_ABYTES + data.size];
+ cipherTextLength = crypto_aead_xchacha20poly1305_ietf_ABYTES + data.size;
+
+ if(_key.data)
+ {
+ if(_key.size != KEY_BYTE_SIZE)
+ throw EncryptionException("Encryption key is wrong size");
+ memcpy(key, _key.data, _key.size);
+ }
+ else
+ crypto_aead_xchacha20poly1305_ietf_keygen(key);
+
randombytes_buf(nonce, 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, (const unsigned char*)additionalData.data, additionalData.size, nullptr, nonce, key) < 0)
throw EncryptionException("Failed to encrypt data");
}
@@ -37,6 +47,7 @@ namespace odhtdb
Decryption::Decryption(const DataView &data, const DataView &nonce, const DataView &key)
{
decryptedText = new unsigned char[data.size];
+ decryptedTextLength = data.size;
if(nonce.size < NONCE_BYTE_SIZE)
throw DecryptionException("Nonce is not big enough");
@@ -44,10 +55,29 @@ namespace odhtdb
if(key.size < KEY_BYTE_SIZE)
throw DecryptionException("Key is not big enough");
- if(crypto_aead_xchacha20poly1305_ietf_decrypt(decryptedText, &decryptedTextLength, nullptr, (const unsigned char*)data.data, data.size, nullptr, 0, (const unsigned char*)nonce.data, (const unsigned char*)key.data) != 0)
+ if(crypto_aead_xchacha20poly1305_ietf_decrypt(decryptedText, &decryptedTextLength, nullptr, (const unsigned char*)data.data, data.size, nullptr, 0, (const unsigned char*)nonce.data, (const unsigned char*)key.data) < 0)
throw DecryptionException("Failed to decrypt data");
}
+ Decryption::Decryption(Decryption &&other)
+ {
+ decryptedText = other.decryptedText;
+ decryptedTextLength = other.decryptedTextLength;
+
+ other.decryptedText = nullptr;
+ other.decryptedTextLength = 0;
+ }
+
+ Decryption& Decryption::operator=(Decryption &&other)
+ {
+ decryptedText = other.decryptedText;
+ decryptedTextLength = other.decryptedTextLength;
+
+ other.decryptedText = nullptr;
+ other.decryptedTextLength = 0;
+ return *this;
+ }
+
Decryption::~Decryption()
{
delete[](decryptedText);
diff --git a/src/Hash.cpp b/src/Hash.cpp
index 5d2f914..91bc062 100644
--- a/src/Hash.cpp
+++ b/src/Hash.cpp
@@ -17,15 +17,6 @@ namespace odhtdb
static SodiumInitializer __sodiumInitializer;
- // Source: https://stackoverflow.com/a/11414104 (public license)
- static size_t fnvHash(const unsigned char *key, int len)
- {
- size_t h = 2166136261;
- for (int i = 0; i < len; i++)
- h = (h * 16777619) ^ key[i];
- return h;
- }
-
Hash::Hash()
{
memset(data, 0, HASH_BYTE_SIZE);
@@ -38,6 +29,11 @@ namespace odhtdb
throw HashException("Failed to hash data using blake2b");
}
+ Hash::Hash(const Hash &other)
+ {
+ memcpy(data, other.data, HASH_BYTE_SIZE);
+ }
+
size_t Hash::operator()() const
{
return fnvHash((const unsigned char*)data, HASH_BYTE_SIZE);
diff --git a/src/Signature.cpp b/src/Signature.cpp
index 34f6190..d328b58 100644
--- a/src/Signature.cpp
+++ b/src/Signature.cpp
@@ -1,4 +1,5 @@
#include "../include/Signature.hpp"
+#include "../include/Hash.hpp"
#include <sodium/crypto_sign_ed25519.h>
#include <sodium/utils.h>
#include <cstring>
@@ -48,10 +49,20 @@ namespace odhtdb
return result;
}
+ size_t PublicKey::operator()() const
+ {
+ return fnvHash((const unsigned char*)data, PUBLIC_KEY_NUM_BYTES);
+ }
+
+ bool PublicKey::operator==(const PublicKey &other) const
+ {
+ return memcmp(data, other.data, PUBLIC_KEY_NUM_BYTES) == 0;
+ }
+
string PublicKey::toString() const
{
string result;
- result.resize(PUBLIC_KEY_NUM_BYTES * 2);
+ result.resize(PUBLIC_KEY_NUM_BYTES * 2 + 1);
sodium_bin2hex(&result[0], PUBLIC_KEY_NUM_BYTES * 2 + 1, (const unsigned char*)data, PUBLIC_KEY_NUM_BYTES);
return result;
}