telegabber/e2ee/omemo/libsignal/context.go
2026-07-28 00:38:46 -04:00

89 lines
4.1 KiB
Go

package libsignal
/*
#include <signal_protocol.h>
#include <stdint.h>
// Forward declarations of the Go-exported crypto callbacks implemented in
// crypto.go. Declared here (rather than relying on a generated
// _cgo_export.h) with signatures matching signal_protocol.h's
// signal_crypto_provider field types exactly, so the struct-literal
// assignment below type-checks; the actual symbols are resolved at link
// time regardless of the const-qualifier differences cgo's own generated
// prototypes would have (const has no effect on calling convention).
extern int go_crypto_random(uint8_t *data, size_t len, void *user_data);
extern int go_crypto_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data);
extern int go_crypto_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data);
extern int go_crypto_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data);
extern void go_crypto_hmac_sha256_cleanup(void *hmac_context, void *user_data);
extern int go_crypto_sha512_init(void **digest_context, void *user_data);
extern int go_crypto_sha512_update(void *digest_context, const uint8_t *data, size_t data_len, void *user_data);
extern int go_crypto_sha512_final(void *digest_context, signal_buffer **output, void *user_data);
extern void go_crypto_sha512_cleanup(void *digest_context, void *user_data);
extern int go_crypto_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);
extern int go_crypto_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);
static int telegabber_setup_crypto_provider(signal_context *ctx) {
signal_crypto_provider provider;
provider.random_func = go_crypto_random;
provider.hmac_sha256_init_func = go_crypto_hmac_sha256_init;
provider.hmac_sha256_update_func = go_crypto_hmac_sha256_update;
provider.hmac_sha256_final_func = go_crypto_hmac_sha256_final;
provider.hmac_sha256_cleanup_func = go_crypto_hmac_sha256_cleanup;
provider.sha512_digest_init_func = go_crypto_sha512_init;
provider.sha512_digest_update_func = go_crypto_sha512_update;
provider.sha512_digest_final_func = go_crypto_sha512_final;
provider.sha512_digest_cleanup_func = go_crypto_sha512_cleanup;
provider.encrypt_func = go_crypto_encrypt;
provider.decrypt_func = go_crypto_decrypt;
provider.user_data = 0;
return signal_context_set_crypto_provider(ctx, &provider);
}
*/
import "C"
import "errors"
// Context wraps the global signal_context, wiring up a crypto provider
// backed by Go's standard library (libomemo-c ships no default one).
//
// This binding does not register locking functions with the library (see
// signal_context_set_locking_functions), because the C API requires them to
// support recursive locking, which a plain sync.Mutex cannot safely
// provide. Instead, callers MUST serialize all operations against a given
// Context - and anything built from it (StoreContext, SessionBuilder,
// SessionCipher) - themselves; libomemo-c does not spawn threads of its
// own, so a single mutex held by the caller around each call is sufficient.
type Context struct {
raw *C.signal_context
}
// NewContext creates and configures a new global library context.
func NewContext() (*Context, error) {
ctx := &Context{}
if code := C.signal_context_create(&ctx.raw, nil); code != C.SG_SUCCESS {
return nil, newError("signal_context_create", int(code))
}
if code := C.telegabber_setup_crypto_provider(ctx.raw); code != C.SG_SUCCESS {
C.signal_context_destroy(ctx.raw)
return nil, newError("signal_context_set_crypto_provider", int(code))
}
return ctx, nil
}
// Close destroys the underlying signal_context. Do not use the Context (or
// anything built from it) afterward.
func (c *Context) Close() {
if c.raw != nil {
C.signal_context_destroy(c.raw)
c.raw = nil
}
}
var errContextClosed = errors.New("libsignal: context is closed")