summaryrefslogtreecommitdiffstats
path: root/vendor/go.mau.fi/libsignal/groups/GroupCipher.go
diff options
context:
space:
mode:
authorWim <wim@42.be>2022-01-31 00:27:37 +0100
committerWim <wim@42.be>2022-03-20 14:57:48 +0100
commite3cafeaf9292f67459ff1d186f68283bfaedf2ae (patch)
treeb69c39620aa91dba695b3b935c6651c0fb37ce75 /vendor/go.mau.fi/libsignal/groups/GroupCipher.go
parente7b193788a56ee7cdb02a87a9db0ad6724ef66d5 (diff)
downloadmatterbridge-msglm-e3cafeaf9292f67459ff1d186f68283bfaedf2ae.tar.gz
matterbridge-msglm-e3cafeaf9292f67459ff1d186f68283bfaedf2ae.tar.bz2
matterbridge-msglm-e3cafeaf9292f67459ff1d186f68283bfaedf2ae.zip
Add dependencies/vendor (whatsapp)
Diffstat (limited to 'vendor/go.mau.fi/libsignal/groups/GroupCipher.go')
-rw-r--r--vendor/go.mau.fi/libsignal/groups/GroupCipher.go141
1 files changed, 141 insertions, 0 deletions
diff --git a/vendor/go.mau.fi/libsignal/groups/GroupCipher.go b/vendor/go.mau.fi/libsignal/groups/GroupCipher.go
new file mode 100644
index 00000000..b821f3c3
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/groups/GroupCipher.go
@@ -0,0 +1,141 @@
+package groups
+
+import (
+ "fmt"
+
+ "go.mau.fi/libsignal/cipher"
+ "go.mau.fi/libsignal/ecc"
+ "go.mau.fi/libsignal/groups/ratchet"
+ "go.mau.fi/libsignal/groups/state/record"
+ "go.mau.fi/libsignal/groups/state/store"
+ "go.mau.fi/libsignal/protocol"
+ "go.mau.fi/libsignal/signalerror"
+)
+
+// NewGroupCipher will return a new group message cipher that can be used for
+// encrypt/decrypt operations.
+func NewGroupCipher(builder *SessionBuilder, senderKeyID *protocol.SenderKeyName,
+ senderKeyStore store.SenderKey) *GroupCipher {
+
+ return &GroupCipher{
+ senderKeyID: senderKeyID,
+ senderKeyStore: senderKeyStore,
+ sessionBuilder: builder,
+ }
+}
+
+// GroupCipher is the main entry point for group encrypt/decrypt operations.
+// Once a session has been established, this can be used for
+// all encrypt/decrypt operations within that session.
+type GroupCipher struct {
+ senderKeyID *protocol.SenderKeyName
+ senderKeyStore store.SenderKey
+ sessionBuilder *SessionBuilder
+}
+
+// Encrypt will take the given message in bytes and return encrypted bytes.
+func (c *GroupCipher) Encrypt(plaintext []byte) (protocol.GroupCiphertextMessage, error) {
+ // Load the sender key based on id from our store.
+ keyRecord := c.senderKeyStore.LoadSenderKey(c.senderKeyID)
+ senderKeyState, err := keyRecord.SenderKeyState()
+ if err != nil {
+ return nil, err
+ }
+
+ // Get the message key from the senderkey state.
+ senderKey, err := senderKeyState.SenderChainKey().SenderMessageKey()
+ if err != nil {
+ return nil, err
+ }
+
+ // Encrypt the plaintext.
+ ciphertext, err := cipher.EncryptCbc(senderKey.Iv(), senderKey.CipherKey(), plaintext)
+ if err != nil {
+ return nil, err
+ }
+
+ senderKeyMessage := protocol.NewSenderKeyMessage(
+ senderKeyState.KeyID(),
+ senderKey.Iteration(),
+ ciphertext,
+ senderKeyState.SigningKey().PrivateKey(),
+ c.sessionBuilder.serializer.SenderKeyMessage,
+ )
+
+ senderKeyState.SetSenderChainKey(senderKeyState.SenderChainKey().Next())
+ c.senderKeyStore.StoreSenderKey(c.senderKeyID, keyRecord)
+
+ return senderKeyMessage, nil
+}
+
+// Decrypt decrypts the given message using an existing session that
+// is stored in the senderKey store.
+func (c *GroupCipher) Decrypt(senderKeyMessage *protocol.SenderKeyMessage) ([]byte, error) {
+ keyRecord := c.senderKeyStore.LoadSenderKey(c.senderKeyID)
+
+ if keyRecord.IsEmpty() {
+ return nil, fmt.Errorf("%w for %s in %s", signalerror.ErrNoSenderKeyForUser, c.senderKeyID.Sender().String(), c.senderKeyID.GroupID())
+ }
+
+ // Get the senderkey state by id.
+ senderKeyState, err := keyRecord.GetSenderKeyStateByID(senderKeyMessage.KeyID())
+ if err != nil {
+ return nil, err
+ }
+
+ // Verify the signature of the senderkey message.
+ verified := c.verifySignature(senderKeyState.SigningKey().PublicKey(), senderKeyMessage)
+ if !verified {
+ return nil, signalerror.ErrSenderKeyStateVerificationFailed
+ }
+
+ senderKey, err := c.getSenderKey(senderKeyState, senderKeyMessage.Iteration())
+ if err != nil {
+ return nil, err
+ }
+
+ // Decrypt the message ciphertext.
+ plaintext, err := cipher.DecryptCbc(senderKey.Iv(), senderKey.CipherKey(), senderKeyMessage.Ciphertext())
+ if err != nil {
+ return nil, err
+ }
+
+ // Store the sender key by id.
+ c.senderKeyStore.StoreSenderKey(c.senderKeyID, keyRecord)
+
+ return plaintext, nil
+}
+
+// verifySignature will verify the signature of the senderkey message with
+// the given public key.
+func (c *GroupCipher) verifySignature(signingPubKey ecc.ECPublicKeyable,
+ senderKeyMessage *protocol.SenderKeyMessage) bool {
+
+ return ecc.VerifySignature(signingPubKey, senderKeyMessage.Serialize(), senderKeyMessage.Signature())
+}
+
+func (c *GroupCipher) getSenderKey(senderKeyState *record.SenderKeyState, iteration uint32) (*ratchet.SenderMessageKey, error) {
+ senderChainKey := senderKeyState.SenderChainKey()
+ if senderChainKey.Iteration() > iteration {
+ if senderKeyState.HasSenderMessageKey(iteration) {
+ return senderKeyState.RemoveSenderMessageKey(iteration), nil
+ }
+ return nil, fmt.Errorf("%w (current: %d, received: %d)", signalerror.ErrOldCounter, senderChainKey.Iteration(), iteration)
+ }
+
+ if iteration-senderChainKey.Iteration() > 2000 {
+ return nil, signalerror.ErrTooFarIntoFuture
+ }
+
+ for senderChainKey.Iteration() < iteration {
+ senderMessageKey, err := senderChainKey.SenderMessageKey()
+ if err != nil {
+ return nil, err
+ }
+ senderKeyState.AddSenderMessageKey(senderMessageKey)
+ senderChainKey = senderChainKey.Next()
+ }
+
+ senderKeyState.SetSenderChainKey(senderChainKey.Next())
+ return senderChainKey.SenderMessageKey()
+}