forked from blue/squawk
feat(omemo): add signal protocol wrappers
This commit is contained in:
parent
12ffe8e8e6
commit
2654e38665
@ -1,14 +1,14 @@
|
|||||||
target_sources(squawk PRIVATE
|
target_sources(squawk PRIVATE
|
||||||
bundle.cpp
|
bundle.cpp
|
||||||
bundle.h
|
bundle.h
|
||||||
|
database.cpp
|
||||||
|
database.h
|
||||||
device.cpp
|
device.cpp
|
||||||
device.h
|
device.h
|
||||||
device_key_storage.cpp
|
device_key_storage.cpp
|
||||||
device_key_storage.h
|
device_key_storage.h
|
||||||
device_service.cpp
|
device_service.cpp
|
||||||
device_service.h
|
device_service.h
|
||||||
signal.h
|
|
||||||
signal.cpp
|
|
||||||
qomemo.cpp
|
qomemo.cpp
|
||||||
qomemo.h
|
qomemo.h
|
||||||
sce.cpp
|
sce.cpp
|
||||||
@ -19,4 +19,5 @@ target_sources(squawk PRIVATE
|
|||||||
qxmpp_omemo_manager.h
|
qxmpp_omemo_manager.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_subdirectory(signal)
|
||||||
add_subdirectory(variant)
|
add_subdirectory(variant)
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by victoria on 2021-05-11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "signal.h"
|
|
@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by victoria on 2021-05-11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <signal/signal_protocol.h>
|
|
||||||
|
|
||||||
namespace Signal
|
|
||||||
{
|
|
||||||
|
|
||||||
class Context {};
|
|
||||||
class RatchetIdentityPair {};
|
|
||||||
class SessionSignedPreKey {};
|
|
||||||
class ProtocolKeyHelper {};
|
|
||||||
class ProtocolStoreContext {};
|
|
||||||
class SessionBuilder {};
|
|
||||||
class SessionCipher {};
|
|
||||||
|
|
||||||
}
|
|
7
qomemo/signal/CMakeLists.txt
Normal file
7
qomemo/signal/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
target_sources(squawk PRIVATE
|
||||||
|
context.cpp
|
||||||
|
context.h
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(crypto)
|
||||||
|
add_subdirectory(stores)
|
9
qomemo/signal/context.cpp
Normal file
9
qomemo/signal/context.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "context.h"
|
||||||
|
|
||||||
|
Signal::Context::Context() {}
|
||||||
|
|
||||||
|
Signal::Context::~Context() {}
|
23
qomemo/signal/context.h
Normal file
23
qomemo/signal/context.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal {
|
||||||
|
|
||||||
|
class Context {
|
||||||
|
public:
|
||||||
|
Context();
|
||||||
|
~Context();
|
||||||
|
Context(const Context &) = delete;
|
||||||
|
Context(Context &&) = delete;
|
||||||
|
Context &operator=(const Context &) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
signal_context *ctx{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Signal
|
10
qomemo/signal/crypto/CMakeLists.txt
Normal file
10
qomemo/signal/crypto/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
target_sources(squawk PRIVATE
|
||||||
|
aes_openssl.cpp
|
||||||
|
aes_openssl.h
|
||||||
|
crypto.cpp
|
||||||
|
crypto.h
|
||||||
|
hmac_sha256_openssl.cpp
|
||||||
|
hmac_sha256_openssl.h
|
||||||
|
sha512_digest_openssl.cpp
|
||||||
|
sha512_digest_openssl.h
|
||||||
|
)
|
187
qomemo/signal/crypto/aes_openssl.cpp
Normal file
187
qomemo/signal/crypto/aes_openssl.cpp
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "aes_openssl.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/opensslv.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace Signal::Crypto;
|
||||||
|
|
||||||
|
class EVPCipherCtxWrapper {
|
||||||
|
public:
|
||||||
|
EVPCipherCtxWrapper() {
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||||
|
ctx = EVP_CIPHER_CTX_new();
|
||||||
|
#else
|
||||||
|
ctx = new EVP_CIPHER_CTX;
|
||||||
|
EVP_CIPHER_CTX_init(ctx);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
~EVPCipherCtxWrapper() {
|
||||||
|
if (good()) {
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||||
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
|
#else
|
||||||
|
EVP_CIPHER_CTX_cleanup(ctx);
|
||||||
|
delete ctx;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EVPCipherCtxWrapper(const EVPCipherCtxWrapper &) = delete;
|
||||||
|
EVPCipherCtxWrapper(EVPCipherCtxWrapper &&) = delete;
|
||||||
|
EVPCipherCtxWrapper &operator=(const EVPCipherCtxWrapper &) = delete;
|
||||||
|
|
||||||
|
[[nodiscard]] bool good() const { return ctx != nullptr; }
|
||||||
|
|
||||||
|
[[nodiscard]] EVP_CIPHER_CTX *operator*() const { return ctx; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
EVP_CIPHER_CTX *ctx{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
static const EVP_CIPHER *aes_cipher(int cipher, size_t key_len) {
|
||||||
|
if (cipher == SG_CIPHER_AES_CBC_PKCS5) {
|
||||||
|
if (key_len == 16) {
|
||||||
|
return EVP_aes_128_cbc();
|
||||||
|
} else if (key_len == 24) {
|
||||||
|
return EVP_aes_192_cbc();
|
||||||
|
} else if (key_len == 32) {
|
||||||
|
return EVP_aes_256_cbc();
|
||||||
|
}
|
||||||
|
} else if (cipher == SG_CIPHER_AES_CTR_NOPADDING) {
|
||||||
|
if (key_len == 16) {
|
||||||
|
return EVP_aes_128_ctr();
|
||||||
|
} else if (key_len == 24) {
|
||||||
|
return EVP_aes_192_ctr();
|
||||||
|
} else if (key_len == 32) {
|
||||||
|
return EVP_aes_256_ctr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Aes::encrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv,
|
||||||
|
size_t iv_len, const uint8_t *plaintext, size_t plaintext_len, void *) {
|
||||||
|
const EVP_CIPHER *evp_cipher = aes_cipher(cipher, key_len);
|
||||||
|
if (!evp_cipher) {
|
||||||
|
fprintf(stderr, "invalid AES mode or key size: %zu\n", key_len);
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iv_len != 16) {
|
||||||
|
fprintf(stderr, "invalid AES IV size: %zu\n", iv_len);
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plaintext_len > INT_MAX - EVP_CIPHER_block_size(evp_cipher)) {
|
||||||
|
fprintf(stderr, "invalid plaintext length: %zu\n", plaintext_len);
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVPCipherCtxWrapper ctx{};
|
||||||
|
if (!ctx.good()) {
|
||||||
|
fprintf(stderr, "could not create context\n");
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = EVP_EncryptInit_ex(*ctx, evp_cipher, nullptr, key, iv);
|
||||||
|
if (!result) {
|
||||||
|
fprintf(stderr, "cannot initialize cipher\n");
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cipher == SG_CIPHER_AES_CTR_NOPADDING) {
|
||||||
|
result = EVP_CIPHER_CTX_set_padding(*ctx, 0);
|
||||||
|
if (!result) {
|
||||||
|
fprintf(stderr, "cannot set padding\n");
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto out_buf = std::make_unique<uint8_t>(plaintext_len + EVP_CIPHER_block_size(evp_cipher));
|
||||||
|
|
||||||
|
int out_len = 0;
|
||||||
|
result = EVP_EncryptUpdate(*ctx, out_buf.get(), &out_len, plaintext,
|
||||||
|
plaintext_len);
|
||||||
|
if (!result) {
|
||||||
|
fprintf(stderr, "cannot encrypt plaintext\n");
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int final_len = 0;
|
||||||
|
result = EVP_EncryptFinal_ex(*ctx, out_buf.get() + out_len, &final_len);
|
||||||
|
if (!result) {
|
||||||
|
fprintf(stderr, "cannot finish encrypting plaintext\n");
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
*output = signal_buffer_create(out_buf.get(), out_len + final_len);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Aes::decrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv,
|
||||||
|
size_t iv_len, const uint8_t *ciphertext, size_t ciphertext_len, void *) {
|
||||||
|
const EVP_CIPHER *evp_cipher = aes_cipher(cipher, key_len);
|
||||||
|
if (!evp_cipher) {
|
||||||
|
fprintf(stderr, "invalid AES mode or key size: %zu\n", key_len);
|
||||||
|
return SG_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iv_len != 16) {
|
||||||
|
fprintf(stderr, "invalid AES IV size: %zu\n", iv_len);
|
||||||
|
return SG_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ciphertext_len > INT_MAX - EVP_CIPHER_block_size(evp_cipher)) {
|
||||||
|
fprintf(stderr, "invalid ciphertext length: %zu\n", ciphertext_len);
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVPCipherCtxWrapper ctx{};
|
||||||
|
if (!ctx.good()) {
|
||||||
|
fprintf(stderr, "could not create context\n");
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = EVP_DecryptInit_ex(*ctx, evp_cipher, nullptr, key, iv);
|
||||||
|
if (!result) {
|
||||||
|
fprintf(stderr, "cannot initialize cipher\n");
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cipher == SG_CIPHER_AES_CTR_NOPADDING) {
|
||||||
|
result = EVP_CIPHER_CTX_set_padding(*ctx, 0);
|
||||||
|
if (!result) {
|
||||||
|
fprintf(stderr, "cannot set padding\n");
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto out_buf = std::make_unique<uint8_t>(ciphertext_len + EVP_CIPHER_block_size(evp_cipher));
|
||||||
|
|
||||||
|
int out_len = 0;
|
||||||
|
result = EVP_DecryptUpdate(*ctx, out_buf.get(), &out_len, ciphertext, ciphertext_len);
|
||||||
|
if (!result) {
|
||||||
|
fprintf(stderr, "cannot decrypt ciphertext\n");
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int final_len = 0;
|
||||||
|
result = EVP_DecryptFinal_ex(*ctx, out_buf.get() + out_len, &final_len);
|
||||||
|
if (!result) {
|
||||||
|
fprintf(stderr, "cannot finish decrypting ciphertext\n");
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
*output = signal_buffer_create(out_buf.get(), out_len + final_len);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
17
qomemo/signal/crypto/aes_openssl.h
Normal file
17
qomemo/signal/crypto/aes_openssl.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal::Crypto::Aes {
|
||||||
|
|
||||||
|
int encrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv,
|
||||||
|
size_t iv_len, const uint8_t *plaintext, size_t plaintext_len, void *user_data);
|
||||||
|
|
||||||
|
int decrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv,
|
||||||
|
size_t iv_len, const uint8_t *ciphertext, size_t ciphertext_len, void *user_data);
|
||||||
|
|
||||||
|
} // namespace Signal::Crypto::Aes
|
40
qomemo/signal/crypto/crypto.cpp
Normal file
40
qomemo/signal/crypto/crypto.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "crypto.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "aes_openssl.h"
|
||||||
|
#include "hmac_sha256_openssl.h"
|
||||||
|
#include "sha512_digest_openssl.h"
|
||||||
|
|
||||||
|
int random_func(uint8_t *data, size_t len, void *) {
|
||||||
|
if (RAND_bytes(data, len)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signal_crypto_provider Signal::Crypto::createProvider() {
|
||||||
|
signal_crypto_provider result{};
|
||||||
|
|
||||||
|
result.random_func = random_func;
|
||||||
|
result.hmac_sha256_init_func = HmacSha256::init;
|
||||||
|
result.hmac_sha256_update_func = HmacSha256::update;
|
||||||
|
result.hmac_sha256_final_func = HmacSha256::final;
|
||||||
|
result.hmac_sha256_cleanup_func = HmacSha256::cleanup;
|
||||||
|
result.sha512_digest_init_func = Sha512::init;
|
||||||
|
result.sha512_digest_update_func = Sha512::update;
|
||||||
|
result.sha512_digest_final_func = Sha512::final;
|
||||||
|
result.sha512_digest_cleanup_func = Sha512::cleanup;
|
||||||
|
result.encrypt_func = Aes::encrypt;
|
||||||
|
result.decrypt_func = Aes::decrypt;
|
||||||
|
result.user_data = nullptr;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
13
qomemo/signal/crypto/crypto.h
Normal file
13
qomemo/signal/crypto/crypto.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal::Crypto {
|
||||||
|
|
||||||
|
signal_crypto_provider createProvider();
|
||||||
|
|
||||||
|
}
|
71
qomemo/signal/crypto/hmac_sha256_openssl.cpp
Normal file
71
qomemo/signal/crypto/hmac_sha256_openssl.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hmac_sha256_openssl.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/hmac.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace Signal::Crypto;
|
||||||
|
|
||||||
|
int HmacSha256::init(void **hmac_context, const uint8_t *key, size_t key_len, void *) {
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||||
|
HMAC_CTX *ctx = HMAC_CTX_new();
|
||||||
|
if (!ctx) {
|
||||||
|
return SG_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
auto ctx = new HMAC_CTX;
|
||||||
|
HMAC_CTX_init(ctx);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*hmac_context = ctx;
|
||||||
|
|
||||||
|
if (HMAC_Init_ex(ctx, key, key_len, EVP_sha256(), nullptr) != 1) {
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HmacSha256::update(void *hmac_context, const uint8_t *data, size_t data_len, void *) {
|
||||||
|
auto ctx = static_cast<HMAC_CTX *>(hmac_context);
|
||||||
|
int result = HMAC_Update(ctx, data, data_len);
|
||||||
|
|
||||||
|
return (result == 1) ? SG_SUCCESS : SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HmacSha256::final(void *hmac_context, signal_buffer **output, void *) {
|
||||||
|
auto ctx = static_cast<HMAC_CTX *>(hmac_context);
|
||||||
|
unsigned char md[EVP_MAX_MD_SIZE];
|
||||||
|
unsigned int len = 0;
|
||||||
|
|
||||||
|
if (HMAC_Final(ctx, md, &len) != 1) {
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
signal_buffer *output_buffer = signal_buffer_create(md, len);
|
||||||
|
if (!output_buffer) {
|
||||||
|
return SG_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
*output = output_buffer;
|
||||||
|
|
||||||
|
return SG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HmacSha256::cleanup(void *hmac_context, void *) {
|
||||||
|
if (hmac_context) {
|
||||||
|
auto ctx = static_cast<HMAC_CTX *>(hmac_context);
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||||
|
HMAC_CTX_free(ctx);
|
||||||
|
#else
|
||||||
|
HMAC_CTX_cleanup(ctx);
|
||||||
|
delete ctx;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
16
qomemo/signal/crypto/hmac_sha256_openssl.h
Normal file
16
qomemo/signal/crypto/hmac_sha256_openssl.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal::Crypto::HmacSha256 {
|
||||||
|
|
||||||
|
int init(void **hmac_context, const uint8_t *key, size_t key_len, void *);
|
||||||
|
int update(void *hmac_context, const uint8_t *data, size_t data_len, void *);
|
||||||
|
int final(void *hmac_context, signal_buffer **output, void *);
|
||||||
|
void cleanup(void *hmac_context, void *);
|
||||||
|
|
||||||
|
} // namespace Signal::Crypto::HmacSha256
|
67
qomemo/signal/crypto/sha512_digest_openssl.cpp
Normal file
67
qomemo/signal/crypto/sha512_digest_openssl.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sha512_digest_openssl.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace Signal::Crypto;
|
||||||
|
|
||||||
|
int Sha512::init(void **digest_context, void *) {
|
||||||
|
auto ctx = EVP_MD_CTX_create();
|
||||||
|
if (!ctx) {
|
||||||
|
return SG_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = EVP_DigestInit_ex(ctx, EVP_sha512(), nullptr);
|
||||||
|
|
||||||
|
if (result == 1) {
|
||||||
|
*digest_context = ctx;
|
||||||
|
return SG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_MD_CTX_destroy(ctx);
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Sha512::update(void *digest_context, const uint8_t *data, size_t data_len, void *) {
|
||||||
|
auto ctx = static_cast<EVP_MD_CTX *>(digest_context);
|
||||||
|
auto result = EVP_DigestUpdate(ctx, data, data_len);
|
||||||
|
|
||||||
|
return (result == 1) ? SG_SUCCESS : SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Sha512::final(void *digest_context, signal_buffer **output, void *) {
|
||||||
|
auto ctx = static_cast<EVP_MD_CTX *>(digest_context);
|
||||||
|
unsigned char md[EVP_MAX_MD_SIZE];
|
||||||
|
unsigned int len = 0;
|
||||||
|
|
||||||
|
auto result = EVP_DigestFinal_ex(ctx, md, &len);
|
||||||
|
if (result != 1) {
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = EVP_DigestInit_ex(ctx, EVP_sha512(), nullptr);
|
||||||
|
if (result != 1) {
|
||||||
|
return SG_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
signal_buffer *output_buffer = signal_buffer_create(md, len);
|
||||||
|
if (!output_buffer) {
|
||||||
|
return SG_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
*output = output_buffer;
|
||||||
|
|
||||||
|
return SG_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sha512::cleanup(void *digest_context, void *) {
|
||||||
|
auto ctx = static_cast<EVP_MD_CTX *>(digest_context);
|
||||||
|
EVP_MD_CTX_destroy(ctx);
|
||||||
|
}
|
16
qomemo/signal/crypto/sha512_digest_openssl.h
Normal file
16
qomemo/signal/crypto/sha512_digest_openssl.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal::Crypto::Sha512 {
|
||||||
|
|
||||||
|
int init(void **digest_context, void *);
|
||||||
|
int update(void *digest_context, const uint8_t *data, size_t data_len, void *);
|
||||||
|
int final(void *digest_context, signal_buffer **output, void *);
|
||||||
|
void cleanup(void *digest_context, void *);
|
||||||
|
|
||||||
|
} // namespace Signal::Crypto::Sha512
|
14
qomemo/signal/stores/CMakeLists.txt
Normal file
14
qomemo/signal/stores/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
target_sources(squawk PRIVATE
|
||||||
|
identity_key_store.cpp
|
||||||
|
identity_key_store.h
|
||||||
|
pre_key_store.cpp
|
||||||
|
pre_key_store.h
|
||||||
|
sender_key_store.cpp
|
||||||
|
sender_key_store.h
|
||||||
|
session_store.cpp
|
||||||
|
session_store.h
|
||||||
|
signed_pre_key_store.cpp
|
||||||
|
signed_pre_key_store.h
|
||||||
|
store_context.cpp
|
||||||
|
store_context.h
|
||||||
|
)
|
47
qomemo/signal/stores/identity_key_store.cpp
Normal file
47
qomemo/signal/stores/identity_key_store.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "identity_key_store.h"
|
||||||
|
|
||||||
|
void Signal::Store::IdentityKeyStore::boundToContext(
|
||||||
|
signal_protocol_store_context *ctx) {
|
||||||
|
signal_protocol_identity_key_store store{};
|
||||||
|
|
||||||
|
store.user_data = nullptr;
|
||||||
|
store.destroy_func = nullptr;
|
||||||
|
|
||||||
|
store.get_identity_key_pair = [](signal_buffer **public_data, signal_buffer **private_data, void *ptr) {
|
||||||
|
return static_cast<IdentityKeyStore *>(ptr)->getIdentityKeyPair(public_data, private_data);
|
||||||
|
};
|
||||||
|
store.get_local_registration_id = [](void *ptr, uint32_t *registrationId) {
|
||||||
|
return static_cast<IdentityKeyStore *>(ptr)->getLocalRegistrationId(registrationId);
|
||||||
|
};
|
||||||
|
store.is_trusted_identity = [](const signal_protocol_address *address, uint8_t *key_data, size_t key_len,
|
||||||
|
void *ptr) {
|
||||||
|
return static_cast<IdentityKeyStore *>(ptr)->isTrustedIdentity(address, key_data, key_len);
|
||||||
|
};
|
||||||
|
store.save_identity = [](const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *ptr) {
|
||||||
|
return static_cast<IdentityKeyStore *>(ptr)->saveIdentity(address, key_data, key_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
signal_protocol_store_context_set_identity_key_store(ctx, &store);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::IdentityKeyStore::getIdentityKeyPair(signal_buffer **public_data, signal_buffer **private_data) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::IdentityKeyStore::getLocalRegistrationId(uint32_t *registration_id) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::IdentityKeyStore::saveIdentity(const signal_protocol_address *address, uint8_t *key_data,
|
||||||
|
size_t key_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::IdentityKeyStore::isTrustedIdentity(const signal_protocol_address *address, uint8_t *key_data,
|
||||||
|
size_t key_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
21
qomemo/signal/stores/identity_key_store.h
Normal file
21
qomemo/signal/stores/identity_key_store.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal::Store {
|
||||||
|
|
||||||
|
class IdentityKeyStore {
|
||||||
|
public:
|
||||||
|
static void boundToContext(signal_protocol_store_context *ctx);
|
||||||
|
|
||||||
|
int getIdentityKeyPair(signal_buffer **public_data, signal_buffer **private_data);
|
||||||
|
int getLocalRegistrationId(uint32_t *registration_id);
|
||||||
|
int saveIdentity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len);
|
||||||
|
int isTrustedIdentity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Signal::Store
|
43
qomemo/signal/stores/pre_key_store.cpp
Normal file
43
qomemo/signal/stores/pre_key_store.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pre_key_store.h"
|
||||||
|
|
||||||
|
void Signal::Store::PreKeyStore::boundToContext(
|
||||||
|
signal_protocol_store_context *ctx) {
|
||||||
|
signal_protocol_pre_key_store store{};
|
||||||
|
|
||||||
|
store.destroy_func = nullptr;
|
||||||
|
store.user_data = nullptr;
|
||||||
|
|
||||||
|
store.contains_pre_key = [](uint32_t id, void *ptr) {
|
||||||
|
return static_cast<PreKeyStore *>(ptr)->containsPreKey(id);
|
||||||
|
};
|
||||||
|
store.load_pre_key = [](signal_buffer **record, uint32_t id, void *ptr) {
|
||||||
|
return static_cast<PreKeyStore *>(ptr)->loadPreKey(record, id);
|
||||||
|
};
|
||||||
|
store.remove_pre_key = [](uint32_t id, void *ptr) {
|
||||||
|
return static_cast<PreKeyStore *>(ptr)->removePreKey(id);
|
||||||
|
};
|
||||||
|
store.store_pre_key = [](uint32_t id, uint8_t *record, size_t size,
|
||||||
|
void *ptr) {
|
||||||
|
return static_cast<PreKeyStore *>(ptr)->storePreKey(id, record, size);
|
||||||
|
};
|
||||||
|
|
||||||
|
signal_protocol_store_context_set_pre_key_store(ctx, &store);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::PreKeyStore::containsPreKey(uint32_t pre_key_id) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::PreKeyStore::loadPreKey(signal_buffer **record, uint32_t pre_key_id) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::PreKeyStore::storePreKey(uint32_t pre_key_id, uint8_t *record, size_t record_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::PreKeyStore::removePreKey(uint32_t pre_key_id) { return 0; }
|
21
qomemo/signal/stores/pre_key_store.h
Normal file
21
qomemo/signal/stores/pre_key_store.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal::Store {
|
||||||
|
|
||||||
|
class PreKeyStore {
|
||||||
|
public:
|
||||||
|
static void boundToContext(signal_protocol_store_context *ctx);
|
||||||
|
|
||||||
|
int containsPreKey(uint32_t pre_key_id);
|
||||||
|
int loadPreKey(signal_buffer **record, uint32_t pre_key_id);
|
||||||
|
int storePreKey(uint32_t pre_key_id, uint8_t *record, size_t record_len);
|
||||||
|
int removePreKey(uint32_t pre_key_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Signal::Store
|
36
qomemo/signal/stores/sender_key_store.cpp
Normal file
36
qomemo/signal/stores/sender_key_store.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sender_key_store.h"
|
||||||
|
|
||||||
|
void Signal::Store::SenderKeyStore::boundToContext(
|
||||||
|
signal_protocol_store_context *ctx) {
|
||||||
|
signal_protocol_sender_key_store store{};
|
||||||
|
|
||||||
|
store.user_data = nullptr;
|
||||||
|
store.destroy_func = nullptr;
|
||||||
|
|
||||||
|
store.load_sender_key = [](signal_buffer **record, signal_buffer **user_record,
|
||||||
|
const signal_protocol_sender_key_name *sender_key_name, void *ptr) {
|
||||||
|
return static_cast<SenderKeyStore *>(ptr)->loadSenderKey(record, user_record, sender_key_name);
|
||||||
|
};
|
||||||
|
store.store_sender_key = [](const signal_protocol_sender_key_name *sender_key_name, uint8_t *record,
|
||||||
|
size_t record_len, uint8_t *user_record, size_t user_record_len, void *ptr) {
|
||||||
|
return static_cast<SenderKeyStore *>(ptr)->storeSenderKey(sender_key_name, record, record_len, user_record,
|
||||||
|
user_record_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
signal_protocol_store_context_set_sender_key_store(ctx, &store);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SenderKeyStore::loadSenderKey(signal_buffer **record, signal_buffer **user_record,
|
||||||
|
const signal_protocol_sender_key_name *sender_key_name) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SenderKeyStore::storeSenderKey(const signal_protocol_sender_key_name *sender_key_name,
|
||||||
|
uint8_t *record, size_t record_len, uint8_t *user_record,
|
||||||
|
size_t user_record_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
21
qomemo/signal/stores/sender_key_store.h
Normal file
21
qomemo/signal/stores/sender_key_store.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal::Store {
|
||||||
|
|
||||||
|
class SenderKeyStore {
|
||||||
|
public:
|
||||||
|
static void boundToContext(signal_protocol_store_context *ctx);
|
||||||
|
|
||||||
|
int storeSenderKey(const signal_protocol_sender_key_name *sender_key_name, uint8_t *record, size_t record_len,
|
||||||
|
uint8_t *user_record, size_t user_record_len);
|
||||||
|
int loadSenderKey(signal_buffer **record, signal_buffer **user_record,
|
||||||
|
const signal_protocol_sender_key_name *sender_key_name);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Signal::Store
|
63
qomemo/signal/stores/session_store.cpp
Normal file
63
qomemo/signal/stores/session_store.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "session_store.h"
|
||||||
|
|
||||||
|
void Signal::Store::SessionStore::boundToContext(
|
||||||
|
signal_protocol_store_context *ctx) {
|
||||||
|
signal_protocol_session_store store{};
|
||||||
|
|
||||||
|
store.user_data = nullptr;
|
||||||
|
store.destroy_func = nullptr;
|
||||||
|
|
||||||
|
store.load_session_func = [](signal_buffer **record, signal_buffer **user_record,
|
||||||
|
const signal_protocol_address *address, void *ptr) {
|
||||||
|
return static_cast<SessionStore *>(ptr)->loadSession(record, user_record, address);
|
||||||
|
};
|
||||||
|
store.get_sub_device_sessions_func = [](signal_int_list **sessions, const char *name, size_t name_len, void *ptr) {
|
||||||
|
return static_cast<SessionStore *>(ptr)->getSubDeviceSessions(sessions, name, name_len);
|
||||||
|
};
|
||||||
|
store.store_session_func = [](const signal_protocol_address *address, uint8_t *record, size_t record_len,
|
||||||
|
uint8_t *user_record, size_t user_record_len, void *ptr) {
|
||||||
|
return static_cast<SessionStore *>(ptr)->storeSession(address, record, record_len, user_record,
|
||||||
|
user_record_len);
|
||||||
|
};
|
||||||
|
store.contains_session_func = [](const signal_protocol_address *address, void *ptr) {
|
||||||
|
return static_cast<SessionStore *>(ptr)->containsSession(address);
|
||||||
|
};
|
||||||
|
store.delete_session_func = [](const signal_protocol_address *address, void *ptr) {
|
||||||
|
return static_cast<SessionStore *>(ptr)->deleteSession(address);
|
||||||
|
};
|
||||||
|
store.delete_all_sessions_func = [](const char *name, size_t name_len, void *ptr) {
|
||||||
|
return static_cast<SessionStore *>(ptr)->deleteAllSessions(name, name_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
signal_protocol_store_context_set_session_store(ctx, &store);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SessionStore::loadSession(signal_buffer **record, signal_buffer **user_record,
|
||||||
|
const signal_protocol_address *address) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SessionStore::getSubDeviceSessions(signal_int_list **sessions, const char *name, size_t name_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SessionStore::storeSession(const signal_protocol_address *address, uint8_t *record,
|
||||||
|
size_t record_len, uint8_t *user_record, size_t user_record_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SessionStore::containsSession(const signal_protocol_address *address) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SessionStore::deleteSession(const signal_protocol_address *address) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SessionStore::deleteAllSessions(const char *name, size_t name_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
24
qomemo/signal/stores/session_store.h
Normal file
24
qomemo/signal/stores/session_store.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal::Store {
|
||||||
|
|
||||||
|
class SessionStore {
|
||||||
|
public:
|
||||||
|
static void boundToContext(signal_protocol_store_context *ctx);
|
||||||
|
|
||||||
|
int loadSession(signal_buffer **record, signal_buffer **user_record, const signal_protocol_address *address);
|
||||||
|
int getSubDeviceSessions(signal_int_list **sessions, const char *name, size_t name_len);
|
||||||
|
int storeSession(const signal_protocol_address *address, uint8_t *record, size_t record_len,
|
||||||
|
uint8_t *user_record, size_t user_record_len);
|
||||||
|
int containsSession(const signal_protocol_address *address);
|
||||||
|
int deleteSession(const signal_protocol_address *address);
|
||||||
|
int deleteAllSessions(const char *name, size_t name_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Signal::Store
|
48
qomemo/signal/stores/signed_pre_key_store.cpp
Normal file
48
qomemo/signal/stores/signed_pre_key_store.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "signed_pre_key_store.h"
|
||||||
|
|
||||||
|
void Signal::Store::SignedPreKeyStore::boundToContext(
|
||||||
|
signal_protocol_store_context *ctx) {
|
||||||
|
signal_protocol_signed_pre_key_store store{};
|
||||||
|
|
||||||
|
store.user_data = nullptr;
|
||||||
|
store.destroy_func = nullptr;
|
||||||
|
|
||||||
|
store.load_signed_pre_key = [](signal_buffer **record, uint32_t signed_pre_key_id, void *ptr) {
|
||||||
|
return static_cast<SignedPreKeyStore *>(ptr)->loadSignedPreKey(
|
||||||
|
record, signed_pre_key_id);
|
||||||
|
};
|
||||||
|
store.store_signed_pre_key = [](uint32_t signed_pre_key_id, uint8_t *record, size_t record_len, void *ptr) {
|
||||||
|
return static_cast<SignedPreKeyStore *>(ptr)->storeSignedPreKey(
|
||||||
|
signed_pre_key_id, record, record_len);
|
||||||
|
};
|
||||||
|
store.contains_signed_pre_key = [](uint32_t signed_pre_key_id, void *ptr) {
|
||||||
|
return static_cast<SignedPreKeyStore *>(ptr)->containsSignedPreKey(
|
||||||
|
signed_pre_key_id);
|
||||||
|
};
|
||||||
|
store.remove_signed_pre_key = [](uint32_t signed_pre_key_id, void *ptr) {
|
||||||
|
return static_cast<SignedPreKeyStore *>(ptr)->removeSignedPreKey(
|
||||||
|
signed_pre_key_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
signal_protocol_store_context_set_signed_pre_key_store(ctx, &store);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SignedPreKeyStore::loadSignedPreKey(signal_buffer **record, uint32_t signed_pre_key_id) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SignedPreKeyStore::storeSignedPreKey(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SignedPreKeyStore::containsSignedPreKey(uint32_t signed_pre_key_id) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Signal::Store::SignedPreKeyStore::removeSignedPreKey(uint32_t signed_pre_key_id) {
|
||||||
|
return 0;
|
||||||
|
}
|
20
qomemo/signal/stores/signed_pre_key_store.h
Normal file
20
qomemo/signal/stores/signed_pre_key_store.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal::Store {
|
||||||
|
|
||||||
|
class SignedPreKeyStore {
|
||||||
|
public:
|
||||||
|
static void boundToContext(signal_protocol_store_context *ctx);
|
||||||
|
int loadSignedPreKey(signal_buffer **record, uint32_t signed_pre_key_id);
|
||||||
|
int storeSignedPreKey(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len);
|
||||||
|
int containsSignedPreKey(uint32_t signed_pre_key_id);
|
||||||
|
int removeSignedPreKey(uint32_t signed_pre_key_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Signal::Store
|
13
qomemo/signal/stores/store_context.cpp
Normal file
13
qomemo/signal/stores/store_context.cpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "store_context.h"
|
||||||
|
|
||||||
|
Signal::Store::Context::Context(signal_context *global) {
|
||||||
|
signal_protocol_store_context_create(&ctx, global);
|
||||||
|
}
|
||||||
|
|
||||||
|
Signal::Store::Context::~Context() {
|
||||||
|
signal_protocol_store_context_destroy(ctx);
|
||||||
|
}
|
24
qomemo/signal/stores/store_context.h
Normal file
24
qomemo/signal/stores/store_context.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Created by victoria on 2021-05-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal/signal_protocol.h>
|
||||||
|
|
||||||
|
namespace Signal::Store {
|
||||||
|
|
||||||
|
class Context {
|
||||||
|
public:
|
||||||
|
explicit Context(signal_context *global);
|
||||||
|
~Context();
|
||||||
|
|
||||||
|
Context(const Context &) = delete;
|
||||||
|
Context(Context &&) = delete;
|
||||||
|
Context &operator=(const Context &) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
signal_protocol_store_context *ctx{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Signal::Store
|
Loading…
Reference in New Issue
Block a user