libsignal-protocol-go

module
v0.0.0-...-078e79d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 18, 2024 License: GPL-3.0

README

GoDoc Go Report Card License Twitter

libsignal-protocol-go

Libsignal-protocol-go is a Go implementation of the Signal Client Protocol.

Documentation

For more information on how the Signal Protocol works:

Installation

Install the Signal library using the "go get" command:

go get github.com/RadicalApp/libsignal-protocol-go/...

Usage

Install time

At install time, a signal client needs to generate its identity keys, registration id, and prekeys.

import (
	"github.com/RadicalApp/libsignal-protocol-go/serialize"
	"github.com/RadicalApp/libsignal-protocol-go/session"
	"github.com/RadicalApp/libsignal-protocol-go/state/record"
	"github.com/RadicalApp/libsignal-protocol-go/util/keyhelper"
)

...

// Create a serializer that will be responsible for converting objects into
// storeable and transportable bytes.
serializer := serialize.NewJSONSerializer()

// Generate an identity keypair
identityKeyPair, err := keyhelper.GenerateIdentityKeyPair()
if err != nil {
    panic("Unable to generate identity key pair!")
}

// Generate a registration id
registrationID := keyhelper.GenerateRegistrationID(false)

// Generate PreKeys
preKeys, err := keyhelper.GeneratePreKeys(0, 100, serializer.PreKeyRecord)
if err != nil {
    panic("Unable to generate pre keys!")
}

// Generate Signed PreKey
signedPreKey, err := keyhelper.GenerateSignedPreKey(identityKeyPair, 0, serializer.SignedPreKeyRecord)
if err != nil {
    panic("Unable to generate signed prekey!")
}

// Create durable stores for sessions, prekeys, signed prekeys, and identity keys.
// These should be implemented yourself and follow the store interfaces.
sessionStore      := NewSessionStore()
preKeyStore       := NewPreKeyStore()
signedPreKeyStore := NewSignedPreKeyStore()
identityStore     := NewIdentityKeyStore(identityKeyPair, registrationID)

// Put all our pre keys in our local stores.
for i := range preKeys {
	preKeyStore.StorePreKey(
		preKeys[i].ID().Value,
		record.NewPreKey(preKeys[i].ID().Value, preKeys[i].KeyPair(), serializer.PreKeyRecord),
	)
}

// Store our own signed prekey
signedPreKeyStore.StoreSignedPreKey(
	signedPreKey.ID(),
	record.NewSignedPreKey(
		signedPreKey.ID(),
		signedPreKey.Timestamp(),
		signedPreKey.KeyPair(),
		signedPreKey.Signature(),
		serializer.SignedPreKeyRecord,
	),
)

Building a session

A signal client needs to implement four interfaces: IdentityKeyStore, PreKeyStore, SignedPreKeyStore, and SessionStore. These will manage loading and storing of identity, prekeys, signed prekeys, and session state.

Once those are implemented, you can build a session in this way:

// Instantiate a SessionBuilder for a remote recipientId + deviceId tuple.
sessionBuilder := session.NewBuilder(
	sessionStore,
	preKeyStore,
	signedPreKeyStore,
	identityStore,
	address,
	serializer,
)

// Build a session with a PreKey retrieved from the server.
sessionBuilder.ProcessBundle(retrievedPreKey)

// Encrypt a message to send.
sessionCipher := session.NewCipher(sessionBuilder, address)
message, err := sessionCipher.Encrypt([]byte{"Hello world!"})
if err != nil {
    panic("Unable to encrypt message!")
}

// Send the message with your own deliver method. The deliver method should be
// your own implementation for sending an encrypted message to someone.
deliver(message.serialize())

Using your own stores

In order to use the Signal library, you must first implement your own stores for persistent storage of keys, session state, etc. To get started, you can implement in-memory stores for testing. Note that for production application, you will need to write store implementations that can store persistently.

Here is an example of an in-memory implementation of the Identity Key Store:

// IdentityKeyStore
func NewInMemoryIdentityKey(identityKey *identity.KeyPair, localRegistrationID uint32) *InMemoryIdentityKey {
	return &InMemoryIdentityKey{
		trustedKeys:         make(map[*protocol.SignalAddress]*identity.Key),
		identityKeyPair:     identityKey,
		localRegistrationID: localRegistrationID,
	}
}

type InMemoryIdentityKey struct {
	trustedKeys         map[*protocol.SignalAddress]*identity.Key
	identityKeyPair     *identity.KeyPair
	localRegistrationID uint32
}

func (i *InMemoryIdentityKey) GetIdentityKeyPair() *identity.KeyPair {
	return i.identityKeyPair
}

func (i *InMemoryIdentityKey) GetLocalRegistrationId() uint32 {
	return i.localRegistrationID
}

func (i *InMemoryIdentityKey) SaveIdentity(address *protocol.SignalAddress, identityKey *identity.Key) {
	i.trustedKeys[address] = identityKey
}

func (i *InMemoryIdentityKey) IsTrustedIdentity(address *protocol.SignalAddress, identityKey *identity.Key) bool {
	trusted := i.trustedKeys[address]
	return (trusted == nil || trusted.Fingerprint() == identityKey.Fingerprint())
}

Using your own serializer

The Go implementation of the Signal library uses serializer interfaces for encoding and decoding data for use in sending data objects over the network and local storage. This allows users of the Signal library to use their own serialization format (such as JSON, Protobuffers, etc.). It also allows more flexibility for future serialization formats that might be better than the current ones available.

Currently the library includes a JSON implementation of serializing all Signal data structures. If you want to write a new serialization implementation, you will need to write structures that implement the interfaces for each object and write a constructor function to create a new Serializer object using your implementations.

A serializer must implement the serializer interfaces for the following structs:

  • protocol.SignalMessage
  • protocol.PreKeySignalMessage
  • protocol.SenderKeyMessage
  • protocol.SenderKeyDistributionMessage
  • record.SignedPreKey
  • record.PreKey
  • record.State
  • record.Session
  • record.SenderKey
  • record.SenderKeyState

Here is an example of the constructor function for a Serializer that uses JSON implementations:

import "github.com/RadicalApp/libsignal-protocol-go/serializer"

// NewJSONSerializer will return a serializer for all Signal objects that will
// be responsible for converting objects to and from JSON bytes.
func NewJSONSerializer() *serializer.Serializer {
	serializer := serializer.NewSerializer()

	serializer.SignalMessage = &JSONSignalMessageSerializer{}
	serializer.PreKeySignalMessage = &JSONPreKeySignalMessageSerializer{}
	serializer.SignedPreKeyRecord = &JSONSignedPreKeyRecordSerializer{}
	serializer.PreKeyRecord = &JSONPreKeyRecordSerializer{}
	serializer.State = &JSONStateSerializer{}
	serializer.Session = &JSONSessionSerializer{}
	serializer.SenderKeyMessage = &JSONSenderKeyMessageSerializer{}
	serializer.SenderKeyDistributionMessage = &JSONSenderKeyDistributionMessageSerializer{}
	serializer.SenderKeyRecord = &JSONSenderKeySessionSerializer{}
	serializer.SenderKeyState = &JSONSenderKeyStateSerializer{}

	return serializer
}

Directories

Path Synopsis
CBC describes a block cipher mode.
CBC describes a block cipher mode.
Package ecc provides a way to generate, sign, and use Elliptic-Curve X25519 Cryptography keys.
Package ecc provides a way to generate, sign, and use Elliptic-Curve X25519 Cryptography keys.
Package fingerprint provides a way to generate a visually verifiable fingerprint of keys.
Package fingerprint provides a way to generate a visually verifiable fingerprint of keys.
Package groups is responsible for setting up group SenderKey encrypted sessions.
Package groups is responsible for setting up group SenderKey encrypted sessions.
ratchet
Package ratchet provides the methods necessary to establish a ratchet session for group messaging.
Package ratchet provides the methods necessary to establish a ratchet session for group messaging.
state/record
Package record provides the state and record of a group session.
Package record provides the state and record of a group session.
state/store
Package store provides the storage interfaces for storing group sender key records.
Package store provides the storage interfaces for storing group sender key records.
Package kdf provides a key derivation function to calculate key output and negotiate shared secrets for curve X25519 keys.
Package kdf provides a key derivation function to calculate key output and negotiate shared secrets for curve X25519 keys.
keys
chain
Package chain provides chain keys used in double ratchet sessions.
Package chain provides chain keys used in double ratchet sessions.
identity
Package identity provides identity keys used for verifying the identity of a signal user.
Package identity provides identity keys used for verifying the identity of a signal user.
message
Package message provides a structure for message keys, which are symmetric keys used for the encryption/decryption of Signal messages.
Package message provides a structure for message keys, which are symmetric keys used for the encryption/decryption of Signal messages.
prekey
Package prekey provides prekey bundle structures for calculating a new Signal session with a user asyncronously.
Package prekey provides prekey bundle structures for calculating a new Signal session with a user asyncronously.
root
Package root provides root keys which are used to derive new chain and root keys in a ratcheting session.
Package root provides root keys which are used to derive new chain and root keys in a ratcheting session.
session
Package session provides a simple structure for session keys, which is a pair of root and chain keys for a session.
Package session provides a simple structure for session keys, which is a pair of root and chain keys for a session.
Package logger provides optional debug logging of the Signal library.
Package logger provides optional debug logging of the Signal library.
Package protocol provides address, group, and message structures that the Signal protocol uses for sending encrypted messages.
Package protocol provides address, group, and message structures that the Signal protocol uses for sending encrypted messages.
Package ratchet provides the methods necessary to establish a new double ratchet session.
Package ratchet provides the methods necessary to establish a new double ratchet session.
Package serialize provides a serialization structure to serialize and deserialize Signal objects into storeable and transportable bytes.
Package serialize provides a serialization structure to serialize and deserialize Signal objects into storeable and transportable bytes.
Package session provides the methods necessary to build sessions
Package session provides the methods necessary to build sessions
state
record
Package record provides the state and record of an ongoing double ratchet session.
Package record provides the state and record of an ongoing double ratchet session.
store
Package store provides the storage interfaces for storing the state of ongoing double ratchet sessions and keys.
Package store provides the storage interfaces for storing the state of ongoing double ratchet sessions and keys.
util
keyhelper
Package keyhelper is based on: https://github.com/WhisperSystems/libsignal-protocol-java/blob/master/java/src/main/java/org/whispersystems/libsignal/util/KeyHelper.java
Package keyhelper is based on: https://github.com/WhisperSystems/libsignal-protocol-java/blob/master/java/src/main/java/org/whispersystems/libsignal/util/KeyHelper.java

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL