chatterbox

package module
v0.0.0-...-e28655f Latest Latest
Warning

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

Go to latest
Published: Nov 6, 2020 License: GPL-3.0 Imports: 10 Imported by: 0

README

SecureChat

A simplified Signal protocol in Go. Developed by Willie Yee, William Brower, and Joseph Bonneau. Implements the cryptographic logic for a secure messaging client. The security goals are to achieve integrity and confidentiality of all messages transmitted, deniable session authentication, forward secrecy at the level of individual messages, and recovery from compromise. Also recovers gracefully from errors and handles messages delivered out-of-order.

Security warning

Please do not use this for security-critical applications.

Documentation

Index

Constants

View Source
const CHAIN_LABEL = 0x02

Label for ratcheting the main chain of keys

View Source
const FINGERPRINT_LENGTH = 16 //128-bit key fingerprints
View Source
const HANDSHAKE_CHECK_LABEL byte = 0x01

Label for generating a check key from the initial root. Used for verifying the results of a handshake out-of-band.

View Source
const HASH_OUTPUT_LENGTH = 32 // SHA-256
View Source
const IV_LENGTH = 12 // 128-bit nonces
View Source
const KEY_LABEL = 0x03

Label for deriving message keys from chain keys.

View Source
const SYMMETRIC_KEY_LENGTH = 32 // 256-bit keys

Variables

This section is empty.

Functions

func NewIV

func NewIV() []byte

NewSymmetricKey creates a new, random initialization vector

func RandomBytes

func RandomBytes(n int) []byte

RandomBytes fills a buffer with the requested number of bytes. The data is read from the system PRNG

func RandomnessSource

func RandomnessSource() io.Reader

RandomnessSource reveals the real or test randomness source

func SetFixedRandomness

func SetFixedRandomness(newValue bool)

Types

type Chatter

type Chatter struct {
	Identity *KeyPair
	Sessions map[PublicKey]*Session
}

Chatter represents a chat participant. Each Chatter has a single long-term key Identity, and a map of open sessions with other users (indexed by their identity keys). You should not need to modify this.

func NewChatter

func NewChatter() *Chatter

NewChatter creates and initializes a new Chatter object. A long-term identity key is created and the map of sessions is initialized. You should not need to modify this code.

func (*Chatter) EndSession

func (c *Chatter) EndSession(partnerIdentity *PublicKey) error

EndSession erases all data for a session with the designated partner. All outstanding key material should be zeroized and the session erased.

func (*Chatter) FinalizeHandshake

func (c *Chatter) FinalizeHandshake(partnerIdentity,
	partnerEphemeral *PublicKey) (*SymmetricKey, error)

FinalizeHandshake lets the initiator receive the responder's ephemeral key and finalize the handshake. Part of this code has been provided, you will need to fill in the key derivation code. The partner which calls this method is the initiator.

func (*Chatter) InitiateHandshake

func (c *Chatter) InitiateHandshake(partnerIdentity *PublicKey) (*PublicKey, error)

InitiateHandshake prepares the first message sent in a handshake, containing an ephemeral DH share. The partner which initiates should be the first to choose a new DH ratchet value. Part of this code has been provided for you, you will need to fill in the key derivation code.

func (*Chatter) ReceiveMessage

func (c *Chatter) ReceiveMessage(message *Message) (string, error)

ReceiveMessage is used to receive the given message and return the correct plaintext. This method is where most of the key derivation, ratcheting and out-of-order message handling logic happens.

func (*Chatter) ReturnHandshake

func (c *Chatter) ReturnHandshake(partnerIdentity,
	partnerEphemeral *PublicKey) (*PublicKey, *SymmetricKey, error)

ReturnHandshake prepares the first message sent in a handshake, containing an ephemeral DH share. Part of this code has been provided for you, you will need to fill in the key derivation code. The partner which calls this method is the responder.

func (*Chatter) SendMessage

func (c *Chatter) SendMessage(partnerIdentity *PublicKey,
	plaintext string) (*Message, error)

SendMessage is used to send the given plaintext string as a message. You'll need to implement the code to ratchet, derive keys and encrypt this message.

type FixedRandom

type FixedRandom struct {
	// contains filtered or unexported fields
}

Simple PRNG based on SHA256 hashing from a constant intput

func (*FixedRandom) Update

func (a *FixedRandom) Update()

Update updates the internal state, when necessary

type FixedRandomReader

type FixedRandomReader struct {
	// contains filtered or unexported fields
}

Needed to comply with reader interface

func (FixedRandomReader) Read

func (a FixedRandomReader) Read(p []byte) (int, error)

Read returns random bytes produced by a chain of SHA-256 hashes

type KeyPair

type KeyPair struct {
	PrivateKey PrivateKey
	PublicKey  PublicKey
}

KeyPair represents a public and private key pair. In this application we are only doing Diffie-Hellman exchanges. The public key is g^x and the private key is the exponent x.

func NewKeyPair

func NewKeyPair() *KeyPair

NewKeyPair creates a new key pair. It panics in the case of randomness failure.

func (*KeyPair) Fingerprint

func (kp *KeyPair) Fingerprint() []byte

Fingerprint returns the fingerprint of the underlying public key.

func (*KeyPair) String

func (kp *KeyPair) String() string

String representation of a public key.

func (*KeyPair) Zeroize

func (kp *KeyPair) Zeroize()

Zeroize overwrites the buffer storing a private key with 0 bytes.

type Message

type Message struct {
	Sender        *PublicKey
	Receiver      *PublicKey
	NextDHRatchet *PublicKey
	Counter       int
	LastUpdate    int
	Ciphertext    []byte
	IV            []byte
}

Message represents a message as sent over an untrusted network. The first 5 fields are send unencrypted (but should be authenticated). The ciphertext contains the (encrypted) communication payload. You should not need to modify this.

func (*Message) EncodeAdditionalData

func (m *Message) EncodeAdditionalData() []byte

EncodeAdditionalData encodes all of the non-ciphertext fields of a message into a single byte array, suitable for use as additional authenticated data in an AEAD scheme. You should not need to modify this code.

type PrivateKey

type PrivateKey struct {
	Key []byte
}

PrivateKey represents a "private key". This is simply a random buffer representing a secret exponent.

func (*PrivateKey) Zeroize

func (k *PrivateKey) Zeroize()

Zeroize overwrites the buffer storing a private key with 0 bytes.

type PublicKey

type PublicKey struct {
	X *big.Int
	Y *big.Int
}

PrivateKey represents a public key, which is an elliptic curve point. Represented by two integers X, Y.

func (*PublicKey) Fingerprint

func (k *PublicKey) Fingerprint() []byte

Fingerprint returns a hash representation of a public key. This is useful for a shorter value that uniquely identifies the key, but cannot be used to recover the key itself.

type Session

type Session struct {
	MyDHRatchet      *KeyPair
	PartnerDHRatchet *PublicKey
	RootChain        *SymmetricKey
	SendChain        *SymmetricKey
	ReceiveChain     *SymmetricKey
	StaleReceiveKeys map[int]*SymmetricKey
	SendCounter      int
	LastUpdate       int
	ReceiveCounter   int
}

Session represents an open session between one chatter and another. You should not need to modify this, though you can add additional fields if you want to.

type SymmetricKey

type SymmetricKey struct {
	Key []byte
}

SymmetricKey represents a symmetric key, which is simply a buffer of random bytes.

func CombineKeys

func CombineKeys(keys ...*SymmetricKey) *SymmetricKey

CombineKeys takes any number of keys as input and combines them into a new key. This combined key is a hash of the input keys so does not reveal any info about them. This does not zeroize the input keys. Note that the order the keys are passed in matters.

func DHCombine

func DHCombine(publicKey *PublicKey, privateKey *PrivateKey) *SymmetricKey

DHCombine performs a Diffie-Hellman exchange between a public key and a private key. For example, if the public key is g^a and the private key is b, this returns a key derived by hashing g^ab. This is immediatly converted to a SymmetricKey.

func NewSymmetricKey

func NewSymmetricKey() *SymmetricKey

NewSymmetricKey creates a new random symmetric key. Note: you should not need to call this for your chat application. Every key needed will be derived from DH outputs and chains of keys.

func (*SymmetricKey) AuthenticatedDecrypt

func (k *SymmetricKey) AuthenticatedDecrypt(ciphertext, additionalData, iv []byte) (string, error)

AuthenticatedDecrypt uses a key k to decrypt a given ciphertext and a buffer additionalData of data for authentication (but not encryption). If the ciphertext or additionalData have been modified, an error will be returned.

func (*SymmetricKey) AuthenticatedEncrypt

func (k *SymmetricKey) AuthenticatedEncrypt(plaintext string, additionalData, iv []byte) []byte

AuthenticatedEncrypt uses a key k to encrypt a given plaintext and a buffer additionalData of data for authentication (but not encryption). Since AESGCM is a stream cipher, semantic security requires a new random IV for every encryption.

func (*SymmetricKey) DeriveKey

func (k *SymmetricKey) DeriveKey(label byte) *SymmetricKey

DeriveKey evalutes a key derivation function (KDF) on a key and returns the result. The label modifiers how the KDF operates. Note that the original key is left intact and not zeroized.

func (*SymmetricKey) Duplicate

func (k *SymmetricKey) Duplicate() *SymmetricKey

Duplicate produces an exact copy of a given key

func (*SymmetricKey) String

func (k *SymmetricKey) String() string

String representation of a symmetric key.

func (*SymmetricKey) Zeroize

func (k *SymmetricKey) Zeroize()

Zeroize overwrites the key bytes with zero bytes

Jump to

Keyboard shortcuts

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