Move encryption code over to SDK

This commit is contained in:
timoreo 2023-12-10 20:24:32 +01:00
parent 4955bbaa29
commit 0fc3f95c9b
Signed by: timoreo
GPG key ID: 121A72C3512BA288

View file

@ -2,12 +2,9 @@
#include <matrixclient.h> #include <matrixclient.h>
#include <memorystore.h> #include <memorystore.h>
#include <olm/olm.h> #include <olm/olm.h>
#include <cstring>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <olm/account.hh>
#include "olm/base64.hh"
#define PREFIX_DIRECTORY "./matrix-storage" #define PREFIX_DIRECTORY "./matrix-storage"
#define TOKEN_FILENAME "token" #define TOKEN_FILENAME "token"
@ -18,11 +15,6 @@ class Store : public Matrix::Store {
void setFilterId(std::string filterId) override {} void setFilterId(std::string filterId) override {}
std::string getFilterId() override { return ""; } std::string getFilterId() override { return ""; }
}; };
void print_json(json_t *json){
char* data = json_dumps(json, 0);
puts(data);
free(data);
}
PrintConsole* bottom = new PrintConsole; PrintConsole* bottom = new PrintConsole;
std::string ask_for_pass() { std::string ask_for_pass() {
@ -35,202 +27,6 @@ std::string ask_for_pass() {
swkbdInputText(&swkbd, buf, sizeof(buf)); swkbdInputText(&swkbd, buf, sizeof(buf));
return buf; return buf;
} }
void generate_otk(olm::Account& acc, 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 generate_otk(olm::Account& acc) {
size_t otkcount = acc.max_number_of_one_time_keys() / 2;
generate_otk(acc, otkcount);
}
void generate_device_key(olm::Account& acc) {
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 generate_fallback_key(olm::Account& acc) {
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 sign_json(Matrix::Client& client, olm::Account& acc, 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:" + client.getDeviceId()).c_str(), json_stringn(reinterpret_cast<const char*>(signature.get()), ptrlen));
json_t* signobj = json_object();
json_object_set_new(signobj, client.getUserId().c_str(), signitem);
json_object_set_new(json, "signatures", signobj);
}
json_t* get_device_keys(Matrix::Client& client, olm::Account& acc) {
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(client.getDeviceId().c_str()));
json_object_set_new(device_keys, "user_id", json_string(client.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:" + client.getDeviceId()).c_str(), json_object_get(keys, "ed25519"));
json_object_set(device_keys, ("curve25519:" + client.getDeviceId()).c_str(), json_object_get(keys, "curve25519"));
json_decref(keys);
std::cout << "Finalizing" << std::endl;
return device_keys;
}
json_t* get_fallback_keys(Matrix::Client& client, olm::Account& acc) {
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(client, acc, 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* get_unpublished_otk(Matrix::Client& client, olm::Account& acc) {
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(client, acc, 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 save_keys(olm::Account& acc) {
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 upload_keys(Matrix::Client& client, olm::Account& acc) { // Upload the keys ---
// Build device key json
json_t* upload_keys = json_object();
json_t* device_keys = get_device_keys(client, acc);
std::cout << "Gathered device keys" << std::endl;
// Sign keys block
sign_json(client, acc, 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(client, acc);
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(client, acc);
std::cout << "Signed OTK keys" << std::endl;
// OTK keys are already signed
json_object_set_new(upload_keys, "one_time_keys", otk);
client.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(acc);
}
void load_account(Matrix::Client& client, olm::Account& acc) {
// 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(acc);
std::cout << "Generated device key" << std::endl;
// One time keys
generate_otk(acc);
std::cout << "Generated OTK key" << std::endl;
// Fallback keys
generate_fallback_key(acc);
std::cout << "Generated fallback key" << std::endl;
upload_keys(client, acc);
} 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);
}
}
int main() { int main() {
fsInit(); fsInit();
@ -244,7 +40,6 @@ int main() {
// Matrix::MemoryStore store{}; // Matrix::MemoryStore store{};
Matrix::Client client("https://matrix.timoreo.fr", "", nullptr); Matrix::Client client("https://matrix.timoreo.fr", "", nullptr);
auto acc = std::make_unique<olm::Account>();
while (aptMainLoop()) { while (aptMainLoop()) {
gspWaitForVBlank(); gspWaitForVBlank();
hidScanInput(); hidScanInput();
@ -282,7 +77,7 @@ int main() {
} }
std::cout << "Logged in as " << userid << std::endl; std::cout << "Logged in as " << userid << std::endl;
// Load encryption here // Load encryption here
load_account(client, *acc); client.start_encryption();
client.setRoomInfoCallback([](std::string roomId, Matrix::RoomInfo info) { client.setRoomInfoCallback([](std::string roomId, Matrix::RoomInfo info) {
consoleSelect(bottom); consoleSelect(bottom);
printf("Joined room %s named %s\n", roomId.c_str(), info.name.c_str()); printf("Joined room %s named %s\n", roomId.c_str(), info.name.c_str());