diff options
Diffstat (limited to 'vendor/go.mau.fi/libsignal/keys')
8 files changed, 528 insertions, 0 deletions
diff --git a/vendor/go.mau.fi/libsignal/keys/chain/ChainKey.go b/vendor/go.mau.fi/libsignal/keys/chain/ChainKey.go new file mode 100644 index 00000000..0a5125df --- /dev/null +++ b/vendor/go.mau.fi/libsignal/keys/chain/ChainKey.go @@ -0,0 +1,127 @@ +// Package chain provides chain keys used in double ratchet sessions. +package chain + +import ( + "crypto/hmac" + "crypto/sha256" + "go.mau.fi/libsignal/kdf" + "go.mau.fi/libsignal/keys/message" +) + +var messageKeySeed = []byte{0x01} +var chainKeySeed = []byte{0x02} + +// NewKey returns a new chain key with the given kdf, key, and index +func NewKey(kdf kdf.HKDF, key []byte, index uint32) *Key { + chainKey := Key{ + kdf: kdf, + key: key, + index: index, + } + + return &chainKey +} + +// NewKeyFromStruct will return a chain key built from the given structure. +func NewKeyFromStruct(structure *KeyStructure, kdf kdf.HKDF) *Key { + return NewKey( + kdf, + structure.Key, + structure.Index, + ) +} + +// NewStructFromKey will return a chain key structure for serialization. +func NewStructFromKey(key *Key) *KeyStructure { + return &KeyStructure{ + Key: key.key, + Index: key.index, + } +} + +// KeyStructure is a serializeable structure for chain keys. +type KeyStructure struct { + Key []byte + Index uint32 +} + +// Key is used for generating message keys. This key "ratchets" every time a +// message key is generated. Every time the chain key ratchets forward, its index +// increases by one. +type Key struct { + kdf kdf.HKDF + key []byte + index uint32 // Index's maximum size: 4,294,967,295 +} + +// Current returns the current ChainKey struct. +func (c *Key) Current() *Key { + return c +} + +// Key returns the ChainKey's key material. +func (c *Key) Key() []byte { + return c.key +} + +// SetKey will set the ChainKey's key material. +func (c *Key) SetKey(key []byte) { + c.key = key +} + +// Index returns how many times the ChainKey has been "ratcheted" forward. +func (c *Key) Index() uint32 { + return c.index +} + +// SetIndex sets how many times the ChainKey has been "ratcheted" forward. +func (c *Key) SetIndex(index uint32) { + c.index = index +} + +// NextKey uses the key derivation function to generate a new ChainKey. +func (c *Key) NextKey() *Key { + nextKey := c.BaseMaterial(chainKeySeed) + return NewKey(c.kdf, nextKey, c.index+1) +} + +// MessageKeys returns message keys, which includes the cipherkey, mac, iv, and index. +func (c *Key) MessageKeys() *message.Keys { + inputKeyMaterial := c.BaseMaterial(messageKeySeed) + keyMaterialBytes, _ := c.kdf(inputKeyMaterial, nil, []byte(message.KdfSalt), message.DerivedSecretsSize) + keyMaterial := newKeyMaterial(keyMaterialBytes) + + // Use the key material returned from the key derivation function for our cipherkey, mac, and iv. + messageKeys := message.NewKeys( + keyMaterial.CipherKey, // Use the first 32 bytes of the key material for the CipherKey + keyMaterial.MacKey, // Use bytes 32-64 of the key material for the MacKey + keyMaterial.IV, // Use the last 16 bytes for the IV. + c.Index(), // Attach the chain key's index to the message keys. + ) + + return messageKeys +} + +// BaseMaterial uses hmac to derive the base material used in the key derivation function for a new key. +func (c *Key) BaseMaterial(seed []byte) []byte { + mac := hmac.New(sha256.New, c.key[:]) + mac.Write(seed) + + return mac.Sum(nil) +} + +// NewKeyMaterial takes an 80-byte slice derived from a key derivation function and splits +// it into the cipherkey, mac, and iv. +func newKeyMaterial(keyMaterialBytes []byte) *kdf.KeyMaterial { + cipherKey := keyMaterialBytes[:32] // Use the first 32 bytes of the key material for the CipherKey + macKey := keyMaterialBytes[32:64] // Use bytes 32-64 of the key material for the MacKey + iv := keyMaterialBytes[64:80] // Use the last 16 bytes for the IV. + + keyMaterial := kdf.KeyMaterial{ + CipherKey: cipherKey, + MacKey: macKey, + IV: iv, + } + + return &keyMaterial +} diff --git a/vendor/go.mau.fi/libsignal/keys/identity/IdentityKey.go b/vendor/go.mau.fi/libsignal/keys/identity/IdentityKey.go new file mode 100644 index 00000000..127dbe16 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/keys/identity/IdentityKey.go @@ -0,0 +1,47 @@ +// Package identity provides identity keys used for verifying the identity +// of a signal user. +package identity + +import ( + "encoding/hex" + "go.mau.fi/libsignal/ecc" +) + +// NewKey generates a new IdentityKey from an ECPublicKey +func NewKey(publicKey ecc.ECPublicKeyable) *Key { + identityKey := Key{ + publicKey: publicKey, + } + + return &identityKey +} + +// NewKeyFromBytes generates a new IdentityKey from public key bytes +func NewKeyFromBytes(publicKey [32]byte, offset int) Key { + identityKey := Key{ + publicKey: ecc.NewDjbECPublicKey(publicKey), + } + + return identityKey +} + +// Key is a structure for representing an identity key. This same structure can +// be used for verifying recipient's identity key or storing our own identity key. +type Key struct { + publicKey ecc.ECPublicKeyable +} + +// Fingerprint gets the string fingerprint representation of the public key. +func (k *Key) Fingerprint() string { + return hex.EncodeToString(k.publicKey.Serialize()) +} + +// PublicKey returns the EC Public key of the identity key +func (k *Key) PublicKey() ecc.ECPublicKeyable { + return k.publicKey +} + +// Serialize returns the serialized version of the key +func (k *Key) Serialize() []byte { + return k.publicKey.Serialize() +} diff --git a/vendor/go.mau.fi/libsignal/keys/identity/IdentityKeyPair.go b/vendor/go.mau.fi/libsignal/keys/identity/IdentityKeyPair.go new file mode 100644 index 00000000..1d401118 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/keys/identity/IdentityKeyPair.go @@ -0,0 +1,39 @@ +package identity + +import ( + "go.mau.fi/libsignal/ecc" +) + +// NewKeyPair returns a new identity key with the given public and private keys. +func NewKeyPair(publicKey *Key, privateKey ecc.ECPrivateKeyable) *KeyPair { + keyPair := KeyPair{ + publicKey: publicKey, + privateKey: privateKey, + } + + return &keyPair +} + +// NewKeyPairFromBytes returns a new identity key from the given serialized bytes. +//func NewKeyPairFromBytes(serialized []byte) KeyPair { +//} + +// KeyPair is a holder for public and private identity key pair. +type KeyPair struct { + publicKey *Key + privateKey ecc.ECPrivateKeyable +} + +// PublicKey returns the identity key's public key. +func (k *KeyPair) PublicKey() *Key { + return k.publicKey +} + +// PrivateKey returns the identity key's private key. +func (k *KeyPair) PrivateKey() ecc.ECPrivateKeyable { + return k.privateKey +} + +// Serialize returns a byte array that represents the keypair. +//func (k *KeyPair) Serialize() []byte { +//} diff --git a/vendor/go.mau.fi/libsignal/keys/message/MessageKey.go b/vendor/go.mau.fi/libsignal/keys/message/MessageKey.go new file mode 100644 index 00000000..4eadffbe --- /dev/null +++ b/vendor/go.mau.fi/libsignal/keys/message/MessageKey.go @@ -0,0 +1,91 @@ +// Package message provides a structure for message keys, which are symmetric +// keys used for the encryption/decryption of Signal messages. +package message + +// DerivedSecretsSize is the size of the derived secrets for message keys. +const DerivedSecretsSize = 80 + +// CipherKeyLength is the length of the actual cipher key used for messages. +const CipherKeyLength = 32 + +// MacKeyLength is the length of the message authentication code in bytes. +const MacKeyLength = 32 + +// IVLength is the length of the initialization vector in bytes. +const IVLength = 16 + +// KdfSalt is used as the Salt for message keys to derive secrets using a Key Derivation Function +const KdfSalt string = "WhisperMessageKeys" + +// NewKeys returns a new message keys structure with the given cipherKey, mac, iv, and index. +func NewKeys(cipherKey, macKey, iv []byte, index uint32) *Keys { + messageKeys := Keys{ + cipherKey: cipherKey, + macKey: macKey, + iv: iv, + index: index, + } + + return &messageKeys +} + +// NewKeysFromStruct will return a new message keys object from the +// given serializeable structure. +func NewKeysFromStruct(structure *KeysStructure) *Keys { + return NewKeys( + structure.CipherKey, + structure.MacKey, + structure.IV, + structure.Index, + ) +} + +// NewStructFromKeys returns a serializeable structure of message keys. +func NewStructFromKeys(keys *Keys) *KeysStructure { + return &KeysStructure{ + CipherKey: keys.cipherKey, + MacKey: keys.macKey, + IV: keys.iv, + Index: keys.index, + } +} + +// KeysStructure is a serializeable structure of message keys. +type KeysStructure struct { + CipherKey []byte + MacKey []byte + IV []byte + Index uint32 +} + +// Keys is a structure to hold all the keys for a single MessageKey, including the +// cipherKey, mac, iv, and index of the chain key. MessageKeys are used to +// encrypt individual messages. +type Keys struct { + cipherKey []byte + macKey []byte + iv []byte + index uint32 +} + +// CipherKey is the key used to produce ciphertext. +func (k *Keys) CipherKey() []byte { + return k.cipherKey +} + +// MacKey returns the message's message authentication code. +func (k *Keys) MacKey() []byte { + return k.macKey +} + +// Iv returns the message keys' initialization vector. The IV is a fixed-size input +// to a cryptographic primitive. +func (k *Keys) Iv() []byte { + return k.iv +} + +// Index returns the number of times the chain key has been put through a key derivation +// function to generate this message key. +func (k *Keys) Index() uint32 { + return k.index +} diff --git a/vendor/go.mau.fi/libsignal/keys/prekey/PreKeyBundle.go b/vendor/go.mau.fi/libsignal/keys/prekey/PreKeyBundle.go new file mode 100644 index 00000000..04471673 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/keys/prekey/PreKeyBundle.go @@ -0,0 +1,86 @@ +// Package prekey provides prekey bundle structures for calculating +// a new Signal session with a user asyncronously. +package prekey + +import ( + "go.mau.fi/libsignal/ecc" + "go.mau.fi/libsignal/keys/identity" + "go.mau.fi/libsignal/util/optional" +) + +// NewBundle returns a Bundle structure that contains a remote PreKey +// and collection of associated items. +func NewBundle(registrationID, deviceID uint32, preKeyID *optional.Uint32, signedPreKeyID uint32, + preKeyPublic, signedPreKeyPublic ecc.ECPublicKeyable, signedPreKeySig [64]byte, + identityKey *identity.Key) *Bundle { + + bundle := Bundle{ + registrationID: registrationID, + deviceID: deviceID, + preKeyID: preKeyID, + preKeyPublic: preKeyPublic, + signedPreKeyID: signedPreKeyID, + signedPreKeyPublic: signedPreKeyPublic, + signedPreKeySignature: signedPreKeySig, + identityKey: identityKey, + } + + return &bundle +} + +// Bundle is a structure that contains a remote PreKey and collection +// of associated items. +type Bundle struct { + registrationID uint32 + deviceID uint32 + preKeyID *optional.Uint32 + preKeyPublic ecc.ECPublicKeyable + signedPreKeyID uint32 + signedPreKeyPublic ecc.ECPublicKeyable + signedPreKeySignature [64]byte + identityKey *identity.Key +} + +// DeviceID returns the device ID this PreKey belongs to. +func (b *Bundle) DeviceID() uint32 { + return b.deviceID +} + +// PreKeyID returns the unique key ID for this PreKey. +func (b *Bundle) PreKeyID() *optional.Uint32 { + return b.preKeyID +} + +// PreKey returns the public key for this PreKey. +func (b *Bundle) PreKey() ecc.ECPublicKeyable { + return b.preKeyPublic +} + +// SignedPreKeyID returns the unique key ID for this +// signed PreKey. +func (b *Bundle) SignedPreKeyID() uint32 { + return b.signedPreKeyID +} + +// SignedPreKey returns the signed PreKey for this +// PreKeyBundle. +func (b *Bundle) SignedPreKey() ecc.ECPublicKeyable { + return b.signedPreKeyPublic +} + +// SignedPreKeySignature returns the signature over the +// signed PreKey. +func (b *Bundle) SignedPreKeySignature() [64]byte { + return b.signedPreKeySignature +} + +// IdentityKey returns the Identity Key of this PreKey's owner. +func (b *Bundle) IdentityKey() *identity.Key { + return b.identityKey +} + +// RegistrationID returns the registration ID associated with +// this PreKey. +func (b *Bundle) RegistrationID() uint32 { + return b.registrationID +} diff --git a/vendor/go.mau.fi/libsignal/keys/root/RootKey.go b/vendor/go.mau.fi/libsignal/keys/root/RootKey.go new file mode 100644 index 00000000..e925bc76 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/keys/root/RootKey.go @@ -0,0 +1,66 @@ +// Package root provides root keys which are used to derive new chain and +// root keys in a ratcheting session. +package root + +import ( + "go.mau.fi/libsignal/ecc" + "go.mau.fi/libsignal/kdf" + "go.mau.fi/libsignal/keys/chain" + "go.mau.fi/libsignal/keys/session" +) + +// DerivedSecretsSize is the size of the derived secrets for root keys. +const DerivedSecretsSize = 64 + +// KdfInfo is used as the info for message keys to derive secrets using a Key Derivation Function +const KdfInfo string = "WhisperRatchet" + +// NewKey returns a new RootKey given the key derivation function and bytes. +func NewKey(kdf kdf.HKDF, key []byte) *Key { + rootKey := Key{ + kdf: kdf, + key: key, + } + + return &rootKey +} + +// Key is a structure for RootKeys, which are used to derive a new set of chain and root +// keys for every round trip of messages. +type Key struct { + kdf kdf.HKDF + key []byte +} + +// Bytes returns the RootKey in bytes. +func (k *Key) Bytes() []byte { + return k.key +} + +// CreateChain creates a new RootKey and ChainKey from the recipient's ratchet key and our private key. +func (k *Key) CreateChain(theirRatchetKey ecc.ECPublicKeyable, ourRatchetKey *ecc.ECKeyPair) (*session.KeyPair, error) { + theirPublicKey := theirRatchetKey.PublicKey() + ourPrivateKey := ourRatchetKey.PrivateKey().Serialize() + + // Use our key derivation function to calculate a shared secret. + sharedSecret := kdf.CalculateSharedSecret(theirPublicKey, ourPrivateKey) + derivedSecretBytes, err := kdf.DeriveSecrets(sharedSecret[:], k.key, []byte(KdfInfo), DerivedSecretsSize) + if err != nil { + return nil, err + } + + // Split the derived secret bytes in half, using one half for the root key and the second for the chain key. + derivedSecrets := session.NewDerivedSecrets(derivedSecretBytes) + + // Create new root and chain key structures from the derived secrets. + rootKey := NewKey(k.kdf, derivedSecrets.RootKey()) + chainKey := chain.NewKey(k.kdf, derivedSecrets.ChainKey(), 0) + + // Create a session keypair with the generated root and chain keys. + keyPair := session.NewKeyPair( + rootKey, + chainKey, + ) + + return keyPair, nil +} diff --git a/vendor/go.mau.fi/libsignal/keys/session/DerivedSecrets.go b/vendor/go.mau.fi/libsignal/keys/session/DerivedSecrets.go new file mode 100644 index 00000000..6d73cb45 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/keys/session/DerivedSecrets.go @@ -0,0 +1,29 @@ +package session + +// NewDerivedSecrets returns a new RootKey/ChainKey pair from 64 bytes of key material +// generated by the key derivation function. +func NewDerivedSecrets(keyMaterial []byte) *DerivedSecrets { + secrets := DerivedSecrets{ + keyMaterial[:32], + keyMaterial[32:], + } + + return &secrets +} + +// DerivedSecrets is a structure for holding the derived secrets for the +// Root and Chain keys for a session. +type DerivedSecrets struct { + rootKey []byte + chainKey []byte +} + +// RootKey returns the RootKey bytes. +func (d *DerivedSecrets) RootKey() []byte { + return d.rootKey +} + +// ChainKey returns the ChainKey bytes. +func (d *DerivedSecrets) ChainKey() []byte { + return d.chainKey +} diff --git a/vendor/go.mau.fi/libsignal/keys/session/Pair.go b/vendor/go.mau.fi/libsignal/keys/session/Pair.go new file mode 100644 index 00000000..f6387ba8 --- /dev/null +++ b/vendor/go.mau.fi/libsignal/keys/session/Pair.go @@ -0,0 +1,43 @@ +// Package session provides a simple structure for session keys, which is +// a pair of root and chain keys for a session. +package session + +import ( + "go.mau.fi/libsignal/ecc" + "go.mau.fi/libsignal/keys/chain" + "go.mau.fi/libsignal/keys/message" +) + +// RootKeyable is an interface for all root key implementations that are part of +// a session keypair. +type RootKeyable interface { + Bytes() []byte + CreateChain(theirRatchetKey ecc.ECPublicKeyable, ourRatchetKey *ecc.ECKeyPair) (*KeyPair, error) +} + +// ChainKeyable is an interface for all chain key implementations that are part of +// a session keypair. +type ChainKeyable interface { + Key() []byte + Index() uint32 + NextKey() *chain.Key + MessageKeys() *message.Keys + Current() *chain.Key +} + +// NewKeyPair returns a new session key pair that holds a root and chain key. +func NewKeyPair(rootKey RootKeyable, chainKey ChainKeyable) *KeyPair { + keyPair := KeyPair{ + RootKey: rootKey, + ChainKey: chainKey, + } + + return &keyPair +} + +// KeyPair is a session key pair that holds a single root and chain key pair. These +// keys are ratcheted after every message sent and every message round trip. +type KeyPair struct { + RootKey RootKeyable + ChainKey ChainKeyable +} |