Move encryption code over to SDK
This commit is contained in:
parent
c671cd464c
commit
0954cdfb32
2 changed files with 230 additions and 11 deletions
|
@ -1,12 +1,14 @@
|
||||||
#ifndef _matrixclient_h_
|
#ifndef _matrixclient_h_
|
||||||
#define _matrixclient_h_
|
#define _matrixclient_h_
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <curl/curl.h>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "olm/account.hh"
|
||||||
|
|
||||||
namespace Matrix {
|
namespace Matrix {
|
||||||
|
|
||||||
|
@ -49,6 +51,7 @@ private:
|
||||||
bool stopSyncing = false;
|
bool stopSyncing = false;
|
||||||
bool isSyncing = false;
|
bool isSyncing = false;
|
||||||
Thread syncThread;
|
Thread syncThread;
|
||||||
|
olm::Account acc;
|
||||||
struct {
|
struct {
|
||||||
eventCallback event = NULL;
|
eventCallback event = NULL;
|
||||||
eventCallback leaveRoom = NULL;
|
eventCallback leaveRoom = NULL;
|
||||||
|
@ -61,6 +64,8 @@ private:
|
||||||
json_t* doSync(std::string token, std::string filter, u32 timeout, CURLcode* res);
|
json_t* doSync(std::string token, std::string filter, u32 timeout, CURLcode* res);
|
||||||
json_t* doRequest(const char* method, std::string path, json_t* body = NULL, u32 timeout = 5, CURLcode* retRes = NULL);
|
json_t* doRequest(const char* method, std::string path, json_t* body = NULL, u32 timeout = 5, CURLcode* retRes = NULL);
|
||||||
json_t* doRequestCurl(const char* method, std::string url, json_t* body, u32 timeout, CURLcode* retRes);
|
json_t* doRequestCurl(const char* method, std::string url, json_t* body, u32 timeout, CURLcode* retRes);
|
||||||
|
|
||||||
|
static void print_json(json_t *json);
|
||||||
public:
|
public:
|
||||||
Client(std::string homeserverUrl, std::string matrixToken = "", Store* clientStore = NULL);
|
Client(std::string homeserverUrl, std::string matrixToken = "", Store* clientStore = NULL);
|
||||||
std::string getToken() const;
|
std::string getToken() const;
|
||||||
|
@ -97,6 +102,19 @@ public:
|
||||||
void setRoomLimitedCallback(roomLimitedCallback cb);
|
void setRoomLimitedCallback(roomLimitedCallback cb);
|
||||||
void syncLoop();
|
void syncLoop();
|
||||||
void uploadKeys(json_t* body);
|
void uploadKeys(json_t* body);
|
||||||
|
|
||||||
|
// Crypto
|
||||||
|
void generate_otk(size_t otkcount);
|
||||||
|
void generate_otk();
|
||||||
|
void generate_device_key();
|
||||||
|
void generate_fallback_key();
|
||||||
|
void sign_json(json_t* json);
|
||||||
|
json_t* get_device_keys();
|
||||||
|
json_t* get_fallback_keys();
|
||||||
|
json_t* get_unpublished_otk();
|
||||||
|
void save_keys();
|
||||||
|
void upload_keys();
|
||||||
|
void start_encryption();
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace Matrix
|
}; // namespace Matrix
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
#include <matrixclient.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <curl/curl.h>
|
#include <matrixclient.h>
|
||||||
#include <string.h>
|
#include <olm/olm.h>
|
||||||
#include "util.h"
|
#include <stdio.h>
|
||||||
#include "memorystore.h"
|
#include <cstring>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <olm/account.hh>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include "memorystore.h"
|
||||||
|
#include "olm/base64.hh"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
@ -877,4 +882,200 @@ json_t* Client::doRequestCurl(const char* method, std::string url, json_t* body,
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::print_json(json_t *json){
|
||||||
|
char* data = json_dumps(json, 0);
|
||||||
|
puts(data);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::generate_otk(size_t otkcount) {
|
||||||
|
size_t len = acc.generate_one_time_keys_random_length(otkcount);
|
||||||
|
std::unique_ptr<uint8_t[]> otkrandom = std::make_unique<uint8_t[]>(len);
|
||||||
|
PS_GenerateRandomBytes(otkrandom.get(), len);
|
||||||
|
acc.generate_one_time_keys(otkcount, otkrandom.get(), len);
|
||||||
|
}
|
||||||
|
void Client::generate_otk() {
|
||||||
|
size_t otkcount = acc.max_number_of_one_time_keys() / 2;
|
||||||
|
generate_otk(otkcount);
|
||||||
|
}
|
||||||
|
void Client::generate_device_key() {
|
||||||
|
size_t len = acc.new_account_random_length();
|
||||||
|
std::unique_ptr<uint8_t[]> random = std::make_unique<uint8_t[]>(len);
|
||||||
|
PS_GenerateRandomBytes(random.get(), len);
|
||||||
|
acc.new_account(random.get(), len);
|
||||||
|
}
|
||||||
|
void Client::generate_fallback_key() {
|
||||||
|
size_t len = acc.generate_fallback_key_random_length();
|
||||||
|
std::unique_ptr<uint8_t[]> random = std::make_unique<uint8_t[]>(len);
|
||||||
|
PS_GenerateRandomBytes(random.get(), len);
|
||||||
|
acc.generate_fallback_key(random.get(), len);
|
||||||
|
}
|
||||||
|
// Make sure to remove any unsigned and signatures block before doing this !
|
||||||
|
void Client::sign_json(json_t* json) {
|
||||||
|
puts("Signing json");
|
||||||
|
char* jsonStr = json_dumps(json, JSON_COMPACT | JSON_SORT_KEYS);
|
||||||
|
size_t signlen = acc.signature_length();
|
||||||
|
size_t ptrlen = olm::encode_base64_length(signlen);
|
||||||
|
std::unique_ptr<uint8_t[]> signature = std::make_unique<uint8_t[]>(ptrlen);
|
||||||
|
acc.sign(reinterpret_cast<const uint8_t*>(jsonStr), strlen(jsonStr), signature.get() + ptrlen - signlen, signlen);
|
||||||
|
free(jsonStr);
|
||||||
|
|
||||||
|
olm::encode_base64(signature.get() + ptrlen - signlen, signlen, signature.get());
|
||||||
|
|
||||||
|
json_t* signitem = json_object();
|
||||||
|
std::cout << std::string(reinterpret_cast<const char*>(signature.get()), ptrlen) << std::endl;
|
||||||
|
json_object_set_new(signitem, ("ed25519:" + getDeviceId()).c_str(), json_stringn(reinterpret_cast<const char*>(signature.get()), ptrlen));
|
||||||
|
json_t* signobj = json_object();
|
||||||
|
json_object_set_new(signobj, getUserId().c_str(), signitem);
|
||||||
|
json_object_set_new(json, "signatures", signobj);
|
||||||
|
}
|
||||||
|
json_t* Client::get_device_keys() {
|
||||||
|
json_t* device_keys = json_object();
|
||||||
|
json_t* algorithms = json_array();
|
||||||
|
json_array_append_new(algorithms, json_string("m.olm.v1.curve25519-aes-sha2"));
|
||||||
|
json_array_append_new(algorithms, json_string("m.megolm.v1.aes-sha2"));
|
||||||
|
json_object_set_new(device_keys, "algorithms", algorithms);
|
||||||
|
json_object_set_new(device_keys, "device_id", json_string(getDeviceId().c_str()));
|
||||||
|
json_object_set_new(device_keys, "user_id", json_string(getUserId().c_str()));
|
||||||
|
|
||||||
|
// Extract keys
|
||||||
|
size_t acclen = acc.get_identity_json_length();
|
||||||
|
std::unique_ptr<uint8_t[]> acckeys = std::make_unique<uint8_t[]>(acclen);
|
||||||
|
size_t bytes = acc.get_identity_json(acckeys.get(), acclen);
|
||||||
|
std::cout << "Parsing bytes" << std::endl;
|
||||||
|
json_error_t error;
|
||||||
|
sleep(5);
|
||||||
|
std::cout << "Heading into it..." << std::endl;
|
||||||
|
json_t* keys = json_loadb(reinterpret_cast<const char*>(acckeys.get()), bytes, 0, &error);
|
||||||
|
if (keys == nullptr) {
|
||||||
|
printf("error: on line %d at char %d: %s\n", error.line, error.column, error.text);
|
||||||
|
sleep(10);
|
||||||
|
}
|
||||||
|
std::cout << "Reloaded data" << std::endl;
|
||||||
|
std::cout << "Adding bits" << std::endl;
|
||||||
|
|
||||||
|
// Merge keys
|
||||||
|
json_object_set(device_keys, ("ed25519:" + getDeviceId()).c_str(), json_object_get(keys, "ed25519"));
|
||||||
|
json_object_set(device_keys, ("curve25519:" + getDeviceId()).c_str(), json_object_get(keys, "curve25519"));
|
||||||
|
json_decref(keys);
|
||||||
|
std::cout << "Finalizing" << std::endl;
|
||||||
|
return device_keys;
|
||||||
|
}
|
||||||
|
json_t* Client::get_fallback_keys() {
|
||||||
|
json_t* fallback_keys = json_object();
|
||||||
|
// Extract keys
|
||||||
|
size_t acclen = acc.get_unpublished_fallback_key_json_length();
|
||||||
|
auto acckeys = std::make_unique<uint8_t[]>(acclen);
|
||||||
|
size_t bytes = acc.get_unpublished_fallback_key_json(acckeys.get(), acclen);
|
||||||
|
json_t* keys = json_loadb(reinterpret_cast<const char*>(acckeys.get()), bytes, 0, nullptr);
|
||||||
|
json_t* keyobj = json_object_get(keys, "curve25519");
|
||||||
|
void* iter = json_object_iter(keyobj);
|
||||||
|
|
||||||
|
while (iter != nullptr) {
|
||||||
|
const char* keyid = json_object_iter_key(iter);
|
||||||
|
json_t* keyval = json_object_iter_value(iter);
|
||||||
|
json_t* tosign = json_object();
|
||||||
|
json_object_set(tosign, "key", keyval);
|
||||||
|
// object is fallback key
|
||||||
|
json_object_set_new(tosign, "fallback", json_true());
|
||||||
|
|
||||||
|
sign_json(tosign);
|
||||||
|
json_object_set(fallback_keys, (std::string("signed_curve25519:") + keyid).c_str(), tosign);
|
||||||
|
iter = json_object_iter_next(keyobj, iter);
|
||||||
|
}
|
||||||
|
json_decref(keys);
|
||||||
|
return fallback_keys;
|
||||||
|
}
|
||||||
|
json_t* Client::get_unpublished_otk() {
|
||||||
|
json_t* otk_keys = json_object();
|
||||||
|
// Extract keys
|
||||||
|
size_t acclen = acc.get_one_time_keys_json_length();
|
||||||
|
auto acckeys = std::make_unique<uint8_t[]>(acclen);
|
||||||
|
size_t bytes = acc.get_one_time_keys_json(acckeys.get(), acclen);
|
||||||
|
json_t* keys = json_loadb(reinterpret_cast<const char*>(acckeys.get()), bytes, 0, nullptr);
|
||||||
|
|
||||||
|
json_t* keyobj = json_object_get(keys, "curve25519");
|
||||||
|
void* iter = json_object_iter(keyobj);
|
||||||
|
|
||||||
|
while (iter != nullptr) {
|
||||||
|
const char* keyid = json_object_iter_key(iter);
|
||||||
|
json_t* keyval = json_object_iter_value(iter);
|
||||||
|
json_t* tosign = json_object();
|
||||||
|
json_object_set(tosign, "key", keyval);
|
||||||
|
|
||||||
|
sign_json(tosign);
|
||||||
|
json_object_set(otk_keys, (std::string("signed_curve25519:") + keyid).c_str(), tosign);
|
||||||
|
iter = json_object_iter_next(keyobj, iter);
|
||||||
|
}
|
||||||
|
json_decref(keys);
|
||||||
|
return otk_keys;
|
||||||
|
}
|
||||||
|
void Client::save_keys() {
|
||||||
|
size_t pacclen = olm::pickle_length(acc);
|
||||||
|
auto m = std::make_unique<uint8_t[]>(pacclen);
|
||||||
|
olm::pickle(m.get(), acc);
|
||||||
|
FILE* file = fopen("secret-keys", "w");
|
||||||
|
fwrite(m.get(), pacclen, 1, file);
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
void Client::upload_keys() { // Upload the keys ---
|
||||||
|
// Build device key json
|
||||||
|
json_t* upload_keys = json_object();
|
||||||
|
|
||||||
|
json_t* device_keys = get_device_keys();
|
||||||
|
std::cout << "Gathered device keys" << std::endl;
|
||||||
|
// Sign keys block
|
||||||
|
sign_json(device_keys);
|
||||||
|
std::cout << "Signed device keys" << std::endl;
|
||||||
|
json_object_set_new(upload_keys, "device_keys", device_keys);
|
||||||
|
|
||||||
|
json_t* fallback_keys = get_fallback_keys();
|
||||||
|
std::cout << "Signed fallback keys" << std::endl;
|
||||||
|
// fallback keys are already signed
|
||||||
|
json_object_set_new(upload_keys, "fallback_keys", fallback_keys);
|
||||||
|
|
||||||
|
// OTK keys
|
||||||
|
json_t* otk = get_unpublished_otk();
|
||||||
|
std::cout << "Signed OTK keys" << std::endl;
|
||||||
|
// OTK keys are already signed
|
||||||
|
json_object_set_new(upload_keys, "one_time_keys", otk);
|
||||||
|
|
||||||
|
uploadKeys(upload_keys);
|
||||||
|
std::cout << "Keys uploaded !" << std::endl;
|
||||||
|
print_json(upload_keys);
|
||||||
|
json_decref(upload_keys);
|
||||||
|
acc.mark_keys_as_published();
|
||||||
|
// Whether a key or not is published is saved, let's save again
|
||||||
|
save_keys();
|
||||||
|
}
|
||||||
|
void Client::start_encryption() {
|
||||||
|
// std::FILE* file = std::fopen("secret-keys", "r");
|
||||||
|
std::ifstream ifs("secret-keys", std::ios::binary | std::ios::ate);
|
||||||
|
if (!ifs.is_open()) {
|
||||||
|
std::cout << "No secret keys found, generating " << std::endl;
|
||||||
|
// Generate and save to file
|
||||||
|
// Device keys
|
||||||
|
generate_device_key();
|
||||||
|
std::cout << "Generated device key" << std::endl;
|
||||||
|
// One time keys
|
||||||
|
generate_otk();
|
||||||
|
std::cout << "Generated OTK key" << std::endl;
|
||||||
|
// Fallback keys
|
||||||
|
generate_fallback_key();
|
||||||
|
std::cout << "Generated fallback key" << std::endl;
|
||||||
|
upload_keys();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Load from file
|
||||||
|
std::ifstream::pos_type fsize = ifs.tellg();
|
||||||
|
if (fsize == -1) {
|
||||||
|
std::cout << "What." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto data = std::make_unique<uint8_t[]>(fsize);
|
||||||
|
ifs.seekg(0, std::ios::beg);
|
||||||
|
ifs.read(reinterpret_cast<char*>(data.get()), static_cast<std::streamsize>(fsize));
|
||||||
|
olm::unpickle(data.get(), data.get() + fsize, acc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}; // namespace Matrix
|
}; // namespace Matrix
|
||||||
|
|
Loading…
Reference in a new issue