295 lines
9.8 KiB
Go
295 lines
9.8 KiB
Go
// mautrix-signal - A Matrix-signal puppeting bridge.
|
|
// Copyright (C) 2023 Scott Weber
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package libsignalgo
|
|
|
|
/*
|
|
#cgo LDFLAGS: -lsignal_ffi -ldl -lm
|
|
#include "./libsignal-ffi.h"
|
|
*/
|
|
import "C"
|
|
import (
|
|
"context"
|
|
"runtime"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type SealedSenderAddress struct {
|
|
E164 string
|
|
UUID uuid.UUID
|
|
DeviceID uint32
|
|
}
|
|
|
|
func NewSealedSenderAddress(e164 string, uuid uuid.UUID, deviceID uint32) *SealedSenderAddress {
|
|
return &SealedSenderAddress{
|
|
E164: e164,
|
|
UUID: uuid,
|
|
DeviceID: deviceID,
|
|
}
|
|
}
|
|
|
|
func SealedSenderEncryptPlaintext(ctx context.Context, message []byte, contentHint UnidentifiedSenderMessageContentHint, forAddress *Address, fromSenderCert *SenderCertificate, sessionStore SessionStore, identityStore IdentityKeyStore) ([]byte, error) {
|
|
ciphertextMessage, err := Encrypt(ctx, message, forAddress, sessionStore, identityStore)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
usmc, err := NewUnidentifiedSenderMessageContent(
|
|
ciphertextMessage,
|
|
fromSenderCert,
|
|
contentHint,
|
|
nil,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return SealedSenderEncrypt(ctx, usmc, forAddress, identityStore)
|
|
}
|
|
|
|
func SealedSenderEncrypt(ctx context.Context, usmc *UnidentifiedSenderMessageContent, forRecipient *Address, identityStore IdentityKeyStore) ([]byte, error) {
|
|
var encrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{}
|
|
callbackCtx := NewCallbackContext(ctx)
|
|
defer callbackCtx.Unref()
|
|
signalFfiError := C.signal_sealed_session_cipher_encrypt(
|
|
&encrypted,
|
|
forRecipient.ptr,
|
|
usmc.ptr,
|
|
callbackCtx.wrapIdentityKeyStore(identityStore),
|
|
)
|
|
runtime.KeepAlive(usmc)
|
|
runtime.KeepAlive(forRecipient)
|
|
if signalFfiError != nil {
|
|
return nil, callbackCtx.wrapError(signalFfiError)
|
|
}
|
|
return CopySignalOwnedBufferToBytes(encrypted), nil
|
|
}
|
|
|
|
func SealedSenderMultiRecipientEncrypt(messageContent *UnidentifiedSenderMessageContent, forRecipients []*Address, identityStore IdentityKeyStore, sessionStore SessionStore, ctx *CallbackContext) ([]byte, error) {
|
|
panic("not implemented")
|
|
}
|
|
|
|
type SealedSenderResult struct {
|
|
Message []byte
|
|
Sender SealedSenderAddress
|
|
}
|
|
|
|
func SealedSenderDecryptToUSMC(
|
|
ctx context.Context,
|
|
ciphertext []byte,
|
|
identityStore IdentityKeyStore,
|
|
) (*UnidentifiedSenderMessageContent, error) {
|
|
callbackCtx := NewCallbackContext(ctx)
|
|
defer callbackCtx.Unref()
|
|
var usmc *C.SignalUnidentifiedSenderMessageContent = nil
|
|
signalFfiError := C.signal_sealed_session_cipher_decrypt_to_usmc(
|
|
&usmc,
|
|
BytesToBuffer(ciphertext),
|
|
callbackCtx.wrapIdentityKeyStore(identityStore),
|
|
)
|
|
runtime.KeepAlive(ciphertext)
|
|
if signalFfiError != nil {
|
|
return nil, callbackCtx.wrapError(signalFfiError)
|
|
}
|
|
return wrapUnidentifiedSenderMessageContent(usmc), nil
|
|
}
|
|
|
|
func SealedSenderDecrypt(
|
|
ctx context.Context,
|
|
ciphertext []byte,
|
|
localAddress *SealedSenderAddress,
|
|
trustRoot *PublicKey,
|
|
timestamp uint64,
|
|
sessionStore SessionStore,
|
|
identityStore IdentityKeyStore,
|
|
preKeyStore PreKeyStore,
|
|
signedPreKeyStore SignedPreKeyStore,
|
|
) (result SealedSenderResult, err error) {
|
|
callbackCtx := NewCallbackContext(ctx)
|
|
defer callbackCtx.Unref()
|
|
|
|
var decrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{}
|
|
var senderE164 *C.char
|
|
var senderUUID *C.char
|
|
var senderDeviceID C.uint32_t
|
|
|
|
signalFfiError := C.signal_sealed_session_cipher_decrypt(
|
|
&decrypted,
|
|
&senderE164,
|
|
&senderUUID,
|
|
&senderDeviceID,
|
|
BytesToBuffer(ciphertext),
|
|
trustRoot.ptr,
|
|
C.uint64_t(timestamp),
|
|
C.CString(localAddress.E164),
|
|
C.CString(localAddress.UUID.String()),
|
|
C.uint32_t(localAddress.DeviceID),
|
|
callbackCtx.wrapSessionStore(sessionStore),
|
|
callbackCtx.wrapIdentityKeyStore(identityStore),
|
|
callbackCtx.wrapPreKeyStore(preKeyStore),
|
|
callbackCtx.wrapSignedPreKeyStore(signedPreKeyStore),
|
|
)
|
|
runtime.KeepAlive(localAddress)
|
|
runtime.KeepAlive(trustRoot)
|
|
if signalFfiError != nil {
|
|
err = callbackCtx.wrapError(signalFfiError)
|
|
return
|
|
}
|
|
|
|
defer C.signal_free_string(senderE164)
|
|
defer C.signal_free_string(senderUUID)
|
|
|
|
return SealedSenderResult{
|
|
Message: CopySignalOwnedBufferToBytes(decrypted),
|
|
Sender: SealedSenderAddress{
|
|
E164: C.GoString(senderE164),
|
|
UUID: uuid.MustParse(C.GoString(senderUUID)),
|
|
DeviceID: uint32(senderDeviceID),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
type UnidentifiedSenderMessageContentHint uint32
|
|
|
|
const (
|
|
UnidentifiedSenderMessageContentHintDefault UnidentifiedSenderMessageContentHint = 0
|
|
UnidentifiedSenderMessageContentHintResendable UnidentifiedSenderMessageContentHint = 1
|
|
UnidentifiedSenderMessageContentHintImplicit UnidentifiedSenderMessageContentHint = 2
|
|
)
|
|
|
|
type UnidentifiedSenderMessageContent struct {
|
|
nc noCopy
|
|
ptr *C.SignalUnidentifiedSenderMessageContent
|
|
}
|
|
|
|
func wrapUnidentifiedSenderMessageContent(ptr *C.SignalUnidentifiedSenderMessageContent) *UnidentifiedSenderMessageContent {
|
|
messageContent := &UnidentifiedSenderMessageContent{ptr: ptr}
|
|
runtime.SetFinalizer(messageContent, (*UnidentifiedSenderMessageContent).Destroy)
|
|
return messageContent
|
|
}
|
|
|
|
func NewUnidentifiedSenderMessageContent(message *CiphertextMessage, senderCertificate *SenderCertificate, contentHint UnidentifiedSenderMessageContentHint, groupID []byte) (*UnidentifiedSenderMessageContent, error) {
|
|
var usmc *C.SignalUnidentifiedSenderMessageContent
|
|
signalFfiError := C.signal_unidentified_sender_message_content_new(&usmc, message.ptr, senderCertificate.ptr, C.uint32_t(contentHint), BytesToBuffer(groupID))
|
|
runtime.KeepAlive(message)
|
|
runtime.KeepAlive(senderCertificate)
|
|
runtime.KeepAlive(groupID)
|
|
if signalFfiError != nil {
|
|
return nil, wrapError(signalFfiError)
|
|
}
|
|
return wrapUnidentifiedSenderMessageContent(usmc), nil
|
|
}
|
|
|
|
//func NewUnidentifiedSenderMessageContentFromMessage(sealedSenderMessage []byte, identityStore IdentityKeyStore, ctx *CallbackContext) (*UnidentifiedSenderMessageContent, error) {
|
|
// contextPtr := gopointer.Save(ctx)
|
|
// defer gopointer.Unref(contextPtr)
|
|
//
|
|
// var usmc *C.SignalUnidentifiedSenderMessageContent
|
|
//
|
|
// signalFfiError := C.signal_sealed_session_cipher_decrypt_to_usmc(
|
|
// &usmc,
|
|
// BytesToBuffer(sealedSenderMessage),
|
|
// wrapIdentityKeyStore(identityStore),
|
|
// contextPtr,
|
|
// )
|
|
// if signalFfiError != nil {
|
|
// return nil, wrapError(signalFfiError)
|
|
// }
|
|
// return wrapUnidentifiedSenderMessageContent(usmc), nil
|
|
//}
|
|
|
|
func DeserializeUnidentifiedSenderMessageContent(serialized []byte) (*UnidentifiedSenderMessageContent, error) {
|
|
var usmc *C.SignalUnidentifiedSenderMessageContent
|
|
signalFfiError := C.signal_unidentified_sender_message_content_deserialize(&usmc, BytesToBuffer(serialized))
|
|
runtime.KeepAlive(serialized)
|
|
if signalFfiError != nil {
|
|
return nil, wrapError(signalFfiError)
|
|
}
|
|
return wrapUnidentifiedSenderMessageContent(usmc), nil
|
|
}
|
|
|
|
func (usmc *UnidentifiedSenderMessageContent) Destroy() error {
|
|
usmc.CancelFinalizer()
|
|
return wrapError(C.signal_unidentified_sender_message_content_destroy(usmc.ptr))
|
|
}
|
|
|
|
func (usmc *UnidentifiedSenderMessageContent) CancelFinalizer() {
|
|
runtime.SetFinalizer(usmc, nil)
|
|
}
|
|
|
|
func (usmc *UnidentifiedSenderMessageContent) Serialize() ([]byte, error) {
|
|
var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{}
|
|
signalFfiError := C.signal_unidentified_sender_message_content_serialize(&serialized, usmc.ptr)
|
|
runtime.KeepAlive(usmc)
|
|
if signalFfiError != nil {
|
|
return nil, wrapError(signalFfiError)
|
|
}
|
|
return CopySignalOwnedBufferToBytes(serialized), nil
|
|
}
|
|
|
|
func (usmc *UnidentifiedSenderMessageContent) GetContents() ([]byte, error) {
|
|
var contents C.SignalOwnedBuffer = C.SignalOwnedBuffer{}
|
|
signalFfiError := C.signal_unidentified_sender_message_content_get_contents(&contents, usmc.ptr)
|
|
runtime.KeepAlive(usmc)
|
|
if signalFfiError != nil {
|
|
return nil, wrapError(signalFfiError)
|
|
}
|
|
return CopySignalOwnedBufferToBytes(contents), nil
|
|
}
|
|
|
|
//func (usmc *UnidentifiedSenderMessageContent) GetGroupID() ([]byte, error) {
|
|
// var groupID *C.uchar
|
|
// var length C.ulong
|
|
// signalFfiError := C.signal_unidentified_sender_message_content_get_group_id(&groupID, &length, usmc.ptr)
|
|
// if signalFfiError != nil {
|
|
// return nil, wrapError(signalFfiError)
|
|
// }
|
|
// if groupID == nil {
|
|
// return nil, nil
|
|
// }
|
|
// return CopyBufferToBytes(groupID, length), nil
|
|
//}
|
|
|
|
func (usmc *UnidentifiedSenderMessageContent) GetSenderCertificate() (*SenderCertificate, error) {
|
|
var senderCertificate *C.SignalSenderCertificate
|
|
signalFfiError := C.signal_unidentified_sender_message_content_get_sender_cert(&senderCertificate, usmc.ptr)
|
|
runtime.KeepAlive(usmc)
|
|
if signalFfiError != nil {
|
|
return nil, wrapError(signalFfiError)
|
|
}
|
|
return wrapSenderCertificate(senderCertificate), nil
|
|
}
|
|
|
|
func (usmc *UnidentifiedSenderMessageContent) GetMessageType() (CiphertextMessageType, error) {
|
|
var messageType C.uint8_t
|
|
signalFfiError := C.signal_unidentified_sender_message_content_get_msg_type(&messageType, usmc.ptr)
|
|
runtime.KeepAlive(usmc)
|
|
if signalFfiError != nil {
|
|
return 0, wrapError(signalFfiError)
|
|
}
|
|
return CiphertextMessageType(messageType), nil
|
|
}
|
|
|
|
func (usmc *UnidentifiedSenderMessageContent) GetContentHint() (UnidentifiedSenderMessageContentHint, error) {
|
|
var contentHint C.uint32_t
|
|
signalFfiError := C.signal_unidentified_sender_message_content_get_content_hint(&contentHint, usmc.ptr)
|
|
runtime.KeepAlive(usmc)
|
|
if signalFfiError != nil {
|
|
return 0, wrapError(signalFfiError)
|
|
}
|
|
return UnidentifiedSenderMessageContentHint(contentHint), nil
|
|
}
|