Initial commit

This commit is contained in:
belong 2021-03-06 19:46:35 +00:00
commit 34be706660
9 changed files with 417 additions and 0 deletions

16
.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
.dub
docs.json
__dummy.html
docs/
configs/
/dropper
dropper.so
dropper.dylib
dropper.dll
dropper.a
dropper.lib
dropper-test-*
*.exe
*.o
*.obj
*.lst

44
README.md Normal file
View File

@ -0,0 +1,44 @@
# Dropper
The dropper is part the of the deaddrop project.
It is used to post / fetch encrypted messages to / from the
drop server.
## Required software:
- dmd
- dub
- libsodium
## Building
```bash
$ git clone http://repourl/dropper.git dropper
$ cd dropper
$ dub build --build=release
```
## Simple usage:
Key generation:
```bash
$ ./dropper -w ./key_dir/alice
```
Sending a message
- specify the base64 encoded publickey of the recipient with -r
- load the previously generated keys from disk with -c
- specify the message to send with -m
- specify the url of the drop server with -u
```bash
$ ./dropper -c ./key_dir/alice -m "Hello Bob" -r "3e51N4....pHI=" -u "http://dropperserver.url"
```
Getting all messages for a public key:
- specify that we want to fetch messages with -f
- load the previously generated keys from disk with -c
```bash
$ ./dropper -f -c ./key_dir/bob -u "http://dropperserver.url"
```

12
dub.json Normal file
View File

@ -0,0 +1,12 @@
{
"authors": [
"anon"
],
"copyright": "Copyright © 2021, anon",
"dependencies": {
"libsodiumd": "~>0.1.1"
},
"description": "A minimal D application.",
"license": "proprietary",
"name": "dropper"
}

6
dub.selections.json Normal file
View File

@ -0,0 +1,6 @@
{
"fileVersion": 1,
"versions": {
"libsodiumd": "0.1.1+1.0.18"
}
}

118
source/app.d Normal file
View File

@ -0,0 +1,118 @@
import std.stdio;
import std.getopt;
import userinfo;
import message;
import cryptoclass;
import networker;
void generateAndSaveKeys(string write_path)
{
UserInfo user;
writeln("[*] Generating keys...");
generateKeysForUser(user);
writeln("[+] Generated user-keys:");
writeln(">> Public-Key: ", user.b64_publickey);
writeln(">> Private-Key: ", user.b64_privatekey);
writeln("[*] Saving keys to files...");
saveKeysToFile(user, write_path);
writeln("[+] Saved keys into files: ");
writeln("Public-Key -> ", write_path ~ ".pub");
writeln("Private-Key -> ", write_path ~ ".priv");
}
UserInfo loadConfigs(string config_path)
{
immutable string priv_key_file = config_path ~ ".priv";
immutable string pub_key_file = config_path ~ ".pub";
// Load the users keys
writeln("[*] Loading keys from ", config_path);
UserInfo user = loadUserInfoFromFile(priv_key_file, pub_key_file);
writeln("[+] Loaded keys:");
writeln("\t->", priv_key_file);
writeln("\t->", pub_key_file);
return user;
}
void main(string[] args)
{
string write_path;
string config_path;
string message;
string b64_recipient_pubkey;
string server_url;
bool fetch = false;
auto flags = getopt(args,
std.getopt.config.bundling,
"w|write", "Path to generate and write keys to. ( ./config/alice )", &write_path,
"c|config", "File prefix to load key files from. ( ./configs/alice )", &config_path,
"m|messsage", "The message that should be sent. ( \"Hi bob how are you?\" ) ", &message,
"f|fetch", "If this option is set the dropper only fetches messages for the public-key from -config", &fetch,
"r|recipient", "Base64 encoded public-key of the recipient", &b64_recipient_pubkey,
"u|url", "URL of the deaddrop server.", &server_url);
if (write_path != "")
{
generateAndSaveKeys(write_path);
return;
}
if (fetch && config_path != "" && server_url != "")
{
UserInfo user = loadConfigs(config_path);
Cryptoclass crypto = new Cryptoclass(user);
Networker networker = new Networker(server_url);
writeln("\n📧📧📧 You've got mail 📧📧📧\n");
auto list = networker.getMessagesForRecipient(user.b64_publickey);
foreach (single_message; list)
{
auto bin_msg = crypto.decryptMessage(single_message["payload"]);
writeln(cast(string)bin_msg);
}
return;
}
else if (flags.helpWanted
|| config_path == ""
|| message == ""
|| b64_recipient_pubkey == ""
|| server_url == "")
{
defaultGetoptPrinter("Dropper to post and get messages from a deaddrop server.",
flags.options);
return;
}
// Load the configs
UserInfo user = loadConfigs(config_path);
// Create the crypto class
Cryptoclass crypto = new Cryptoclass(user);
Networker networker = new Networker(server_url);
// Timestamp the message
string timestamped_msg = prependTimeStamp(message);
// Encrypt the message
writeln("[*] Encrypting message...");
auto binary_payload = crypto.encryptMessage(b64_recipient_pubkey, timestamped_msg);
writeln("[*] Encoding payload...");
string encoded_payload = encodePayload(binary_payload);
// Format the message for a post request
writeln("[*] Formatting message...");
Message msg = formatMessage(b64_recipient_pubkey, encoded_payload);
// Post message to server
writeln("[!] Posting message to server ", server_url);
networker.postMessage(msg);
writeln("[+] Done :^)");
}

76
source/cryptoclass.d Normal file
View File

@ -0,0 +1,76 @@
module cryptoclass;
import userinfo : UserInfo;
/// This class handles the encryption and
/// decryption of messages to the `UserInfo`
/// that was specified while creating this class
class Cryptoclass
{
private:
import libsodium;
import std.stdio : stderr;
import std.base64 : Base64;
import core.stdc.stdlib : exit, EXIT_FAILURE;
UserInfo p_me;
public:
/// This constructor sets the `UserInfo` for the crypto class
/// that is used to decrypt messages. It also makes sure
/// that libsodium is loaded and initialized
this(UserInfo user)
{
// Load libsodium
if (sodium_init() < 0)
{
stderr.writeln("[-] Failed to load libsodium! Is it installed?");
exit(EXIT_FAILURE);
}
this.p_me = user;
}
/// This function encrypts messages for the base64 encoded public
/// key that is passed to the function and returns a ubyte array
/// containing the payload
ubyte[] encryptMessage(string b64_recipientPublicKey, string message)
{
import std.conv : to;
ubyte[] messageBin = cast(ubyte[])message;
ubyte[] cipherText = new ubyte[(crypto_box_SEALBYTES + messageBin.length)];
ubyte[] recipientPublicKey = Base64.decode(b64_recipientPublicKey);
crypto_box_seal(cipherText.ptr, messageBin.ptr, messageBin.length, recipientPublicKey.ptr);
return cipherText;
}
/// This function decrypts a given base64 encoded
/// payload string using the internal userinfos
/// public and private key and returns
/// the decrypted buffer as a ubyte array
ubyte[] decryptMessage(string messagePayload)
{
ubyte[] payloadBinary = Base64.decode(messagePayload);
ubyte[] decrypted = new ubyte[payloadBinary.length];
ubyte[crypto_box_PUBLICKEYBYTES] pubkey = p_me.getPublicKey();
ubyte[crypto_box_SECRETKEYBYTES] seckey = p_me.getPrivateKey();
if (crypto_box_seal_open(
decrypted.ptr,
payloadBinary.ptr,
payloadBinary.length,
pubkey.ptr,
seckey.ptr
) != 0 ) {
stderr.writeln("[!] Failed to open sealed message!!!");
}
return decrypted;
}
}

26
source/message.d Normal file
View File

@ -0,0 +1,26 @@
module message;
alias Message = string[string];
string encodePayload(ubyte[] payload)
{
import std.base64 : Base64;
return Base64.encode(payload);
}
Message formatMessage(string recipient, string payload)
{
return [
"recipient": recipient,
"payload": payload
];
}
string prependTimeStamp(string message)
{
import std.datetime : Clock;
import std.conv : to;
string utc = to!string(Clock.currTime.toUTC());
return utc ~ " >> " ~ message;
}

53
source/networker.d Normal file
View File

@ -0,0 +1,53 @@
module networker;
import message;
class Networker
{
private:
import std.net.curl : get, post;
string p_serverUrl;
public:
this(string serverUrl)
{
this.p_serverUrl = serverUrl;
}
void postMessage(Message msg)
{
auto content = post(p_serverUrl ~ "/add-message", msg);
}
Message[] getMessagesForRecipient(string b64_publickey)
{
import std.conv : to;
import std.json : parseJSON, JSONValue, JSONException;
Message[] msgs;
auto queryParams = ["pubkey": b64_publickey];
auto content = post(p_serverUrl ~ "/getmessages", queryParams);
auto json = parseJSON(to!string(content));
foreach (msg_json; json.array)
{
try
{
Message single_msg = [
"recipient": msg_json["recipient"].str,
"payload": msg_json["payload"].str
];
msgs ~= single_msg;
}
catch(Exception ex)
{
continue;
}
}
return msgs;
}
}

66
source/userinfo.d Normal file
View File

@ -0,0 +1,66 @@
module userinfo;
import std.base64 : Base64;
struct UserInfo
{
public:
string b64_publickey;
string b64_privatekey;
ubyte[] getPublicKey()
{
return Base64.decode(b64_publickey);
}
ubyte[] getPrivateKey()
{
return Base64.decode(b64_privatekey);
}
}
void generateKeysForUser(out UserInfo user)
{
import libsodium : crypto_box_keypair, crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES;
import std.stdio : stderr;
ubyte[crypto_box_PUBLICKEYBYTES] publicKey;
ubyte[crypto_box_SECRETKEYBYTES] privateKey;
if (crypto_box_keypair(publicKey.ptr, privateKey.ptr) != 0)
{
stderr.writeln("[-] Failed to generate keypair!");
}
user.b64_publickey = Base64.encode(publicKey);
user.b64_privatekey = Base64.encode(privateKey);
}
UserInfo loadUserInfoFromFile(string privateKeyFile, string publicKeyFile)
{
import std.file : readText;
UserInfo user;
user.b64_publickey = readText(publicKeyFile);
user.b64_privatekey = readText(privateKeyFile);
return user;
}
void saveKeysToFile(UserInfo user, string file_name_prefix)
{
import std.file : write;
write(file_name_prefix ~ ".pub", user.b64_publickey);
write(file_name_prefix ~ ".priv", user.b64_privatekey);
}
UserInfo createRecipient(string b64_publicKey)
{
UserInfo recipient;
recipient.b64_publickey = b64_publicKey;
recipient.b64_privatekey = "";
return recipient;
}