Sorry this is a huge commit, this actually includes a ton of stuff. Text color is now readable, multiple accounts are supported alongside end-to-end encryption but no cross-signing yet :-) There's also a whole lot of other small changes, such as choosing the server you want to request a room directory from.
337 lines
11 KiB
C++
Executable file
337 lines
11 KiB
C++
Executable file
#include "encryption.h"
|
|
#include <stdlib.h>
|
|
#include <QDebug>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <QJsonDocument>
|
|
#include <cstring>
|
|
|
|
void Encryption::createNewDeviceKeys() {
|
|
initAccount();
|
|
|
|
// create account
|
|
auto length = olm_create_account_random_length(account);
|
|
|
|
void* memory = malloc(length);
|
|
|
|
int fd = open("/dev/random", O_RDONLY);
|
|
read(fd, memory, length);
|
|
|
|
olm_create_account(account, memory, length);
|
|
qDebug() << olm_account_last_error(account);
|
|
|
|
qDebug() << "Created new device keys!";
|
|
|
|
// retrieve identity keys
|
|
length = olm_account_identity_keys_length(account);
|
|
|
|
char* identity_memory = (char*)malloc(length + 1);
|
|
identity_memory[length] = '\0';
|
|
|
|
olm_account_identity_keys(account, identity_memory, length);
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson((char*)identity_memory);
|
|
identityKey = doc.object();
|
|
|
|
qDebug() << "identity keys: " << (char*)identity_memory;
|
|
qDebug() << "identity keys (parsed): " << identityKey;
|
|
|
|
}
|
|
|
|
QString Encryption::saveDeviceKeys() {
|
|
auto length = olm_pickle_account_length(account);
|
|
char* identity_memory = (char*)malloc(length + 1);
|
|
identity_memory[length] = '\0';
|
|
|
|
auto err = olm_pickle_account(account, "secret_key", 10, identity_memory, length);
|
|
qDebug() << olm_account_last_error(account);
|
|
qDebug() << err << " = " << olm_error();
|
|
|
|
qDebug() << "Save: " << identity_memory;
|
|
|
|
return identity_memory;
|
|
}
|
|
|
|
void Encryption::loadDeviceKeys(QString bytes) {
|
|
initAccount();
|
|
|
|
qDebug() << "load: " << bytes;
|
|
|
|
auto length = bytes.length();
|
|
|
|
std::string key = bytes.toStdString();
|
|
|
|
olm_unpickle_account(account, "secret_key", 10, key.data(), key.length());
|
|
qDebug() << olm_account_last_error(account);
|
|
|
|
length = olm_account_identity_keys_length(account);
|
|
char* identity_memory = (char*)malloc(length + 1);
|
|
identity_memory[length] = '\0';
|
|
|
|
olm_account_identity_keys(account, identity_memory, length);
|
|
|
|
qDebug() << identity_memory;
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(identity_memory);
|
|
qDebug() << doc;
|
|
|
|
identityKey = doc.object();
|
|
}
|
|
|
|
QJsonObject Encryption::generateOneTimeKeys(int number_of_keys) {
|
|
int fd = open("/dev/random", O_RDONLY);
|
|
|
|
// generate random data
|
|
auto length = olm_account_generate_one_time_keys_random_length(account, number_of_keys);
|
|
auto memory = malloc(length);
|
|
read(fd, memory, length);
|
|
|
|
olm_account_generate_one_time_keys(account, number_of_keys, memory, length);
|
|
|
|
// retrieve one time keys
|
|
length = olm_account_one_time_keys_length(account);
|
|
memory = malloc(length);
|
|
olm_account_one_time_keys(account, memory, length);
|
|
|
|
olm_account_mark_keys_as_published(account);
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson((char*)memory);
|
|
return doc.object();
|
|
}
|
|
|
|
int Encryption::getRecommendedNumberOfOneTimeKeys() {
|
|
return olm_account_max_number_of_one_time_keys(account) / 2;
|
|
}
|
|
|
|
QString Encryption::signMessage(QString message) {
|
|
auto length = olm_account_signature_length(account);
|
|
|
|
void* memory = malloc(length);
|
|
|
|
olm_account_sign(
|
|
account,
|
|
message.data(), message.length(),
|
|
memory, length
|
|
);
|
|
|
|
qDebug() << "Signed: " << (char*)memory;
|
|
|
|
return (char*)memory;
|
|
}
|
|
|
|
void Encryption::initAccount() {
|
|
void* memory = malloc(olm_account_size());
|
|
account = olm_account(memory);
|
|
}
|
|
|
|
OlmOutboundGroupSession* Encryption::beginOutboundSession() {
|
|
void* outboundMemory = malloc(olm_outbound_group_session_size());
|
|
auto outboundSession = olm_outbound_group_session(outboundMemory);
|
|
|
|
auto length = olm_init_outbound_group_session_random_length(outboundSession);
|
|
|
|
void* memory = malloc(length);
|
|
|
|
int fd = open("/dev/random", O_RDONLY);
|
|
read(fd, memory, length);
|
|
|
|
olm_init_outbound_group_session(outboundSession, (uint8_t*)memory, length);
|
|
|
|
return outboundSession;
|
|
}
|
|
|
|
std::string Encryption::getGroupSessionId(OlmOutboundGroupSession* session) {
|
|
auto encryptedLength = olm_outbound_group_session_id_length(session);
|
|
char* encryptedMemory = (char*)malloc(encryptedLength + 1);
|
|
|
|
olm_outbound_group_session_id(session, (uint8_t*)encryptedMemory, encryptedLength);
|
|
|
|
return encryptedMemory;
|
|
}
|
|
|
|
std::string Encryption::getGroupSessionKey(OlmOutboundGroupSession* session) {
|
|
auto encryptedLength = olm_outbound_group_session_key_length(session);
|
|
char* encryptedMemory = (char*)malloc(encryptedLength + 1);
|
|
|
|
olm_outbound_group_session_key(session, (uint8_t*)encryptedMemory, encryptedLength);
|
|
|
|
return encryptedMemory;
|
|
}
|
|
|
|
OlmSession* Encryption::beginOutboundOlmSession(std::string identityKey, std::string oneTimeKey) {
|
|
void* outboundMemory = malloc(olm_session_size());
|
|
auto outboundSession = olm_session(outboundMemory);
|
|
|
|
auto length = olm_create_outbound_session_random_length(outboundSession);
|
|
|
|
void* memory = malloc(length);
|
|
|
|
int fd = open("/dev/random", O_RDONLY);
|
|
read(fd, memory, length);
|
|
|
|
olm_create_outbound_session(outboundSession, account, identityKey.data(), identityKey.length(), oneTimeKey.data(), oneTimeKey.length(), (uint8_t*)memory, length);
|
|
//qDebug() << "ERR: " << olm_session_last_error(outboundSession);
|
|
|
|
return outboundSession;
|
|
|
|
/*size_t olm_create_outbound_session(
|
|
OlmSession * session,
|
|
OlmAccount * account,
|
|
void const * their_identity_key, size_t their_identity_key_length,
|
|
void const * their_one_time_key, size_t their_one_time_key_length,
|
|
void * random, size_t random_length
|
|
);*/
|
|
|
|
}
|
|
|
|
std::string Encryption::getSessionId(OlmSession* session) {
|
|
auto length = olm_session_id_length(session);
|
|
char* memory = (char*)malloc(length + 1);
|
|
memory[length] = '\0';
|
|
|
|
/** An identifier for this session. Will be the same for both ends of the
|
|
* conversation. If the id buffer is too small then olm_session_last_error()
|
|
* will be "OUTPUT_BUFFER_TOO_SMALL". */
|
|
olm_session_id(
|
|
session,
|
|
memory, length
|
|
);
|
|
|
|
return memory;
|
|
}
|
|
|
|
std::string Encryption::encrypt(OlmSession* session, std::string message) {
|
|
auto length = olm_encrypt_random_length(session);
|
|
|
|
void* memory = malloc(length);
|
|
|
|
int fd = open("/dev/random", O_RDONLY);
|
|
read(fd, memory, length);
|
|
|
|
auto encryptedLength = olm_encrypt_message_length(session, message.length());
|
|
char* encryptedMemory = (char*)malloc(encryptedLength + 1);
|
|
|
|
olm_encrypt(session, message.data(), message.length(), memory, length, encryptedMemory, encryptedLength);
|
|
|
|
return encryptedMemory;
|
|
}
|
|
|
|
std::string Encryption::encryptGroup(OlmOutboundGroupSession* session, std::string message) {
|
|
auto encryptedLength = olm_group_encrypt_message_length(session, message.length());
|
|
char* encryptedMemory = (char*)malloc(encryptedLength + 1);
|
|
|
|
olm_group_encrypt(session, (uint8_t*)message.data(), message.length(), (uint8_t*)encryptedMemory, encryptedLength);
|
|
|
|
return encryptedMemory;
|
|
}
|
|
|
|
OlmSession* Encryption::createInboundSession(std::string senderKey, std::string body) {
|
|
void* inboundMemory = malloc(olm_session_size());
|
|
auto inboundSession = olm_session(inboundMemory);
|
|
|
|
olm_create_inbound_session_from(inboundSession, account, (void*)senderKey.c_str(), senderKey.length(), (void*)body.c_str(), body.length());
|
|
|
|
return inboundSession;
|
|
}
|
|
|
|
std::vector<std::uint8_t> Encryption::decrypt(OlmSession* session, int msgType, std::string cipherText) {
|
|
/*std::string maxPlaintextLengthBuffer = cipherText;
|
|
|
|
size_t maxPlaintextLength = olm_decrypt_max_plaintext_length(session, msgType, (void*)maxPlaintextLengthBuffer.data(), maxPlaintextLengthBuffer.length());;
|
|
qDebug() << "THE ERROR YOU ARE LOOKING FOR " << olm_session_last_error(session);
|
|
if(maxPlaintextLength == olm_error())
|
|
return "";
|
|
|
|
char* plaintext = new char[maxPlaintextLength];
|
|
//plaintext[maxPlaintextLength] = '\0';
|
|
memset(plaintext, '\0', maxPlaintextLength);
|
|
int size = olm_decrypt(session, msgType, (void*)cipherText.data(), cipherText.length(), (void*)plaintext, maxPlaintextLength);
|
|
//plaintext[size] = '\0';
|
|
|
|
plaintext[size + 1] = '\0';
|
|
|
|
return plaintext;*/
|
|
|
|
// because olm_group_decrypt_max_plaintext_length DESTROYS the buffer, why?
|
|
auto tmp_plaintext_buffer = std::vector<std::uint8_t>(cipherText.size());
|
|
std::copy(cipherText.begin(), cipherText.end(), tmp_plaintext_buffer.begin());
|
|
|
|
// create the result buffer
|
|
size_t length = olm_decrypt_max_plaintext_length(session, msgType, tmp_plaintext_buffer.data(), tmp_plaintext_buffer.size());
|
|
if(length == olm_error())
|
|
return {};
|
|
|
|
auto result_buffer = std::vector<std::uint8_t>(length);
|
|
|
|
// now create another buffer for olm_group_decrypt
|
|
auto tmp_buffer = std::vector<std::uint8_t>(cipherText.size());
|
|
std::copy(cipherText.begin(), cipherText.end(), tmp_buffer.begin());
|
|
|
|
auto size = olm_decrypt(session, msgType, tmp_buffer.data(), tmp_buffer.size(), result_buffer.data(), result_buffer.size());
|
|
if(size == olm_error())
|
|
return {};
|
|
|
|
auto output = std::vector<std::uint8_t>(size);
|
|
std::memcpy(output.data(), result_buffer.data(), size);
|
|
|
|
return output;
|
|
}
|
|
|
|
QString Encryption::saveSession(OlmOutboundGroupSession* session) {
|
|
auto length = olm_pickle_outbound_group_session_length(session);
|
|
char* identity_memory = (char*)malloc(length + 1);
|
|
identity_memory[length] = '\0';
|
|
|
|
auto err = olm_pickle_outbound_group_session(session, "secret_key", 10, identity_memory, length);
|
|
|
|
return identity_memory;
|
|
}
|
|
|
|
OlmOutboundGroupSession* Encryption::loadSession(QString bytes) {
|
|
void* outboundMemory = malloc(olm_outbound_group_session_size());
|
|
auto outboundSession = olm_outbound_group_session(outboundMemory);
|
|
|
|
auto length = bytes.length();
|
|
|
|
std::string key = bytes.toStdString();
|
|
|
|
olm_unpickle_outbound_group_session(outboundSession, "secret_key", 10, (void*)key.data(), key.length());
|
|
|
|
return outboundSession;
|
|
}
|
|
|
|
OlmInboundGroupSession* Encryption::beginInboundSession(std::string sessionKey) {
|
|
void* inboundMemory = malloc(olm_inbound_group_session_size());
|
|
auto inboundSession = olm_inbound_group_session(inboundMemory);
|
|
|
|
olm_init_inbound_group_session(inboundSession, (uint8_t*)sessionKey.data(), sessionKey.size());
|
|
|
|
return inboundSession;
|
|
}
|
|
|
|
std::vector<std::uint8_t> Encryption::decrypt(OlmInboundGroupSession* session, std::string cipherText) {
|
|
// because olm_group_decrypt_max_plaintext_length DESTROYS the buffer, why?
|
|
auto tmp_plaintext_buffer = std::vector<std::uint8_t>(cipherText.size());
|
|
std::copy(cipherText.begin(), cipherText.end(), tmp_plaintext_buffer.begin());
|
|
|
|
// create the result buffer
|
|
size_t length = olm_group_decrypt_max_plaintext_length(session, tmp_plaintext_buffer.data(), tmp_plaintext_buffer.size());
|
|
if(length == olm_error())
|
|
return {};
|
|
|
|
auto result_buffer = std::vector<std::uint8_t>(length);
|
|
|
|
// now create another buffer for olm_group_decrypt
|
|
auto tmp_buffer = std::vector<std::uint8_t>(cipherText.size());
|
|
std::copy(cipherText.begin(), cipherText.end(), tmp_buffer.begin());
|
|
|
|
uint32_t msgIndex;
|
|
auto size = olm_group_decrypt(session, tmp_buffer.data(), tmp_buffer.size(), result_buffer.data(), result_buffer.size(), &msgIndex);
|
|
if(size == olm_error())
|
|
return {};
|
|
|
|
auto output = std::vector<std::uint8_t>(size);
|
|
std::memcpy(output.data(), result_buffer.data(), size);
|
|
|
|
return output;
|
|
}
|