Fix : various memory errors + reformat to be better C++ code

This commit is contained in:
timoreo 2023-12-09 23:35:38 +01:00
parent c2d0114aec
commit c9dfadb1b6
Signed by: timoreo
GPG key ID: 121A72C3512BA288
2 changed files with 77 additions and 67 deletions

View file

@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.24)
project(matrix-3ds-client) project(matrix-3ds-client)
# for compiling a part of the pica asm # for compiling a part of the pica asm
enable_language(ASM) enable_language(ASM)
add_compile_options(-O2 -Wall -Wextra -pedantic -Wno-unused-parameter)
add_subdirectory(matrix-3ds-sdk) add_subdirectory(matrix-3ds-sdk)
add_subdirectory(olm) add_subdirectory(olm)

View file

@ -1,7 +1,7 @@
#include <3ds.h> #include <3ds.h>
#include <matrixclient.h> #include <matrixclient.h>
#include <olm/base64.h>
#include <olm/olm.h> #include <olm/olm.h>
#include <olm/account.hh>
#include <cstring> #include <cstring>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
@ -22,7 +22,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 ""; }
}; };
std::string ask_for_pass();
PrintConsole* bottom = new PrintConsole; PrintConsole* bottom = new PrintConsole;
std::string ask_for_pass() { std::string ask_for_pass() {
@ -31,50 +30,50 @@ std::string ask_for_pass() {
swkbdSetValidation(&swkbd, SWKBD_NOTEMPTY_NOTBLANK, 0, 0); swkbdSetValidation(&swkbd, SWKBD_NOTEMPTY_NOTBLANK, 0, 0);
swkbdSetPasswordMode(&swkbd, SWKBD_PASSWORD_HIDE_DELAY); swkbdSetPasswordMode(&swkbd, SWKBD_PASSWORD_HIDE_DELAY);
swkbdSetHintText(&swkbd, "Enter password"); swkbdSetHintText(&swkbd, "Enter password");
char buf[256]; char buf[256]{0};
swkbdInputText(&swkbd, buf, sizeof(buf)); swkbdInputText(&swkbd, buf, sizeof(buf));
return buf; return buf;
} }
void generate_otk(OlmAccount* acc, size_t otkcount) { void generate_otk(olm::Account& acc, size_t otkcount) {
size_t len = olm_account_generate_one_time_keys_random_length(acc, otkcount); size_t len = acc.generate_one_time_keys_random_length(otkcount);
std::unique_ptr<char> otkrandom = std::make_unique<char>(len); std::unique_ptr<uint8_t[]> otkrandom = std::make_unique<uint8_t[]>(len);
PS_GenerateRandomBytes(otkrandom.get(), len); PS_GenerateRandomBytes(otkrandom.get(), len);
olm_account_generate_one_time_keys(acc, otkcount, otkrandom.get(), len); acc.generate_one_time_keys(otkcount, otkrandom.get(), len);
} }
void generate_otk(OlmAccount* acc){ void generate_otk(olm::Account& acc){
size_t otkcount = olm_account_max_number_of_one_time_keys(acc)/2; size_t otkcount = acc.max_number_of_one_time_keys()/2;
generate_otk(acc, otkcount); generate_otk(acc, otkcount);
} }
void generate_device_key(OlmAccount* acc) { void generate_device_key(olm::Account& acc) {
size_t len = olm_create_account_random_length(acc); size_t len = acc.new_account_random_length();
std::unique_ptr<char> random = std::make_unique<char>(len); std::unique_ptr<uint8_t[]> random = std::make_unique<uint8_t[]>(len);
PS_GenerateRandomBytes(random.get(), len); PS_GenerateRandomBytes(random.get(), len);
olm_create_account(acc, random.get(), len); acc.new_account(random.get(), len);
} }
void generate_fallback_key(OlmAccount* acc) { void generate_fallback_key(olm::Account& acc) {
size_t len = olm_account_generate_fallback_key_random_length(acc); size_t len = acc.generate_fallback_key_random_length();
std::unique_ptr<char> random = std::make_unique<char>(len); std::unique_ptr<uint8_t[]> random = std::make_unique<uint8_t[]>(len);
PS_GenerateRandomBytes(random.get(), len); PS_GenerateRandomBytes(random.get(), len);
olm_account_generate_fallback_key(acc, random.get(), len); acc.generate_fallback_key(random.get(), len);
} }
// Make sure to remove any unsigned and signatures block before doing this ! // Make sure to remove any unsigned and signatures block before doing this !
void sign_json(Matrix::Client& client, OlmAccount* acc, json_t* json) { void sign_json(Matrix::Client& client, olm::Account& acc, json_t* json) {
char* jsonStr = json_dumps(json, JSON_COMPACT | JSON_SORT_KEYS); char* jsonStr = json_dumps(json, JSON_COMPACT | JSON_SORT_KEYS);
size_t signlen = olm_account_signature_length(acc); size_t signlen = acc.signature_length();
char* signature = reinterpret_cast<char*>(malloc(signlen)); std::string signature(signlen, '\0');
olm_account_sign(acc, jsonStr, strlen(jsonStr), signature, signlen); acc.sign(reinterpret_cast<const uint8_t*>(jsonStr), strlen(jsonStr), reinterpret_cast<uint8_t*>(signature.data()), signlen);
free(jsonStr); free(jsonStr);
json_t * signitem = json_object(); json_t * signitem = json_object();
json_object_set(signitem, ("ed25519:" + client.getDeviceId()).c_str(), json_stringn(signature, signlen)); json_object_set(signitem, ("ed25519:" + client.getDeviceId()).c_str(), json_stringn(signature.data(), signlen));
json_t * signobj = json_object(); json_t * signobj = json_object();
json_object_set(signobj, client.getUserId().c_str(), signitem); json_object_set(signobj, client.getUserId().c_str(), signitem);
json_object_set(json, "signatures", signobj); json_object_set(json, "signatures", signobj);
} }
json_t* get_device_keys(Matrix::Client& client, OlmAccount* acc) { json_t* get_device_keys(Matrix::Client& client, olm::Account& acc) {
json_t * device_keys = json_object(); json_t * device_keys = json_object();
json_t * algorithms = json_array(); 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.olm.v1.curve25519-aes-sha2"));
@ -84,26 +83,35 @@ json_t* get_device_keys(Matrix::Client& client, OlmAccount* acc) {
json_object_set_new(device_keys, "user_id", json_string(client.getUserId().c_str())); json_object_set_new(device_keys, "user_id", json_string(client.getUserId().c_str()));
// Extract keys // Extract keys
size_t acclen = olm_account_identity_keys_length(acc); size_t acclen = acc.get_identity_json_length();
auto acckeys = reinterpret_cast<char *>(malloc(acclen)); std::unique_ptr<uint8_t[]> acckeys = std::make_unique<uint8_t[]>(acclen);
olm_account_identity_keys(acc, acckeys, acclen); size_t bytes = acc.get_identity_json(acckeys.get(), acclen);
json_t * keys = json_loads(acckeys, 0, nullptr); std::cout << "Parsing bytes" << std::endl;
free(acckeys); 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 // Merge keys
json_object_set_new(device_keys, ("ed25519:" + client.getDeviceId()).c_str(), json_object_get(keys, "ed25519")); json_object_set_new(device_keys, ("ed25519:" + client.getDeviceId()).c_str(), json_object_get(keys, "ed25519"));
json_object_set_new(device_keys, ("curve25519:" + client.getDeviceId()).c_str(), json_object_get(keys, "curve25519")); json_object_set_new(device_keys, ("curve25519:" + client.getDeviceId()).c_str(), json_object_get(keys, "curve25519"));
std::cout << "Finalizing" << std::endl;
json_decref(keys); json_decref(keys);
return device_keys; return device_keys;
} }
json_t* get_fallback_keys(Matrix::Client& client, OlmAccount* acc) { json_t* get_fallback_keys(Matrix::Client& client, olm::Account& acc) {
json_t * fallback_keys = json_object(); json_t * fallback_keys = json_object();
// Extract keys // Extract keys
size_t acclen = olm_account_unpublished_fallback_key_length(acc); size_t acclen = acc.get_unpublished_fallback_key_json_length();
auto acckeys = reinterpret_cast<char *>(malloc(acclen)); auto acckeys = std::make_unique<uint8_t[]>(acclen);
olm_account_unpublished_fallback_key(acc, acckeys, acclen); size_t bytes = acc.get_unpublished_fallback_key_json(acckeys.get(), acclen);
json_t * keys = json_loads(acckeys, 0, nullptr); json_t * keys = json_loadb(reinterpret_cast<const char*>(acckeys.get()), bytes, 0, nullptr);
free(acckeys);
json_t* keyobj = json_object_get(keys, "curve25519"); json_t* keyobj = json_object_get(keys, "curve25519");
void* iter = json_object_iter(keyobj); void* iter = json_object_iter(keyobj);
@ -123,14 +131,13 @@ json_t* get_fallback_keys(Matrix::Client& client, OlmAccount* acc) {
return fallback_keys; return fallback_keys;
} }
json_t* get_unpublished_otk(Matrix::Client& client, OlmAccount* acc) { json_t* get_unpublished_otk(Matrix::Client& client, olm::Account& acc) {
json_t * otk_keys = json_object(); json_t * otk_keys = json_object();
// Extract keys // Extract keys
size_t acclen = olm_account_one_time_keys_length(acc); size_t acclen = acc.get_one_time_keys_json_length();
auto acckeys = reinterpret_cast<char *>(malloc(acclen)); auto acckeys = std::make_unique<uint8_t []>(acclen);
olm_account_one_time_keys(acc, acckeys, acclen); size_t bytes = acc.get_one_time_keys_json(acckeys.get(), acclen);
json_t * keys = json_loads(acckeys, 0, nullptr); json_t * keys = json_loadb(reinterpret_cast<const char*>(acckeys.get()), bytes, 0, nullptr);
free(acckeys);
json_t* keyobj = json_object_get(keys, "curve25519"); json_t* keyobj = json_object_get(keys, "curve25519");
void* iter = json_object_iter(keyobj); void* iter = json_object_iter(keyobj);
@ -149,55 +156,60 @@ json_t* get_unpublished_otk(Matrix::Client& client, OlmAccount* acc) {
return otk_keys; return otk_keys;
} }
void save_keys(OlmAccount* acc) { void save_keys(olm::Account& acc) {
size_t pacclen = olm_pickle_account_length(acc); size_t pacclen = olm::pickle_length(acc);
auto m = reinterpret_cast<uint8_t *>(malloc(pacclen)); auto m = std::make_unique<uint8_t []>(pacclen);
olm_pickle_account(acc, nullptr, 0, m, pacclen); olm::pickle(m.get(), acc);
pacclen = _olm_decode_base64(m, pacclen, m);
FILE* file = fopen("secret-keys", "w"); FILE* file = fopen("secret-keys", "w");
fwrite(m, pacclen, 1, file); fwrite(m.get(), pacclen, 1, file);
free(m);
fclose(file); fclose(file);
} }
OlmAccount* load_account(Matrix::Client& client){
auto* acc = static_cast<OlmAccount*>(malloc(olm_account_size()));
olm_account(acc);
std::filebuf filestorage;
void load_account(Matrix::Client& client, olm::Account& acc){
// std::FILE* file = std::fopen("secret-keys", "r"); // std::FILE* file = std::fopen("secret-keys", "r");
std::ifstream ifs("secret-keys", std::ios::binary|std::ios::ate); std::ifstream ifs("secret-keys", std::ios::binary|std::ios::ate);
if (ifs.is_open()) { if (!ifs.is_open()) {
std::cout << "No secret keys found, generating " << std::endl;
// Generate and save to file // Generate and save to file
// Device keys // Device keys
generate_device_key(acc); generate_device_key(acc);
std::cout << "Generated device key" << std::endl;
// One time keys // One time keys
generate_otk(acc); generate_otk(acc);
std::cout << "Generated OTK key" << std::endl;
// Fallback keys // Fallback keys
generate_fallback_key(acc); generate_fallback_key(acc);
std::cout << "Generated fallback key" << std::endl;
// Convert to pickled format // Convert to pickled format
save_keys(acc); // save_keys(acc);
std::cout << "Saved keys postgen." << std::endl;
// Upload the keys --- // Upload the keys ---
// Build device key json // Build device key json
json_t * upload_keys = json_object(); json_t * upload_keys = json_object();
json_t* device_keys = get_device_keys(client, acc); json_t* device_keys = get_device_keys(client, acc);
std::cout << "Gathered device keys" << std::endl;
// Sign keys block // Sign keys block
sign_json(client, acc, device_keys); sign_json(client, acc, device_keys);
std::cout << "Signed device keys" << std::endl;
json_object_set(upload_keys, "device_keys", device_keys); json_object_set(upload_keys, "device_keys", device_keys);
json_t* fallback_keys = get_fallback_keys(client, acc); json_t* fallback_keys = get_fallback_keys(client, acc);
std::cout << "Signed fallback keys" << std::endl;
// fallback keys are already signed // fallback keys are already signed
json_object_set(upload_keys, "fallback_keys", fallback_keys); json_object_set(upload_keys, "fallback_keys", fallback_keys);
// OTK keys // OTK keys
json_t* otk = get_unpublished_otk(client, acc); json_t* otk = get_unpublished_otk(client, acc);
std::cout << "Signed OTK keys" << std::endl;
// OTK keys are already signed // OTK keys are already signed
json_object_set(upload_keys, "one_time_keys", otk); json_object_set(upload_keys, "one_time_keys", otk);
client.uploadKeys(upload_keys); client.uploadKeys(upload_keys);
std::cout << "Keys uploaded !" << std::endl;
json_decref(upload_keys); json_decref(upload_keys);
olm_account_mark_keys_as_published(acc); acc.mark_keys_as_published();
// Whether a key or not is published is saved, let's save again // Whether a key or not is published is saved, let's save again
save_keys(acc); save_keys(acc);
} else { } else {
@ -205,16 +217,13 @@ OlmAccount* load_account(Matrix::Client& client){
std::ifstream::pos_type fsize = ifs.tellg(); std::ifstream::pos_type fsize = ifs.tellg();
if(fsize == -1){ if(fsize == -1){
std::cout << "What." << std::endl; std::cout << "What." << std::endl;
return acc; return;
} }
size_t overhead = fsize/4; auto data = std::make_unique<uint8_t []>(fsize);
auto data = reinterpret_cast<uint8_t*>(malloc(overhead + fsize));
ifs.seekg(0, std::ios::beg); ifs.seekg(0, std::ios::beg);
ifs.read(reinterpret_cast<char*>(overhead + data), static_cast<std::streamsize>(fsize)); ifs.read(reinterpret_cast<char*>(data.get()), static_cast<std::streamsize>(fsize));
_olm_encode_base64(overhead + data, fsize, data); olm::unpickle(data.get(),data.get() + fsize, acc);
olm_unpickle_account(acc, nullptr, 0, data, overhead + fsize);
} }
return acc;
} }
@ -224,12 +233,13 @@ int main() {
consoleInit(GFX_BOTTOM, bottom); consoleInit(GFX_BOTTOM, bottom);
uint8_t major, minor, patch; uint8_t major, minor, patch;
olm_get_library_version(&major, &minor, &patch); olm_get_library_version(&major, &minor, &patch);
std::cout << "Using olm " << major << "." << minor << "." << patch << std::endl; std::cout << "Using olm " << std::to_string(major) << "." << std::to_string(minor) << "." << std::to_string(patch) << std::endl;
std::filesystem::create_directories(PREFIX_DIRECTORY); std::filesystem::create_directories(PREFIX_DIRECTORY);
chdir(PREFIX_DIRECTORY); chdir(PREFIX_DIRECTORY);
Matrix::MemoryStore store = Matrix::MemoryStore();
Matrix::Client client("https://matrix.timoreo.fr", "", &store); // Matrix::MemoryStore store{};
OlmAccount* acc; Matrix::Client client("https://matrix.timoreo.fr", "", nullptr);
auto acc = std::make_unique<olm::Account>();
while (aptMainLoop()) { while (aptMainLoop()) {
gspWaitForVBlank(); gspWaitForVBlank();
hidScanInput(); hidScanInput();
@ -267,7 +277,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
acc = load_account(client); load_account(client, *acc);
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());
@ -284,7 +294,6 @@ int main() {
} }
client.stopSyncLoop(); client.stopSyncLoop();
// DO NOT LOGOUT, KEEP ENCRYPTION KEYS // DO NOT LOGOUT, KEEP ENCRYPTION KEYS
free(acc);
gfxExit(); gfxExit();
fsExit(); fsExit();
} }