diff options
author | dec05eba <dec05eba@protonmail.com> | 2018-03-09 10:26:55 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-08-18 23:25:46 +0200 |
commit | 0e62cb8e5ed06d906ad84321cdda22acfcc952c9 (patch) | |
tree | 9ba0cc8e20febb4bf07d4d065e3d653ed651bdda /src | |
parent | eda9a7bbefc5587bf1ff895a9214f450e64575fa (diff) |
Partially implement 'add' operation
Diffstat (limited to 'src')
-rw-r--r-- | src/Database.cpp | 247 | ||||
-rw-r--r-- | src/DatabaseStorage.cpp | 63 | ||||
-rw-r--r-- | src/Encryption.cpp | 42 | ||||
-rw-r--r-- | src/Hash.cpp | 14 | ||||
-rw-r--r-- | src/Signature.cpp | 13 |
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; } |