xochimilco

package module
v0.0.0-...-85f1846 Latest Latest
Warning

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

Go to latest
Published: Mar 11, 2021 License: GPL-3.0 Imports: 9 Imported by: 0

README

Xochimilco

Go Reference Go REUSE status

An implementation of the Signal Protocols X3DH and Double Ratchet. Plus a simple straightforward usable E2E encryption library build on top, named Xochimilco.

For both implementation details and examples, take a look at the documentation.

Some background, the lake Xochimilco seems to be the last native habitat for the axolotl. This salamander, also called Mexican walking fish, has incredibly self healing abilities. For this reason, the Double Ratchet algorithm was initially named after this animal.

Documentation

Overview

Package xochimilco provides an usable API for end-to-end encrypted communication based on the "Signal Protocol".

The "Signal Protocol" refers to the Extended Triple Diffie-Hellman (X3DH) key agreement protocol paired with the Double Ratchet algorithm. Both are implemented and exposed in this repository's subdirectories. For implementation details please refer there.

Example
// In this example, Alice and Bob can exchange messages over some chat
// protocol. Furthermore, they already know each other's public key.
alicePub, alicePriv, _ := ed25519.GenerateKey(nil)
bobPub, bobPriv, _ := ed25519.GenerateKey(nil)

alice := Session{
	IdentityKey: alicePriv,
	VerifyPeer: func(peer ed25519.PublicKey) (valid bool) {
		return peer.Equal(bobPub)
	},
}
bob := Session{
	IdentityKey: bobPriv,
	VerifyPeer: func(peer ed25519.PublicKey) (valid bool) {
		return peer.Equal(alicePub)
	},
}

// Alice starts by offering Bob to upgrade the connection.
offerMsg, err := alice.Offer()
if err != nil {
	panic(err)
}
fmt.Printf("A->B\tOFFER\t%s\n", offerMsg)

// Bob acknowledges Alice's offer.
ackMsg, err := bob.Acknowledge(offerMsg)
if err != nil {
	panic(err)
}
fmt.Printf("B-A\tACK\t%s\n", ackMsg)

// Alice evaluates Bob's acknowledgement. This SHOULD be `isEstablished`.
isEstablished, _, _, err := alice.Receive(ackMsg)
if err != nil {
	panic(err)
} else if !isEstablished {
	panic("invalid message")
}

// Now we have an established connection.
// Let's exchange some very important messages.
dataMsgAlice1, err := alice.Send([]byte("hello bob"))
if err != nil {
	panic(err)
}
dataMsgAlice2, err := alice.Send([]byte("how are you?"))
if err != nil {
	panic(err)
}

// Ops, the messages were reorder on the wired.
fmt.Printf("A->B\tDATA\t%s", dataMsgAlice2)
fmt.Printf("A->B\tDATA\t%s", dataMsgAlice1)

_, _, plaintextAlice2, err := bob.Receive(dataMsgAlice2)
if err != nil {
	panic(err)
}
fmt.Printf("B\tRECV\t%s", plaintextAlice2)

_, _, plaintextAlice1, err := bob.Receive(dataMsgAlice2)
if err != nil {
	panic(err)
}
fmt.Printf("B\tRECV\t%s", plaintextAlice1)

// Bob also sends an answer.
dataMsgBob, err := bob.Send([]byte("hej alice!"))
if err != nil {
	panic(err)
}
fmt.Printf("B->A\tDATA\t%s", dataMsgBob)

_, _, plaintextBob, err := alice.Receive(dataMsgBob)
if err != nil {
	panic(err)
}
fmt.Printf("A\tRECV\t%s", plaintextBob)

// Finally, Alice closes her Session...
closeMsg, err := alice.Close()
if err != nil {
	panic(err)
}
fmt.Printf("A->B\tCLOSE\t%s", closeMsg)

// ...and tells Bob to do the same.
_, isClosed, _, err := bob.Receive(closeMsg)
if err != nil {
	panic(err)
} else if !isClosed {
	panic("invalid message")
}

_, err = bob.Close()
if err != nil {
	panic(err)
}
Output:

Index

Examples

Constants

View Source
const (

	// Prefix indicates the beginning of an encoded message.
	Prefix string = "!XO!"

	// Suffix indicates the end of an encoded message.
	Suffix string = "!OX!"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Session

type Session struct {
	// IdentityKey is this node's private Ed25519 identity key.
	//
	// This will only be used within the X3DH key agreement protocol. The other
	// party might want to verify this key's public part.
	IdentityKey ed25519.PrivateKey

	// VerifyPeer is a callback during session initialization to verify the
	// other party's public key.
	//
	// To determine when a key is correct is out of Xochimilco's scope. The key
	// might be either exchanged over another secure channel or a trust on first
	// use (TOFU) principle might be used.
	VerifyPeer func(peer ed25519.PublicKey) (valid bool)
	// contains filtered or unexported fields
}

Session between two parties to exchange encrypted messages.

Each party creates a new Session variable configured with their private long time identity key and a function callback to verify the other party's public identity key.

The active party must start by offering to "upgrade" the current channel (Offer). Afterwards, the other party must confirm this step (Acknowledge). Once the first party finally receives the acknowledgement (Receive), the connection is established.

Now both parties can create encrypted messages directed to the other (Send). Furthermore, the Session can be closed again (Close). Incoming messages can be inspected and the payload extracted, if present (Receive).

func (*Session) Acknowledge

func (sess *Session) Acknowledge(offerMsg string) (ackMsg string, err error)

Acknowledge to establish an encrypted Session.

This method MUST be called by the passive party (Bob) with the active party's (Alice's) offer message. The created acknowledge message MUST be send back.

At this point, this passive part is able to send and receive messages.

func (*Session) Close

func (sess *Session) Close() (closeMsg string, err error)

Close this Session and tell the other party to do the same.

This resets the internal state. Thus, the same Session might be reused.

func (*Session) Offer

func (sess *Session) Offer() (offerMsg string, err error)

Offer to establish an encrypted Session.

This method MUST be called initially by the active resp. opening party (Alice) once. The other party will hopefully Acknowledge this message.

func (*Session) Receive

func (sess *Session) Receive(msg string) (isEstablished, isClosed bool, plaintext []byte, err error)

Receive an incoming message.

All messages except the passive party's initial offer message MUST be passed to this method. The multiple return fields indicate this message's kind.

If the active party receives its first (acknowledge) message, this Session will be established; isEstablished. If the other party has signaled to close the Session, isClosed is set. This Session MUST then also be closed down. In case of an incoming encrypted message, the plaintext field holds its decrypted plaintext value. Of course, there might also be an error.

func (*Session) Send

func (sess *Session) Send(plaintext []byte) (dataMsg string, err error)

Send a message to the other party. The given plaintext byte array will be embedded in an encrypted message.

This method is allowed to be called after the initial handshake, Offer resp. Acknowledge.

Directories

Path Synopsis
Package doubleratchet implements a variant of the Double Ratchet Algorithm.
Package doubleratchet implements a variant of the Double Ratchet Algorithm.
Package x3dh implements a variant of the Extended Triple Diffie-Hellman (X3DH) key agreement protocol.
Package x3dh implements a variant of the Extended Triple Diffie-Hellman (X3DH) key agreement protocol.

Jump to

Keyboard shortcuts

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