summaryrefslogtreecommitdiffstats
path: root/vendor/go.mau.fi/libsignal/keys
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.mau.fi/libsignal/keys')
-rw-r--r--vendor/go.mau.fi/libsignal/keys/chain/ChainKey.go127
-rw-r--r--vendor/go.mau.fi/libsignal/keys/identity/IdentityKey.go47
-rw-r--r--vendor/go.mau.fi/libsignal/keys/identity/IdentityKeyPair.go39
-rw-r--r--vendor/go.mau.fi/libsignal/keys/message/MessageKey.go91
-rw-r--r--vendor/go.mau.fi/libsignal/keys/prekey/PreKeyBundle.go86
-rw-r--r--vendor/go.mau.fi/libsignal/keys/root/RootKey.go66
-rw-r--r--vendor/go.mau.fi/libsignal/keys/session/DerivedSecrets.go29
-rw-r--r--vendor/go.mau.fi/libsignal/keys/session/Pair.go43
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
+}