Skip to content
Snippets Groups Projects
Commit eddd95a8 authored by Nicolas Werner's avatar Nicolas Werner
Browse files

Clean up export example

parent 79379f77
No related branches found
No related tags found
No related merge requests found
......@@ -23,6 +23,11 @@ namespace {
std::shared_ptr<Client> client = nullptr;
}
static void
export_backup(const mtx::secret_storage::AesHmacSha2KeyDescription &keyDesc,
const mtx::secret_storage::AesHmacSha2EncryptedData &secretData,
const mtx::responses::backup::KeysBackup &backup);
void
print_errors(RequestErr err)
{
......@@ -52,150 +57,142 @@ login_handler(const mtx::responses::Login &res, RequestErr err)
client->set_access_token(res.access_token);
client->backup_version([](const mtx::responses::backup::BackupVersion &backup_version,
RequestErr err) {
if (err) {
cerr << "Error fetching the backup version: ";
print_errors(err);
client->logout([](mtx::responses::Logout, RequestErr) {});
return;
}
client->backup_version(
[](const mtx::responses::backup::BackupVersion &backup_version, RequestErr err) {
if (err) {
cerr << "Error fetching the backup version: ";
print_errors(err);
client->logout([](mtx::responses::Logout, RequestErr) {});
return;
}
if (backup_version.algorithm != mtx::responses::backup::megolm_backup_v1) {
cerr << "Incompatible backup algorithm: " << backup_version.algorithm
<< "\n";
client->logout([](mtx::responses::Logout, RequestErr) {});
return;
}
client->room_keys(
backup_version.version,
[](mtx::responses::backup::KeysBackup backup, RequestErr err) {
if (err) {
cerr << "Error fetching the backup: ";
print_errors(err);
client->logout([](mtx::responses::Logout, RequestErr) {});
return;
}
client->secret_storage_secret(
mtx::secret_storage::secrets::megolm_backup_v1,
[backup](mtx::secret_storage::Secret secret, RequestErr err) {
if (err) {
cerr << "Error fetching the backup secret: ";
print_errors(err);
client->logout(
[](mtx::responses::Logout, RequestErr) {});
return;
}
if (backup_version.algorithm != mtx::responses::backup::megolm_backup_v1) {
cerr << "Incompatible backup algorithm: " << backup_version.algorithm
<< "\n";
client->logout([](mtx::responses::Logout, RequestErr) {});
return;
}
client->room_keys(
backup_version.version,
[](mtx::responses::backup::KeysBackup backup, RequestErr err) {
if (err) {
cerr << "Error fetching the backup: ";
print_errors(err);
client->logout([](mtx::responses::Logout, RequestErr) {});
return;
}
cout << nlohmann::json(backup).dump(4) << "\n";
client->secret_storage_secret(
mtx::secret_storage::secrets::megolm_backup_v1,
[backup](mtx::secret_storage::Secret secret, RequestErr err) {
if (err) {
cerr << "Error fetching the backup secret: ";
print_errors(err);
client->logout(
[](mtx::responses::Logout, RequestErr) {});
return;
}
if (secret.encrypted.size() != 1) {
cerr << "Only one encryption key for backup "
"supported. Aborting.\n";
return;
client->logout(
[](mtx::responses::Logout, RequestErr) {});
return;
}
client->secret_storage_key(
secret.encrypted.begin()->first,
[backup, secretData = secret.encrypted.begin()->second](
mtx::secret_storage::AesHmacSha2KeyDescription keyDesc,
RequestErr err) {
if (secret.encrypted.size() != 1) {
cerr << "Only one encryption key for backup "
"supported. Aborting.\n";
return;
client->logout(
[](mtx::responses::Logout, RequestErr) {});
if (err) {
cerr << "Error fetching the backup key "
"description: ";
print_errors(err);
return;
}
mtx::crypto::BinaryBuf decryptionKey;
if (keyDesc.passphrase) {
std::optional<mtx::crypto::BinaryBuf> temp;
do {
auto password = getpass(
"Enter Key Backup Password: ");
temp =
mtx::crypto::key_from_passphrase(
password, keyDesc);
} while (!temp);
decryptionKey = temp.value();
} else {
std::optional<mtx::crypto::BinaryBuf> temp;
do {
auto recoveryKey = getpass(
"Enter Key Backup Recovery Key: ");
temp =
mtx::crypto::key_from_recoverykey(
recoveryKey, keyDesc);
} while (!temp);
decryptionKey = temp.value();
}
// verify key
using namespace mtx::crypto;
auto decryptedSecret = decrypt(
secretData,
decryptionKey,
mtx::secret_storage::secrets::megolm_backup_v1);
if (decryptedSecret.empty()) {
cerr
<< "Failed to get backup key from secret";
return;
}
auto sessionDecryptionKey =
to_binary_buf(base642bin(decryptedSecret));
for (const auto &[room_id, backup_sessions] :
backup.rooms) {
for (const auto &[session_id, s] :
backup_sessions.sessions) {
// mtx::crypto::ExportedSession
// session;
// s.session_data;
try {
cout
<< CURVE25519_AES_SHA2_Decrypt(
s.session_data
.ciphertext,
sessionDecryptionKey,
s.session_data
.ephemeral,
s.session_data.mac)
<< std::endl;
} catch (
mtx::crypto::olm_exception &e) {
cerr << e.what() << "\n";
return;
}
}
}
// struct ExportedSession
//{
// std::map<std::string, std::string>
// sender_claimed_keys; // currently unused.
// std::vector<std::string>
// forwarding_curve25519_key_chain; //
// currently unused.
//
// std::string algorithm = MEGOLM_ALGO;
// std::string room_id;
// std::string sender_key;
// std::string session_id;
// std::string session_key;
//};
});
});
});
});
return;
}
client->secret_storage_key(
secret.encrypted.begin()->first,
[backup, secretData = secret.encrypted.begin()->second](
mtx::secret_storage::AesHmacSha2KeyDescription keyDesc,
RequestErr err) {
client->logout(
[](mtx::responses::Logout, RequestErr) {});
if (err) {
cerr << "Error fetching the backup key "
"description: ";
print_errors(err);
return;
}
export_backup(keyDesc, secretData, backup);
});
});
});
});
}
void
export_backup(const mtx::secret_storage::AesHmacSha2KeyDescription &keyDesc,
const mtx::secret_storage::AesHmacSha2EncryptedData &secretData,
const mtx::responses::backup::KeysBackup &backup)
{
mtx::crypto::BinaryBuf decryptionKey;
if (keyDesc.passphrase) {
std::optional<mtx::crypto::BinaryBuf> temp;
do {
auto password = getpass("Enter Key Backup Password: ");
temp = mtx::crypto::key_from_passphrase(password, keyDesc);
} while (!temp);
decryptionKey = temp.value();
} else {
std::optional<mtx::crypto::BinaryBuf> temp;
do {
auto recoveryKey = getpass("Enter Key Backup Recovery Key: ");
temp = mtx::crypto::key_from_recoverykey(recoveryKey, keyDesc);
} while (!temp);
decryptionKey = temp.value();
}
// verify key
using namespace mtx::crypto;
auto decryptedSecret =
decrypt(secretData, decryptionKey, mtx::secret_storage::secrets::megolm_backup_v1);
if (decryptedSecret.empty()) {
cerr << "Failed to get backup key from secret";
return;
}
auto sessionDecryptionKey = to_binary_buf(base642bin(decryptedSecret));
std::vector<ExportedSession> exported_sessions;
for (const auto &[room_id, backup_sessions] : backup.rooms) {
for (const auto &[session_id, s] : backup_sessions.sessions) {
try {
auto session =
decrypt_session(s.session_data, sessionDecryptionKey);
mtx::crypto::ExportedSession export_session{};
export_session.algorithm = session.algorithm;
export_session.sender_key = session.sender_key;
export_session.session_id = session_id;
export_session.room_id = room_id;
export_session.session_key = session.session_key;
export_session.sender_claimed_keys = session.sender_claimed_keys;
export_session.forwarding_curve25519_key_chain =
session.forwarding_curve25519_key_chain;
exported_sessions.push_back(std::move(export_session));
} catch (mtx::crypto::olm_exception &e) {
cerr << e.what() << "\n";
return;
}
}
}
auto encrypted_file = mtx::crypto::encrypt_exported_sessions(
{exported_sessions}, getpass("Encryption password for export file:"));
std::ofstream file;
file.open("exported_sessions.txt");
file << HEADER_LINE << "\n"
<< mtx::crypto::bin2base64(encrypted_file) << "\n"
<< TRAILER_LINE;
file.close();
}
int
......
......@@ -154,6 +154,29 @@ void
from_json(const nlohmann::json &obj, BackupVersion &response);
void
to_json(nlohmann::json &obj, const BackupVersion &response);
struct SessionData
{
//! Required. The end-to-end message encryption algorithm that the key is
// for. Must be m.megolm.v1.aes-sha2.
std::string algorithm;
// Required. Chain of Curve25519 keys through which this
// session was forwarded, via m.forwarded_room_key events.
std::vector<std::string> forwarding_curve25519_key_chain;
// Required. Unpadded base64-encoded device curve25519 key.
std::string sender_key;
// Required. A map from algorithm name (ed25519) to the identity
// key for the sending device.
std::map<std::string, std::string> sender_claimed_keys;
// Required. Unpadded base64-encoded session key in session-sharing format.
std::string session_key;
};
void
to_json(nlohmann::json &obj, const SessionData &desc);
void
from_json(const nlohmann::json &obj, SessionData &desc);
}
} // namespace responses
} // namespace mtx
......@@ -80,5 +80,6 @@ to_json(nlohmann::json &obj, const AesHmacSha2KeyDescription &desc);
void
from_json(const nlohmann::json &obj, AesHmacSha2KeyDescription &desc);
}
}
......@@ -4,6 +4,7 @@
#include <vector>
#include "mtx/common.hpp"
#include "mtx/responses/crypto.hpp"
#include "mtx/secret_storage.hpp"
namespace mtx {
......@@ -78,12 +79,17 @@ AES_CTR_256_Encrypt(const std::string plaintext, const BinaryBuf aes256Key, Bina
BinaryBuf
AES_CTR_256_Decrypt(const std::string ciphertext, const BinaryBuf aes256Key, BinaryBuf iv);
// copies ciphertext, as decryption modifies it.
std::string
CURVE25519_AES_SHA2_Decrypt(std::string base64_ciphertext,
const BinaryBuf &privateKey,
const std::string &ephemeral,
const std::string &mac);
mtx::responses::backup::SessionData
decrypt_session(const mtx::responses::backup::EncryptedSessionData &data,
const BinaryBuf &privateKey);
BinaryBuf
HMAC_SHA256(const BinaryBuf hmacKey, const BinaryBuf data);
......
......@@ -303,6 +303,15 @@ CURVE25519_AES_SHA2_Decrypt(std::string base64_ciphertext,
throw olm_exception(__func__, ctx.get());
}
mtx::responses::backup::SessionData
decrypt_session(const mtx::responses::backup::EncryptedSessionData &data,
const BinaryBuf &privateKey)
{
mtx::responses::backup::SessionData decrypted = json::parse(
CURVE25519_AES_SHA2_Decrypt(data.ciphertext, privateKey, data.ephemeral, data.mac));
return decrypted;
}
std::string
sha256(const std::string &data)
{
......
......@@ -109,6 +109,29 @@ to_json(nlohmann::json &obj, const BackupVersion &response)
obj["etag"] = response.etag;
obj["version"] = response.version;
}
void
to_json(nlohmann::json &obj, const SessionData &data)
{
obj["algorithm"] = data.algorithm;
obj["forwarding_curve25519_key_chain"] = data.forwarding_curve25519_key_chain;
obj["sender_key"] = data.sender_key;
obj["sender_claimed_keys"] = data.sender_claimed_keys;
obj["session_key"] = data.session_key;
}
void
from_json(const nlohmann::json &obj, SessionData &data)
{
data.algorithm = obj.at("algorithm");
data.forwarding_curve25519_key_chain =
obj.at("forwarding_curve25519_key_chain")
.get<decltype(data.forwarding_curve25519_key_chain)>();
data.sender_key = obj.at("sender_key");
data.sender_claimed_keys =
obj.at("sender_claimed_keys").get<decltype(data.sender_claimed_keys)>();
data.session_key = obj.at("session_key");
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment