├── .gitignore ├── CREDITS.md ├── LICENSE ├── README.md ├── cipher └── Cipher.go ├── ecc ├── Curve.go ├── DjbECPublicKey.go ├── DkbECPrivateKey.go ├── Doc.go ├── ECKeyPair.go ├── ECPrivateKey.go ├── ECPublicKey.go └── SignCurve25519.go ├── fingerprint ├── DisplayFingerprint.go ├── Doc.go ├── Fingerprint.go └── FingerprintGenerator.go ├── groups ├── GroupCipher.go ├── GroupSessionBuilder.go ├── ratchet │ ├── Doc.go │ ├── SenderChainKey.go │ └── SenderMessageKey.go └── state │ ├── record │ ├── Doc.go │ ├── SenderKeyRecord.go │ └── SenderKeyState.go │ └── store │ ├── Doc.go │ └── SenderKeyStore.go ├── kdf └── HKDF.go ├── keys ├── chain │ └── ChainKey.go ├── identity │ ├── IdentityKey.go │ └── IdentityKeyPair.go ├── message │ └── MessageKey.go ├── prekey │ └── PreKeyBundle.go ├── root │ └── RootKey.go └── session │ ├── DerivedSecrets.go │ └── Pair.go ├── logger ├── DefaultLogger.go └── Logger.go ├── protocol ├── CiphertextMessage.go ├── Doc.go ├── PreKeySignalMessage.go ├── SenderKeyDistributionMessage.go ├── SenderKeyMessage.go ├── SenderKeyName.go ├── SignalMessage.go └── SignalProtocolAddress.go ├── ratchet ├── Ratchet.go ├── ReceiverParameters.go ├── SenderParameters.go └── SymmetricParameters.go ├── serialize ├── JSONSerializer.go └── Serializer.go ├── session ├── Session.go └── SessionCipher.go ├── state ├── record │ ├── ChainState.go │ ├── Doc.go │ ├── PendingKeyExchangeState.go │ ├── PendingPreKeyState.go │ ├── PreKeyRecord.go │ ├── SessionRecord.go │ ├── SessionState.go │ ├── SignedPreKeyRecord.go │ └── UnacknowledgedPreKey.go └── store │ ├── Doc.go │ ├── IdentityKeyStore.go │ ├── MessageKeyStore.go │ ├── PreKeyStore.go │ ├── SessionStore.go │ ├── SignalProtocolStore.go │ └── SignedPreKeyStore.go ├── tests ├── fingerprint_test.go ├── group_test.go ├── identity_test.go ├── prekey_test.go ├── registrationid_test.go ├── saved_message_keys_test.go ├── serializer.go ├── serializer_test.go ├── session_test.go ├── sharedsecret_test.go ├── stores.go └── user.go └── util ├── bytehelper └── ByteHelper.go ├── errorhelper └── ErrorHelper.go ├── keyhelper └── KeyHelper.go ├── medium └── Medium.go └── optional └── Integer.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | # IntelliJ 27 | .idea 28 | *.iws 29 | *.iml 30 | 31 | ## Plugin-specific files: 32 | 33 | # IntelliJ 34 | /out/ 35 | 36 | # mpeltonen/sbt-idea plugin 37 | .idea_modules/ 38 | -------------------------------------------------------------------------------- /CREDITS.md: -------------------------------------------------------------------------------- 1 | Credits 2 | ======= 3 | 4 | * [William Edwards](mailto:william@usedust.com) 5 | * [Eric Hernandez](mailto:eric@usedust.com) 6 | 7 | ## Special Thanks 8 | 9 | * Moxie Marlinspike 10 | * Trevor Perrin 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GoDoc](https://godoc.org/github.com/RadicalApp/goquery?status.png)](https://godoc.org/github.com/RadicalApp/libsignal-protocol-go) 2 | [![Go Report Card](https://goreportcard.com/badge/github.com/RadicalApp/libsignal-protocol-go)](https://goreportcard.com/report/github.com/RadicalApp/libsignal-protocol-go) 3 | [![License](https://img.shields.io/aur/license/yaourt.svg)](https://www.gnu.org/licenses/quick-guide-gplv3.en.html) 4 | [![Twitter](https://img.shields.io/badge/twitter-@DustMessaging-blue.svg?style=flat)](https://twitter.com/dustmessaging) 5 | 6 | libsignal-protocol-go 7 | ===================== 8 | 9 | Libsignal-protocol-go is a Go implementation of the Signal Client Protocol. 10 | 11 | 12 | Documentation 13 | ------------- 14 | 15 | - [API Reference](https://godoc.org/github.com/RadicalApp/libsignal-protocol-go) 16 | 17 | For more information on how the Signal Protocol works: 18 | - [Double Ratchet](https://whispersystems.org/docs/specifications/doubleratchet/) 19 | - [X3DH Key Agreement](https://whispersystems.org/docs/specifications/x3dh/) 20 | - [XEdDSA Signature Schemes](https://whispersystems.org/docs/specifications/xeddsa/) 21 | 22 | 23 | Installation 24 | ------------ 25 | 26 | Install the Signal library using the "go get" command: 27 | 28 | go get github.com/RadicalApp/libsignal-protocol-go/... 29 | 30 | 31 | Usage 32 | ----- 33 | 34 | ## Install time 35 | At install time, a signal client needs to generate its identity keys, registration id, and prekeys. 36 | 37 | ```go 38 | import ( 39 | "github.com/RadicalApp/libsignal-protocol-go/serialize" 40 | "github.com/RadicalApp/libsignal-protocol-go/session" 41 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 42 | "github.com/RadicalApp/libsignal-protocol-go/util/keyhelper" 43 | ) 44 | 45 | ... 46 | 47 | // Create a serializer that will be responsible for converting objects into 48 | // storeable and transportable bytes. 49 | serializer := serialize.NewJSONSerializer() 50 | 51 | // Generate an identity keypair 52 | identityKeyPair, err := keyhelper.GenerateIdentityKeyPair() 53 | if err != nil { 54 | panic("Unable to generate identity key pair!") 55 | } 56 | 57 | // Generate a registration id 58 | registrationID := keyhelper.GenerateRegistrationID(false) 59 | 60 | // Generate PreKeys 61 | preKeys, err := keyhelper.GeneratePreKeys(0, 100, serializer.PreKeyRecord) 62 | if err != nil { 63 | panic("Unable to generate pre keys!") 64 | } 65 | 66 | // Generate Signed PreKey 67 | signedPreKey, err := keyhelper.GenerateSignedPreKey(identityKeyPair, 0, serializer.SignedPreKeyRecord) 68 | if err != nil { 69 | panic("Unable to generate signed prekey!") 70 | } 71 | 72 | // Create durable stores for sessions, prekeys, signed prekeys, and identity keys. 73 | // These should be implemented yourself and follow the store interfaces. 74 | sessionStore := NewSessionStore() 75 | preKeyStore := NewPreKeyStore() 76 | signedPreKeyStore := NewSignedPreKeyStore() 77 | identityStore := NewIdentityKeyStore(identityKeyPair, registrationID) 78 | 79 | // Put all our pre keys in our local stores. 80 | for i := range preKeys { 81 | preKeyStore.StorePreKey( 82 | preKeys[i].ID().Value, 83 | record.NewPreKey(preKeys[i].ID().Value, preKeys[i].KeyPair(), serializer.PreKeyRecord), 84 | ) 85 | } 86 | 87 | // Store our own signed prekey 88 | signedPreKeyStore.StoreSignedPreKey( 89 | signedPreKey.ID(), 90 | record.NewSignedPreKey( 91 | signedPreKey.ID(), 92 | signedPreKey.Timestamp(), 93 | signedPreKey.KeyPair(), 94 | signedPreKey.Signature(), 95 | serializer.SignedPreKeyRecord, 96 | ), 97 | ) 98 | ``` 99 | 100 | ## Building a session 101 | 102 | A signal client needs to implement four interfaces: `IdentityKeyStore`, `PreKeyStore`, `SignedPreKeyStore`, 103 | and `SessionStore`. These will manage loading and storing of identity, prekeys, signed prekeys, and 104 | session state. 105 | 106 | Once those are implemented, you can build a session in this way: 107 | 108 | ```go 109 | // Instantiate a SessionBuilder for a remote recipientId + deviceId tuple. 110 | sessionBuilder := session.NewBuilder( 111 | sessionStore, 112 | preKeyStore, 113 | signedPreKeyStore, 114 | identityStore, 115 | address, 116 | serializer, 117 | ) 118 | 119 | // Build a session with a PreKey retrieved from the server. 120 | sessionBuilder.ProcessBundle(retrievedPreKey) 121 | 122 | // Encrypt a message to send. 123 | sessionCipher := session.NewCipher(sessionBuilder, address) 124 | message, err := sessionCipher.Encrypt([]byte{"Hello world!"}) 125 | if err != nil { 126 | panic("Unable to encrypt message!") 127 | } 128 | 129 | // Send the message with your own deliver method. The deliver method should be 130 | // your own implementation for sending an encrypted message to someone. 131 | deliver(message.serialize()) 132 | ``` 133 | 134 | ## Using your own stores 135 | 136 | In order to use the Signal library, you must first implement your own stores for persistent 137 | storage of keys, session state, etc. To get started, you can implement in-memory stores for 138 | testing. Note that for production application, you will need to write store implementations 139 | that can store persistently. 140 | 141 | Here is an example of an in-memory implementation of the Identity Key Store: 142 | 143 | ```go 144 | // IdentityKeyStore 145 | func NewInMemoryIdentityKey(identityKey *identity.KeyPair, localRegistrationID uint32) *InMemoryIdentityKey { 146 | return &InMemoryIdentityKey{ 147 | trustedKeys: make(map[*protocol.SignalAddress]*identity.Key), 148 | identityKeyPair: identityKey, 149 | localRegistrationID: localRegistrationID, 150 | } 151 | } 152 | 153 | type InMemoryIdentityKey struct { 154 | trustedKeys map[*protocol.SignalAddress]*identity.Key 155 | identityKeyPair *identity.KeyPair 156 | localRegistrationID uint32 157 | } 158 | 159 | func (i *InMemoryIdentityKey) GetIdentityKeyPair() *identity.KeyPair { 160 | return i.identityKeyPair 161 | } 162 | 163 | func (i *InMemoryIdentityKey) GetLocalRegistrationId() uint32 { 164 | return i.localRegistrationID 165 | } 166 | 167 | func (i *InMemoryIdentityKey) SaveIdentity(address *protocol.SignalAddress, identityKey *identity.Key) { 168 | i.trustedKeys[address] = identityKey 169 | } 170 | 171 | func (i *InMemoryIdentityKey) IsTrustedIdentity(address *protocol.SignalAddress, identityKey *identity.Key) bool { 172 | trusted := i.trustedKeys[address] 173 | return (trusted == nil || trusted.Fingerprint() == identityKey.Fingerprint()) 174 | } 175 | ``` 176 | 177 | ## Using your own serializer 178 | 179 | The Go implementation of the Signal library uses serializer interfaces for encoding and decoding 180 | data for use in sending data objects over the network and local storage. This allows users of 181 | the Signal library to use their own serialization format (such as JSON, Protobuffers, etc.). It 182 | also allows more flexibility for future serialization formats that might be better than the 183 | current ones available. 184 | 185 | Currently the library includes a JSON implementation of serializing all Signal data structures. 186 | If you want to write a new serialization implementation, you will need to write structures 187 | that implement the interfaces for each object and write a constructor function to create a 188 | new `Serializer` object using your implementations. 189 | 190 | A serializer must implement the serializer interfaces for the following structs: 191 | 192 | * `protocol.SignalMessage` 193 | * `protocol.PreKeySignalMessage` 194 | * `protocol.SenderKeyMessage` 195 | * `protocol.SenderKeyDistributionMessage` 196 | * `record.SignedPreKey` 197 | * `record.PreKey` 198 | * `record.State` 199 | * `record.Session` 200 | * `record.SenderKey` 201 | * `record.SenderKeyState` 202 | 203 | Here is an example of the constructor function for a `Serializer` that uses JSON implementations: 204 | 205 | ```go 206 | import "github.com/RadicalApp/libsignal-protocol-go/serializer" 207 | 208 | // NewJSONSerializer will return a serializer for all Signal objects that will 209 | // be responsible for converting objects to and from JSON bytes. 210 | func NewJSONSerializer() *serializer.Serializer { 211 | serializer := serializer.NewSerializer() 212 | 213 | serializer.SignalMessage = &JSONSignalMessageSerializer{} 214 | serializer.PreKeySignalMessage = &JSONPreKeySignalMessageSerializer{} 215 | serializer.SignedPreKeyRecord = &JSONSignedPreKeyRecordSerializer{} 216 | serializer.PreKeyRecord = &JSONPreKeyRecordSerializer{} 217 | serializer.State = &JSONStateSerializer{} 218 | serializer.Session = &JSONSessionSerializer{} 219 | serializer.SenderKeyMessage = &JSONSenderKeyMessageSerializer{} 220 | serializer.SenderKeyDistributionMessage = &JSONSenderKeyDistributionMessageSerializer{} 221 | serializer.SenderKeyRecord = &JSONSenderKeySessionSerializer{} 222 | serializer.SenderKeyState = &JSONSenderKeyStateSerializer{} 223 | 224 | return serializer 225 | } 226 | ``` 227 | -------------------------------------------------------------------------------- /cipher/Cipher.go: -------------------------------------------------------------------------------- 1 | // Package cipher is a package for common encrypt/decrypt of symmetric key messages. 2 | package cipher 3 | 4 | import ( 5 | "bytes" 6 | "crypto/aes" 7 | "crypto/cipher" 8 | "errors" 9 | ) 10 | 11 | // Decrypt will use the given key, iv, and ciphertext and return 12 | // the plaintext bytes. 13 | func Decrypt(iv, key, ciphertext []byte) ([]byte, error) { 14 | block, err := aes.NewCipher(key) 15 | if err != nil { 16 | return nil, err 17 | } 18 | if len(ciphertext) < aes.BlockSize { 19 | return nil, errors.New("ciphertext too short") 20 | } 21 | cbc := cipher.NewCBCDecrypter(block, iv) 22 | cbc.CryptBlocks(ciphertext, ciphertext) 23 | 24 | unpaddedText, err := pkcs7Unpad(ciphertext, aes.BlockSize) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | return unpaddedText, nil 30 | } 31 | 32 | // Encrypt will use the given iv, key, and plaintext bytes 33 | // and return ciphertext bytes. 34 | func Encrypt(iv, key, plaintext []byte) ([]byte, error) { 35 | block, err := aes.NewCipher(key) 36 | if err != nil { 37 | return nil, err 38 | } 39 | paddedText, err := pkcs7Pad(plaintext, block.BlockSize()) 40 | if err != nil { 41 | return nil, err 42 | } 43 | ciphertext := make([]byte, len(paddedText)) 44 | mode := cipher.NewCBCEncrypter(block, iv) 45 | mode.CryptBlocks(ciphertext, paddedText) 46 | 47 | return ciphertext, nil 48 | } 49 | 50 | // PKCS7 padding. 51 | 52 | // PKCS7 errors. 53 | var ( 54 | // ErrInvalidBlockSize indicates hash blocksize <= 0. 55 | ErrInvalidBlockSize = errors.New("invalid blocksize") 56 | 57 | // ErrInvalidPKCS7Data indicates bad input to PKCS7 pad or unpad. 58 | ErrInvalidPKCS7Data = errors.New("invalid PKCS7 data (empty or not padded)") 59 | 60 | // ErrInvalidPKCS7Padding indicates PKCS7 unpad fails to bad input. 61 | ErrInvalidPKCS7Padding = errors.New("invalid padding on input") 62 | ) 63 | 64 | // pkcs7Pad right-pads the given byte slice with 1 to n bytes, where 65 | // n is the block size. The size of the result is x times n, where x 66 | // is at least 1. 67 | func pkcs7Pad(b []byte, blocksize int) ([]byte, error) { 68 | if blocksize <= 0 { 69 | return nil, ErrInvalidBlockSize 70 | } 71 | if b == nil || len(b) == 0 { 72 | return nil, ErrInvalidPKCS7Data 73 | } 74 | n := blocksize - (len(b) % blocksize) 75 | pb := make([]byte, len(b)+n) 76 | copy(pb, b) 77 | copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n)) 78 | return pb, nil 79 | } 80 | 81 | // pkcs7Unpad validates and unpads data from the given bytes slice. 82 | // The returned value will be 1 to n bytes smaller depending on the 83 | // amount of padding, where n is the block size. 84 | func pkcs7Unpad(b []byte, blocksize int) ([]byte, error) { 85 | if blocksize <= 0 { 86 | return nil, ErrInvalidBlockSize 87 | } 88 | if b == nil || len(b) == 0 { 89 | return nil, ErrInvalidPKCS7Data 90 | } 91 | if len(b)%blocksize != 0 { 92 | return nil, ErrInvalidPKCS7Padding 93 | } 94 | c := b[len(b)-1] 95 | n := int(c) 96 | if n == 0 || n > len(b) { 97 | return nil, ErrInvalidPKCS7Padding 98 | } 99 | for i := 0; i < n; i++ { 100 | if b[len(b)-n+i] != c { 101 | return nil, ErrInvalidPKCS7Padding 102 | } 103 | } 104 | return b[:len(b)-n], nil 105 | } 106 | -------------------------------------------------------------------------------- /ecc/Curve.go: -------------------------------------------------------------------------------- 1 | package ecc 2 | 3 | import ( 4 | "crypto/rand" 5 | "errors" 6 | "github.com/RadicalApp/complete" 7 | "github.com/RadicalApp/libsignal-protocol-go/logger" 8 | "golang.org/x/crypto/curve25519" 9 | "io" 10 | ) 11 | 12 | // DjbType is the Diffie-Hellman curve type (curve25519) created by D. J. Bernstein. 13 | const DjbType = 0x05 14 | 15 | // DecodePoint will take the given bytes and offset and return an ECPublicKeyable object. 16 | // This is used to check the byte at the given offset in the byte array for a special 17 | // "type" byte that will determine the key type. Currently only DJB EC keys are supported. 18 | func DecodePoint(bytes []byte, offset int) (ECPublicKeyable, error) { 19 | keyType := bytes[offset] & 0xFF 20 | 21 | switch keyType { 22 | case DjbType: 23 | keyBytes := [32]byte{} 24 | copy(keyBytes[:], bytes[offset+1:]) 25 | return NewDjbECPublicKey(keyBytes), nil 26 | default: 27 | return nil, errors.New("Bad key type: " + string(keyType)) 28 | } 29 | } 30 | 31 | // GenerateKeyPair returns an EC Key Pair. 32 | func GenerateKeyPair() (*ECKeyPair, error) { 33 | logger.Debug("Generating EC Key Pair...") 34 | // Get cryptographically secure random numbers. 35 | random := rand.Reader 36 | 37 | // Create a byte array for our public and private keys. 38 | var private, public [32]byte 39 | 40 | // Generate some random data 41 | _, err := io.ReadFull(random, private[:]) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | // Documented at: http://cr.yp.to/ecdh.html 47 | private[0] &= 248 48 | private[31] &= 127 49 | private[31] |= 64 50 | 51 | curve25519.ScalarBaseMult(&public, &private) 52 | 53 | // Put data into our keypair struct 54 | djbECPub := NewDjbECPublicKey(public) 55 | djbECPriv := NewDjbECPrivateKey(private) 56 | keypair := NewECKeyPair(djbECPub, djbECPriv) 57 | 58 | logger.Debug("Returning keypair: ", keypair) 59 | 60 | return keypair, nil 61 | } 62 | 63 | // VerifySignature verifies that the message was signed with the given key. 64 | func VerifySignature(signingKey ECPublicKeyable, message []byte, signature [64]byte) bool { 65 | logger.Debug("Verifying signature of bytes: ", message) 66 | publicKey := signingKey.PublicKey() 67 | valid := verify(publicKey, message, &signature) 68 | logger.Debug("Signature valid: ", valid) 69 | return valid 70 | } 71 | 72 | // VerifySignatureAsync verifies that a message was signed with the given key asyncronously. 73 | func VerifySignatureAsync(signingKey ECPublicKeyable, message []byte, signature [64]byte, completion complete.Completionable) { 74 | go func() { 75 | r := VerifySignature(signingKey, message, signature) 76 | if r == false { 77 | completion.OnFailure("Signature invalid") 78 | return 79 | } 80 | result := complete.NewResult(r) 81 | completion.OnSuccess(&result) 82 | }() 83 | } 84 | 85 | // CalculateSignature signs a message with the given private key. 86 | func CalculateSignature(signingKey ECPrivateKeyable, message []byte) [64]byte { 87 | logger.Debug("Signing bytes with signing key") 88 | // Get cryptographically secure random numbers. 89 | var random [64]byte 90 | r := rand.Reader 91 | io.ReadFull(r, random[:]) 92 | 93 | // Get the private key. 94 | privateKey := signingKey.Serialize() 95 | 96 | // Sign the message. 97 | signature := sign(&privateKey, message, random) 98 | return *signature 99 | } 100 | 101 | // CalculateSignatureAsync signs a message with the given private key asyncronously. 102 | func CalculateSignatureAsync(signingKey ECPrivateKeyable, message []byte, completion complete.Completionable) { 103 | go func() { 104 | signature := CalculateSignature(signingKey, message) 105 | if signature == [64]byte{} { 106 | completion.OnFailure("Error calculating signature") 107 | return 108 | } 109 | result := complete.NewResult(signature) 110 | completion.OnSuccess(&result) 111 | }() 112 | } 113 | -------------------------------------------------------------------------------- /ecc/DjbECPublicKey.go: -------------------------------------------------------------------------------- 1 | package ecc 2 | 3 | // NewDjbECPublicKey creates a new Curve25519 public key with the given bytes. 4 | func NewDjbECPublicKey(publicKey [32]byte) *DjbECPublicKey { 5 | key := DjbECPublicKey{ 6 | publicKey: publicKey, 7 | } 8 | return &key 9 | } 10 | 11 | // DjbECPublicKey implements the ECPublicKey interface and uses Curve25519. 12 | type DjbECPublicKey struct { 13 | publicKey [32]byte 14 | } 15 | 16 | // PublicKey returns the EC public key as a byte array. 17 | func (d *DjbECPublicKey) PublicKey() [32]byte { 18 | return d.publicKey 19 | } 20 | 21 | // Serialize returns the public key prepended by the DjbType value. 22 | func (d *DjbECPublicKey) Serialize() []byte { 23 | return append([]byte{DjbType}, d.publicKey[:]...) 24 | } 25 | 26 | // Type returns the DjbType value. 27 | func (d *DjbECPublicKey) Type() int { 28 | return DjbType 29 | } 30 | -------------------------------------------------------------------------------- /ecc/DkbECPrivateKey.go: -------------------------------------------------------------------------------- 1 | package ecc 2 | 3 | // NewDjbECPrivateKey returns a new EC private key with the given bytes. 4 | func NewDjbECPrivateKey(key [32]byte) *DjbECPrivateKey { 5 | private := DjbECPrivateKey{ 6 | privateKey: key, 7 | } 8 | return &private 9 | } 10 | 11 | // DjbECPrivateKey implements the ECPrivateKey interface and uses Curve25519. 12 | type DjbECPrivateKey struct { 13 | privateKey [32]byte 14 | } 15 | 16 | // PrivateKey returns the private key as a byte-array. 17 | func (d *DjbECPrivateKey) PrivateKey() [32]byte { 18 | return d.privateKey 19 | } 20 | 21 | // Serialize returns the private key as a byte-array. 22 | func (d *DjbECPrivateKey) Serialize() [32]byte { 23 | return d.privateKey 24 | } 25 | 26 | // Type returns the EC type value. 27 | func (d *DjbECPrivateKey) Type() int { 28 | return DjbType 29 | } 30 | -------------------------------------------------------------------------------- /ecc/Doc.go: -------------------------------------------------------------------------------- 1 | // Package ecc provides a way to generate, sign, and use Elliptic-Curve 2 | // X25519 Cryptography keys. 3 | package ecc 4 | -------------------------------------------------------------------------------- /ecc/ECKeyPair.go: -------------------------------------------------------------------------------- 1 | package ecc 2 | 3 | // NewECKeyPair returns a new elliptic curve keypair given the specified public and private keys. 4 | func NewECKeyPair(publicKey ECPublicKeyable, privateKey ECPrivateKeyable) *ECKeyPair { 5 | keypair := ECKeyPair{ 6 | publicKey: publicKey, 7 | privateKey: privateKey, 8 | } 9 | 10 | return &keypair 11 | } 12 | 13 | // ECKeyPair is a combination of both public and private elliptic curve keys. 14 | type ECKeyPair struct { 15 | publicKey ECPublicKeyable 16 | privateKey ECPrivateKeyable 17 | } 18 | 19 | // PublicKey returns the public key from the key pair. 20 | func (e *ECKeyPair) PublicKey() ECPublicKeyable { 21 | return e.publicKey 22 | } 23 | 24 | // PrivateKey returns the private key from the key pair. 25 | func (e *ECKeyPair) PrivateKey() ECPrivateKeyable { 26 | return e.privateKey 27 | } 28 | -------------------------------------------------------------------------------- /ecc/ECPrivateKey.go: -------------------------------------------------------------------------------- 1 | package ecc 2 | 3 | // ECPrivateKeyable is an interface for all elliptic curve private keys. 4 | type ECPrivateKeyable interface { 5 | Serialize() [32]byte 6 | Type() int 7 | } 8 | -------------------------------------------------------------------------------- /ecc/ECPublicKey.go: -------------------------------------------------------------------------------- 1 | package ecc 2 | 3 | // KeySize is the size of EC keys (32) with the EC type byte prepended to it. 4 | const KeySize int = 33 5 | 6 | // ECPublicKeyable is an interface for all elliptic curve public keys. 7 | type ECPublicKeyable interface { 8 | Serialize() []byte 9 | Type() int 10 | PublicKey() [32]byte 11 | } 12 | -------------------------------------------------------------------------------- /ecc/SignCurve25519.go: -------------------------------------------------------------------------------- 1 | package ecc 2 | 3 | // Package curve25519sign implements a signature scheme based on Curve25519 keys. 4 | // See https://moderncrypto.org/mail-archive/curves/2014/000205.html for details. 5 | 6 | import ( 7 | "crypto/sha512" 8 | 9 | "github.com/agl/ed25519" 10 | "github.com/agl/ed25519/edwards25519" 11 | ) 12 | 13 | // sign signs the message with privateKey and returns a signature as a byte slice. 14 | func sign(privateKey *[32]byte, message []byte, random [64]byte) *[64]byte { 15 | 16 | // Calculate Ed25519 public key from Curve25519 private key 17 | var A edwards25519.ExtendedGroupElement 18 | var publicKey [32]byte 19 | edwards25519.GeScalarMultBase(&A, privateKey) 20 | A.ToBytes(&publicKey) 21 | 22 | // Calculate r 23 | diversifier := [32]byte{ 24 | 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 25 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 26 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 27 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} 28 | 29 | var r [64]byte 30 | hash := sha512.New() 31 | hash.Write(diversifier[:]) 32 | hash.Write(privateKey[:]) 33 | hash.Write(message) 34 | hash.Write(random[:]) 35 | hash.Sum(r[:0]) 36 | 37 | // Calculate R 38 | var rReduced [32]byte 39 | edwards25519.ScReduce(&rReduced, &r) 40 | var R edwards25519.ExtendedGroupElement 41 | edwards25519.GeScalarMultBase(&R, &rReduced) 42 | 43 | var encodedR [32]byte 44 | R.ToBytes(&encodedR) 45 | 46 | // Calculate S = r + SHA2-512(R || A_ed || msg) * a (mod L) 47 | var hramDigest [64]byte 48 | hash.Reset() 49 | hash.Write(encodedR[:]) 50 | hash.Write(publicKey[:]) 51 | hash.Write(message) 52 | hash.Sum(hramDigest[:0]) 53 | var hramDigestReduced [32]byte 54 | edwards25519.ScReduce(&hramDigestReduced, &hramDigest) 55 | 56 | var s [32]byte 57 | edwards25519.ScMulAdd(&s, &hramDigestReduced, privateKey, &rReduced) 58 | 59 | signature := new([64]byte) 60 | copy(signature[:], encodedR[:]) 61 | copy(signature[32:], s[:]) 62 | signature[63] |= publicKey[31] & 0x80 63 | 64 | return signature 65 | } 66 | 67 | // verify checks whether the message has a valid signature. 68 | func verify(publicKey [32]byte, message []byte, signature *[64]byte) bool { 69 | 70 | publicKey[31] &= 0x7F 71 | 72 | /* Convert the Curve25519 public key into an Ed25519 public key. In 73 | particular, convert Curve25519's "montgomery" x-coordinate into an 74 | Ed25519 "edwards" y-coordinate: 75 | 76 | ed_y = (mont_x - 1) / (mont_x + 1) 77 | 78 | NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp 79 | 80 | Then move the sign bit into the pubkey from the signature. 81 | */ 82 | 83 | var edY, one, montX, montXMinusOne, montXPlusOne edwards25519.FieldElement 84 | edwards25519.FeFromBytes(&montX, &publicKey) 85 | edwards25519.FeOne(&one) 86 | edwards25519.FeSub(&montXMinusOne, &montX, &one) 87 | edwards25519.FeAdd(&montXPlusOne, &montX, &one) 88 | edwards25519.FeInvert(&montXPlusOne, &montXPlusOne) 89 | edwards25519.FeMul(&edY, &montXMinusOne, &montXPlusOne) 90 | 91 | var A_ed [32]byte 92 | edwards25519.FeToBytes(&A_ed, &edY) 93 | 94 | A_ed[31] |= signature[63] & 0x80 95 | signature[63] &= 0x7F 96 | 97 | return ed25519.Verify(&A_ed, message, signature) 98 | } 99 | -------------------------------------------------------------------------------- /fingerprint/DisplayFingerprint.go: -------------------------------------------------------------------------------- 1 | package fingerprint 2 | 3 | import ( 4 | "fmt" 5 | "github.com/RadicalApp/libsignal-protocol-go/util/bytehelper" 6 | ) 7 | 8 | // NewDisplay will return a new displayable fingerprint. 9 | func NewDisplay(localFingerprint, remoteFingerprint []byte) *Display { 10 | return &Display{ 11 | localFingerprintNumbers: displayStringFor(localFingerprint), 12 | remoteFingerprintNumbers: displayStringFor(remoteFingerprint), 13 | } 14 | } 15 | 16 | // Display is a structure for displayable fingerprints. 17 | type Display struct { 18 | localFingerprintNumbers string 19 | remoteFingerprintNumbers string 20 | } 21 | 22 | // DisplayText will return a string of the fingerprint numbers. 23 | func (d *Display) DisplayText() string { 24 | if d.localFingerprintNumbers < d.remoteFingerprintNumbers { 25 | return d.localFingerprintNumbers + d.remoteFingerprintNumbers 26 | } 27 | return d.remoteFingerprintNumbers + d.localFingerprintNumbers 28 | } 29 | 30 | // displayStringFor will return a displayable string representation 31 | // of the given fingerprint. 32 | func displayStringFor(fingerprint []byte) string { 33 | return encodedChunk(fingerprint, 0) + 34 | encodedChunk(fingerprint, 5) + 35 | encodedChunk(fingerprint, 10) + 36 | encodedChunk(fingerprint, 15) + 37 | encodedChunk(fingerprint, 20) + 38 | encodedChunk(fingerprint, 25) 39 | } 40 | 41 | // encodedChunk will return an encoded string of the given hash. 42 | func encodedChunk(hash []byte, offset int) string { 43 | chunk := bytehelper.Bytes5ToInt64(hash, offset) % 100000 44 | return fmt.Sprintf("%05d", chunk) 45 | } 46 | -------------------------------------------------------------------------------- /fingerprint/Doc.go: -------------------------------------------------------------------------------- 1 | // Package fingerprint provides a way to generate a visually verifiable 2 | // fingerprint of keys. 3 | package fingerprint 4 | -------------------------------------------------------------------------------- /fingerprint/Fingerprint.go: -------------------------------------------------------------------------------- 1 | package fingerprint 2 | 3 | // NewFingerprint will return a new Fingerprint structure. 4 | func NewFingerprint(displayFingerprint *Display) *Fingerprint { 5 | return &Fingerprint{ 6 | fingerprintDisplay: displayFingerprint, 7 | } 8 | } 9 | 10 | // Fingerprint is a structure for returning a displayable and scannable 11 | // fingerprint for identity verification. 12 | type Fingerprint struct { 13 | fingerprintDisplay *Display 14 | fingerprintScan string 15 | } 16 | 17 | // Display will return a fingerprint display structure for getting a 18 | // string representation of given keys. 19 | func (f *Fingerprint) Display() *Display { 20 | return f.fingerprintDisplay 21 | } 22 | 23 | // Scan will return a fingerprint scan structure for getting a scannable 24 | // representation of given keys. 25 | func (f *Fingerprint) Scan() string { 26 | return f.fingerprintScan 27 | } 28 | -------------------------------------------------------------------------------- /fingerprint/FingerprintGenerator.go: -------------------------------------------------------------------------------- 1 | package fingerprint 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 5 | ) 6 | 7 | // FingerprintGenerator is an interface for fingerprint generators. 8 | type FingerprintGenerator interface { 9 | CreateFor(localStableIdentifier, remoteStableIdentifier string, localIdentityKey, remoteIdentityKey *identity.Key) *Fingerprint 10 | CreateForMultiple(localStableIdentifier, remoteStableIdentifier string, localIdentityKey, remoteIdentityKey []*identity.Key) *Fingerprint 11 | } 12 | -------------------------------------------------------------------------------- /groups/GroupCipher.go: -------------------------------------------------------------------------------- 1 | package groups 2 | 3 | import ( 4 | "errors" 5 | "github.com/RadicalApp/libsignal-protocol-go/cipher" 6 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 7 | "github.com/RadicalApp/libsignal-protocol-go/groups/ratchet" 8 | "github.com/RadicalApp/libsignal-protocol-go/groups/state/record" 9 | "github.com/RadicalApp/libsignal-protocol-go/groups/state/store" 10 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 11 | "strconv" 12 | ) 13 | 14 | // NewGroupCipher will return a new group message cipher that can be used for 15 | // encrypt/decrypt operations. 16 | func NewGroupCipher(builder *SessionBuilder, senderKeyID *protocol.SenderKeyName, 17 | senderKeyStore store.SenderKey) *GroupCipher { 18 | 19 | return &GroupCipher{ 20 | senderKeyID: senderKeyID, 21 | senderKeyStore: senderKeyStore, 22 | sessionBuilder: builder, 23 | } 24 | } 25 | 26 | // GroupCipher is the main entry point for group encrypt/decrypt operations. 27 | // Once a session has been established, this can be used for 28 | // all encrypt/decrypt operations within that session. 29 | type GroupCipher struct { 30 | senderKeyID *protocol.SenderKeyName 31 | senderKeyStore store.SenderKey 32 | sessionBuilder *SessionBuilder 33 | } 34 | 35 | // Encrypt will take the given message in bytes and return encrypted bytes. 36 | func (c *GroupCipher) Encrypt(plaintext []byte) (protocol.CiphertextMessage, error) { 37 | // Load the sender key based on id from our store. 38 | keyRecord := c.senderKeyStore.LoadSenderKey(c.senderKeyID) 39 | senderKeyState, err := keyRecord.SenderKeyState() 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | // Get the message key from the senderkey state. 45 | senderKey, err := senderKeyState.SenderChainKey().SenderMessageKey() 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | // Encrypt the plaintext. 51 | ciphertext, err := cipher.Encrypt(senderKey.Iv(), senderKey.CipherKey(), plaintext) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | senderKeyMessage := protocol.NewSenderKeyMessage( 57 | senderKeyState.KeyID(), 58 | senderKey.Iteration(), 59 | ciphertext, 60 | senderKeyState.SigningKey().PrivateKey(), 61 | c.sessionBuilder.serializer.SenderKeyMessage, 62 | ) 63 | 64 | senderKeyState.SetSenderChainKey(senderKeyState.SenderChainKey().Next()) 65 | c.senderKeyStore.StoreSenderKey(c.senderKeyID, keyRecord) 66 | 67 | return senderKeyMessage, nil 68 | } 69 | 70 | // Decrypt decrypts the given message using an existing session that 71 | // is stored in the senderKey store. 72 | func (c *GroupCipher) Decrypt(senderKeyMessage *protocol.SenderKeyMessage) ([]byte, error) { 73 | keyRecord := c.senderKeyStore.LoadSenderKey(c.senderKeyID) 74 | 75 | if keyRecord.IsEmpty() { 76 | return nil, errors.New("No sender key for: " + c.senderKeyID.GroupID()) 77 | } 78 | 79 | // Get the senderkey state by id. 80 | senderKeyState, err := keyRecord.GetSenderKeyStateByID(senderKeyMessage.KeyID()) 81 | if err != nil { 82 | return nil, err 83 | } 84 | 85 | // Verify the signature of the senderkey message. 86 | verified := c.verifySignature(senderKeyState.SigningKey().PublicKey(), senderKeyMessage) 87 | if !verified { 88 | return nil, errors.New("Sender Key State failed verification with given pub key!") 89 | } 90 | 91 | senderKey, err := c.getSenderKey(senderKeyState, senderKeyMessage.Iteration()) 92 | if err != nil { 93 | return nil, err 94 | } 95 | 96 | // Decrypt the message ciphertext. 97 | plaintext, err := cipher.Decrypt(senderKey.Iv(), senderKey.CipherKey(), senderKeyMessage.Ciphertext()) 98 | if err != nil { 99 | return nil, err 100 | } 101 | 102 | // Store the sender key by id. 103 | c.senderKeyStore.StoreSenderKey(c.senderKeyID, keyRecord) 104 | 105 | return plaintext, nil 106 | } 107 | 108 | // verifySignature will verify the signature of the senderkey message with 109 | // the given public key. 110 | func (c *GroupCipher) verifySignature(signingPubKey ecc.ECPublicKeyable, 111 | senderKeyMessage *protocol.SenderKeyMessage) bool { 112 | 113 | return ecc.VerifySignature(signingPubKey, senderKeyMessage.Serialize(), senderKeyMessage.Signature()) 114 | } 115 | 116 | func (c *GroupCipher) getSenderKey(senderKeyState *record.SenderKeyState, iteration uint32) (*ratchet.SenderMessageKey, error) { 117 | senderChainKey := senderKeyState.SenderChainKey() 118 | if senderChainKey.Iteration() > iteration { 119 | if senderKeyState.HasSenderMessageKey(iteration) { 120 | return senderKeyState.RemoveSenderMessageKey(iteration), nil 121 | } 122 | i1 := strconv.Itoa(int(senderChainKey.Iteration())) 123 | i2 := strconv.Itoa(int(iteration)) 124 | return nil, errors.New("Received message with old counter: " + i1 + ", " + i2) 125 | } 126 | 127 | if iteration-senderChainKey.Iteration() > 2000 { 128 | return nil, errors.New("Over 2000 messages into the future!") 129 | } 130 | 131 | for senderChainKey.Iteration() < iteration { 132 | senderMessageKey, err := senderChainKey.SenderMessageKey() 133 | if err != nil { 134 | return nil, err 135 | } 136 | senderKeyState.AddSenderMessageKey(senderMessageKey) 137 | senderChainKey = senderChainKey.Next() 138 | } 139 | 140 | senderKeyState.SetSenderChainKey(senderChainKey.Next()) 141 | return senderChainKey.SenderMessageKey() 142 | } 143 | -------------------------------------------------------------------------------- /groups/GroupSessionBuilder.go: -------------------------------------------------------------------------------- 1 | // Package groups is responsible for setting up group SenderKey encrypted sessions. 2 | // Once a session has been established, GroupCipher can be used to encrypt/decrypt 3 | // messages in that session. 4 | // 5 | // The built sessions are unidirectional: they can be used either for sending or 6 | // for receiving, but not both. Sessions are constructed per (groupId + senderId + 7 | // deviceId) tuple. Remote logical users are identified by their senderId, and each 8 | // logical recipientId can have multiple physical devices. 9 | package groups 10 | 11 | import ( 12 | "github.com/RadicalApp/libsignal-protocol-go/groups/state/record" 13 | "github.com/RadicalApp/libsignal-protocol-go/groups/state/store" 14 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 15 | "github.com/RadicalApp/libsignal-protocol-go/serialize" 16 | "github.com/RadicalApp/libsignal-protocol-go/util/keyhelper" 17 | ) 18 | 19 | // NewGroupSessionBuilder will return a new group session builder. 20 | func NewGroupSessionBuilder(senderKeyStore store.SenderKey, 21 | serializer *serialize.Serializer) *SessionBuilder { 22 | 23 | return &SessionBuilder{ 24 | senderKeyStore: senderKeyStore, 25 | serializer: serializer, 26 | } 27 | } 28 | 29 | // SessionBuilder is a structure for building group sessions. 30 | type SessionBuilder struct { 31 | senderKeyStore store.SenderKey 32 | serializer *serialize.Serializer 33 | } 34 | 35 | // Process will process an incoming group message and set up the corresponding 36 | // session for it. 37 | func (b *SessionBuilder) Process(senderKeyName *protocol.SenderKeyName, 38 | msg *protocol.SenderKeyDistributionMessage) { 39 | 40 | senderKeyRecord := b.senderKeyStore.LoadSenderKey(senderKeyName) 41 | if senderKeyRecord == nil { 42 | senderKeyRecord = record.NewSenderKey(b.serializer.SenderKeyRecord, b.serializer.SenderKeyState) 43 | } 44 | senderKeyRecord.AddSenderKeyState(msg.ID(), msg.Iteration(), msg.ChainKey(), msg.SignatureKey()) 45 | b.senderKeyStore.StoreSenderKey(senderKeyName, senderKeyRecord) 46 | } 47 | 48 | // Create will create a new group session for the given name. 49 | func (b *SessionBuilder) Create(senderKeyName *protocol.SenderKeyName) (*protocol.SenderKeyDistributionMessage, error) { 50 | // Load the senderkey by name 51 | senderKeyRecord := b.senderKeyStore.LoadSenderKey(senderKeyName) 52 | 53 | // If the record is empty, generate new keys. 54 | if senderKeyRecord == nil || senderKeyRecord.IsEmpty() { 55 | senderKeyRecord = record.NewSenderKey(b.serializer.SenderKeyRecord, b.serializer.SenderKeyState) 56 | signingKey, err := keyhelper.GenerateSenderSigningKey() 57 | if err != nil { 58 | return nil, err 59 | } 60 | senderKeyRecord.SetSenderKeyState( 61 | keyhelper.GenerateSenderKeyID(), 0, 62 | keyhelper.GenerateSenderKey(), 63 | signingKey, 64 | ) 65 | b.senderKeyStore.StoreSenderKey(senderKeyName, senderKeyRecord) 66 | } 67 | 68 | // Get the senderkey state. 69 | state, err := senderKeyRecord.SenderKeyState() 70 | if err != nil { 71 | return nil, err 72 | } 73 | 74 | // Create the group message to return. 75 | senderKeyDistributionMessage := protocol.NewSenderKeyDistributionMessage( 76 | state.KeyID(), 77 | state.SenderChainKey().Iteration(), 78 | state.SenderChainKey().Seed(), 79 | state.SigningKey().PublicKey(), 80 | b.serializer.SenderKeyDistributionMessage, 81 | ) 82 | 83 | return senderKeyDistributionMessage, nil 84 | } 85 | -------------------------------------------------------------------------------- /groups/ratchet/Doc.go: -------------------------------------------------------------------------------- 1 | // Package ratchet provides the methods necessary to establish a ratchet 2 | // session for group messaging. 3 | package ratchet 4 | -------------------------------------------------------------------------------- /groups/ratchet/SenderChainKey.go: -------------------------------------------------------------------------------- 1 | package ratchet 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha256" 6 | ) 7 | 8 | var messageKeySeed = []byte{0x01} 9 | var chainKeySeed = []byte{0x02} 10 | 11 | // NewSenderChainKey will return a new SenderChainKey. 12 | func NewSenderChainKey(iteration uint32, chainKey []byte) *SenderChainKey { 13 | return &SenderChainKey{ 14 | iteration: iteration, 15 | chainKey: chainKey, 16 | } 17 | } 18 | 19 | // NewSenderChainKeyFromStruct will return a new chain key object from the 20 | // given serializeable structure. 21 | func NewSenderChainKeyFromStruct(structure *SenderChainKeyStructure) *SenderChainKey { 22 | return &SenderChainKey{ 23 | iteration: structure.Iteration, 24 | chainKey: structure.ChainKey, 25 | } 26 | } 27 | 28 | // NewStructFromSenderChainKeys returns a serializeable structure of chain keys. 29 | func NewStructFromSenderChainKey(key *SenderChainKey) *SenderChainKeyStructure { 30 | return &SenderChainKeyStructure{ 31 | Iteration: key.iteration, 32 | ChainKey: key.chainKey, 33 | } 34 | } 35 | 36 | // SenderChainKeyStructure is a serializeable structure of SenderChainKeys. 37 | type SenderChainKeyStructure struct { 38 | Iteration uint32 39 | ChainKey []byte 40 | } 41 | 42 | type SenderChainKey struct { 43 | iteration uint32 44 | chainKey []byte 45 | } 46 | 47 | func (k *SenderChainKey) Iteration() uint32 { 48 | return k.iteration 49 | } 50 | 51 | func (k *SenderChainKey) SenderMessageKey() (*SenderMessageKey, error) { 52 | return NewSenderMessageKey(k.iteration, k.getDerivative(messageKeySeed, k.chainKey)) 53 | } 54 | 55 | func (k *SenderChainKey) Next() *SenderChainKey { 56 | return NewSenderChainKey(k.iteration+1, k.getDerivative(chainKeySeed, k.chainKey)) 57 | } 58 | 59 | func (k *SenderChainKey) Seed() []byte { 60 | return k.chainKey 61 | } 62 | 63 | func (k *SenderChainKey) getDerivative(seed []byte, key []byte) []byte { 64 | mac := hmac.New(sha256.New, key[:]) 65 | mac.Write(seed) 66 | 67 | return mac.Sum(nil) 68 | } 69 | -------------------------------------------------------------------------------- /groups/ratchet/SenderMessageKey.go: -------------------------------------------------------------------------------- 1 | package ratchet 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/kdf" 5 | "github.com/RadicalApp/libsignal-protocol-go/util/bytehelper" 6 | ) 7 | 8 | // KdfInfo is optional bytes to include in deriving secrets with KDF. 9 | const KdfInfo string = "WhisperGroup" 10 | 11 | // NewSenderMessageKey will return a new sender message key using the given 12 | // iteration and seed. 13 | func NewSenderMessageKey(iteration uint32, seed []byte) (*SenderMessageKey, error) { 14 | derivative, err := kdf.DeriveSecrets(seed, nil, []byte(KdfInfo), 48) 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | // Split our derived secrets into 2 parts 20 | parts := bytehelper.Split(derivative, 16, 32) 21 | 22 | // Build the message key. 23 | senderKeyMessage := &SenderMessageKey{ 24 | iteration: iteration, 25 | seed: seed, 26 | iv: parts[0], 27 | cipherKey: parts[1], 28 | } 29 | 30 | return senderKeyMessage, nil 31 | } 32 | 33 | // NewSenderMessageKeyFromStruct will return a new message key object from the 34 | // given serializeable structure. 35 | func NewSenderMessageKeyFromStruct(structure *SenderMessageKeyStructure) *SenderMessageKey { 36 | return &SenderMessageKey{ 37 | iteration: structure.Iteration, 38 | iv: structure.IV, 39 | cipherKey: structure.CipherKey, 40 | seed: structure.Seed, 41 | } 42 | } 43 | 44 | // NewStructFromSenderMessageKey returns a serializeable structure of message keys. 45 | func NewStructFromSenderMessageKey(key *SenderMessageKey) *SenderMessageKeyStructure { 46 | return &SenderMessageKeyStructure{ 47 | CipherKey: key.cipherKey, 48 | Iteration: key.iteration, 49 | IV: key.iv, 50 | Seed: key.seed, 51 | } 52 | } 53 | 54 | // SenderMessageKeyStructure is a serializeable structure of SenderMessageKeys. 55 | type SenderMessageKeyStructure struct { 56 | Iteration uint32 57 | IV []byte 58 | CipherKey []byte 59 | Seed []byte 60 | } 61 | 62 | // SenderMessageKey is a structure for sender message keys used in group 63 | // messaging. 64 | type SenderMessageKey struct { 65 | iteration uint32 66 | iv []byte 67 | cipherKey []byte 68 | seed []byte 69 | } 70 | 71 | // Iteration will return the sender message key's iteration. 72 | func (k *SenderMessageKey) Iteration() uint32 { 73 | return k.iteration 74 | } 75 | 76 | // Iv will return the sender message key's initialization vector. 77 | func (k *SenderMessageKey) Iv() []byte { 78 | return k.iv 79 | } 80 | 81 | // CipherKey will return the key in bytes. 82 | func (k *SenderMessageKey) CipherKey() []byte { 83 | return k.cipherKey 84 | } 85 | 86 | // Seed will return the sender message key's seed. 87 | func (k *SenderMessageKey) Seed() []byte { 88 | return k.seed 89 | } 90 | -------------------------------------------------------------------------------- /groups/state/record/Doc.go: -------------------------------------------------------------------------------- 1 | // Package record provides the state and record of a group session. 2 | package record 3 | -------------------------------------------------------------------------------- /groups/state/record/SenderKeyRecord.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "errors" 5 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 6 | ) 7 | 8 | // SenderKeySerializer is an interface for serializing and deserializing 9 | // SenderKey objects into bytes. An implementation of this interface should be 10 | // used to encode/decode the object into JSON, Protobuffers, etc. 11 | type SenderKeySerializer interface { 12 | Serialize(preKey *SenderKeyStructure) []byte 13 | Deserialize(serialized []byte) (*SenderKeyStructure, error) 14 | } 15 | 16 | // NewSenderKeyFromBytes will return a prekey record from the given bytes using the given serializer. 17 | func NewSenderKeyFromBytes(serialized []byte, serializer SenderKeySerializer, 18 | stateSerializer SenderKeyStateSerializer) (*SenderKey, error) { 19 | 20 | // Use the given serializer to decode the senderkey record 21 | senderKeyStructure, err := serializer.Deserialize(serialized) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | return NewSenderKeyFromStruct(senderKeyStructure, serializer, stateSerializer) 27 | } 28 | 29 | // NewSenderKeyFromStruct returns a SenderKey record using the given serializable structure. 30 | func NewSenderKeyFromStruct(structure *SenderKeyStructure, serializer SenderKeySerializer, 31 | stateSerializer SenderKeyStateSerializer) (*SenderKey, error) { 32 | 33 | // Build our sender key states from structure. 34 | senderKeyStates := make([]*SenderKeyState, len(structure.SenderKeyStates)) 35 | for i := range structure.SenderKeyStates { 36 | var err error 37 | senderKeyStates[i], err = NewSenderKeyStateFromStructure(structure.SenderKeyStates[i], stateSerializer) 38 | if err != nil { 39 | return nil, err 40 | } 41 | } 42 | 43 | // Build and return our session. 44 | senderKey := &SenderKey{ 45 | senderKeyStates: senderKeyStates, 46 | serializer: serializer, 47 | } 48 | 49 | return senderKey, nil 50 | 51 | } 52 | 53 | // NewSenderKey record returns a new sender key record that can 54 | // be stored in a SenderKeyStore. 55 | func NewSenderKey(serializer SenderKeySerializer, 56 | stateSerializer SenderKeyStateSerializer) *SenderKey { 57 | 58 | return &SenderKey{ 59 | senderKeyStates: []*SenderKeyState{}, 60 | serializer: serializer, 61 | stateSerializer: stateSerializer, 62 | } 63 | } 64 | 65 | // SenderKeyStructure is a structure for serializing SenderKey records. 66 | type SenderKeyStructure struct { 67 | SenderKeyStates []*SenderKeyStateStructure 68 | } 69 | 70 | // SenderKey record is a structure for storing pre keys inside 71 | // a SenderKeyStore. 72 | type SenderKey struct { 73 | senderKeyStates []*SenderKeyState 74 | serializer SenderKeySerializer 75 | stateSerializer SenderKeyStateSerializer 76 | } 77 | 78 | // SenderKeyState will return the first sender key state in the record's 79 | // list of sender key states. 80 | func (k *SenderKey) SenderKeyState() (*SenderKeyState, error) { 81 | if len(k.senderKeyStates) > 0 { 82 | return k.senderKeyStates[0], nil 83 | } 84 | return nil, errors.New("No Sender Keys") 85 | } 86 | 87 | // GetSenderKeyStateByID will return the sender key state with the given 88 | // key id. 89 | func (k *SenderKey) GetSenderKeyStateByID(keyID uint32) (*SenderKeyState, error) { 90 | for i := 0; i < len(k.senderKeyStates); i++ { 91 | if k.senderKeyStates[i].KeyID() == keyID { 92 | return k.senderKeyStates[i], nil 93 | } 94 | } 95 | 96 | return nil, errors.New("No sender key for for ID") 97 | } 98 | 99 | // IsEmpty will return false if there is more than one state in this 100 | // senderkey record. 101 | func (k *SenderKey) IsEmpty() bool { 102 | return len(k.senderKeyStates) == 0 103 | } 104 | 105 | // AddSenderKeyState will add a new state to this senderkey record with the given 106 | // id, iteration, chainkey, and signature key. 107 | func (k *SenderKey) AddSenderKeyState(id uint32, iteration uint32, 108 | chainKey []byte, signatureKey ecc.ECPublicKeyable) { 109 | 110 | newState := NewSenderKeyStateFromPublicKey(id, iteration, chainKey, signatureKey, k.stateSerializer) 111 | k.senderKeyStates = append(k.senderKeyStates, newState) 112 | 113 | if len(k.senderKeyStates) > maxMessageKeys { 114 | k.senderKeyStates = k.senderKeyStates[1:] 115 | } 116 | } 117 | 118 | // SetSenderKeyState will replace the current senderkey states with the given 119 | // senderkey state. 120 | func (k *SenderKey) SetSenderKeyState(id uint32, iteration uint32, 121 | chainKey []byte, signatureKey *ecc.ECKeyPair) { 122 | 123 | newState := NewSenderKeyState(id, iteration, chainKey, signatureKey, k.stateSerializer) 124 | k.senderKeyStates = make([]*SenderKeyState, 0, maxMessageKeys/2) 125 | k.senderKeyStates = append(k.senderKeyStates, newState) 126 | } 127 | 128 | // Serialize will return the record as serialized bytes so it can be 129 | // persistently stored. 130 | func (k *SenderKey) Serialize() []byte { 131 | return k.serializer.Serialize(k.structure()) 132 | } 133 | 134 | // structure will return a simple serializable record structure. 135 | // This is used for serialization to persistently 136 | // store a session record. 137 | func (k *SenderKey) structure() *SenderKeyStructure { 138 | senderKeyStates := make([]*SenderKeyStateStructure, len(k.senderKeyStates)) 139 | for i := range k.senderKeyStates { 140 | senderKeyStates[i] = k.senderKeyStates[i].structure() 141 | } 142 | return &SenderKeyStructure{ 143 | SenderKeyStates: senderKeyStates, 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /groups/state/record/SenderKeyState.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | "github.com/RadicalApp/libsignal-protocol-go/groups/ratchet" 6 | "github.com/RadicalApp/libsignal-protocol-go/util/bytehelper" 7 | ) 8 | 9 | const maxMessageKeys = 2000 10 | 11 | // SenderKeyStateSerializer is an interface for serializing and deserializing 12 | // a Signal State into bytes. An implementation of this interface should be 13 | // used to encode/decode the object into JSON, Protobuffers, etc. 14 | type SenderKeyStateSerializer interface { 15 | Serialize(state *SenderKeyStateStructure) []byte 16 | Deserialize(serialized []byte) (*SenderKeyStateStructure, error) 17 | } 18 | 19 | // NewSenderKeyStateFromBytes will return a Signal State from the given 20 | // bytes using the given serializer. 21 | func NewSenderKeyStateFromBytes(serialized []byte, serializer SenderKeyStateSerializer) (*SenderKeyState, error) { 22 | // Use the given serializer to decode the signal message. 23 | stateStructure, err := serializer.Deserialize(serialized) 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | return NewSenderKeyStateFromStructure(stateStructure, serializer) 29 | } 30 | 31 | // NewSenderKeyState returns a new SenderKeyState. 32 | func NewSenderKeyState(keyID uint32, iteration uint32, chainKey []byte, 33 | signatureKey *ecc.ECKeyPair, serializer SenderKeyStateSerializer) *SenderKeyState { 34 | 35 | return &SenderKeyState{ 36 | keys: make([]*ratchet.SenderMessageKey, 0, maxMessageKeys/2), 37 | keyID: keyID, 38 | senderChainKey: ratchet.NewSenderChainKey(iteration, chainKey), 39 | signingKeyPair: signatureKey, 40 | serializer: serializer, 41 | } 42 | } 43 | 44 | // NewSenderKeyStateFromPublicKey returns a new SenderKeyState with the given publicKey. 45 | func NewSenderKeyStateFromPublicKey(keyID uint32, iteration uint32, chainKey []byte, 46 | signatureKey ecc.ECPublicKeyable, serializer SenderKeyStateSerializer) *SenderKeyState { 47 | 48 | keyPair := ecc.NewECKeyPair(signatureKey, nil) 49 | 50 | return &SenderKeyState{ 51 | keys: make([]*ratchet.SenderMessageKey, 0, maxMessageKeys/2), 52 | keyID: keyID, 53 | senderChainKey: ratchet.NewSenderChainKey(iteration, chainKey), 54 | signingKeyPair: keyPair, 55 | serializer: serializer, 56 | } 57 | } 58 | 59 | // NewSenderKeyStateFromStructure will return a new session state with the 60 | // given state structure. This structure is given back from an 61 | // implementation of the sender key state serializer. 62 | func NewSenderKeyStateFromStructure(structure *SenderKeyStateStructure, 63 | serializer SenderKeyStateSerializer) (*SenderKeyState, error) { 64 | 65 | // Convert our ecc keys from bytes into object form. 66 | signingKeyPublic, err := ecc.DecodePoint(structure.SigningKeyPublic, 0) 67 | if err != nil { 68 | return nil, err 69 | } 70 | signingKeyPrivate := ecc.NewDjbECPrivateKey(bytehelper.SliceToArray(structure.SigningKeyPrivate)) 71 | 72 | // Build our sender message keys from structure 73 | senderMessageKeys := make([]*ratchet.SenderMessageKey, len(structure.Keys)) 74 | for i := range structure.Keys { 75 | senderMessageKeys[i] = ratchet.NewSenderMessageKeyFromStruct(structure.Keys[i]) 76 | } 77 | 78 | // Build our state object. 79 | state := &SenderKeyState{ 80 | keys: senderMessageKeys, 81 | keyID: structure.KeyID, 82 | senderChainKey: ratchet.NewSenderChainKeyFromStruct(structure.SenderChainKey), 83 | signingKeyPair: ecc.NewECKeyPair(signingKeyPublic, signingKeyPrivate), 84 | serializer: serializer, 85 | } 86 | 87 | return state, nil 88 | } 89 | 90 | // SenderKeyStateStructure is a serializeable structure of SenderKeyState. 91 | type SenderKeyStateStructure struct { 92 | Keys []*ratchet.SenderMessageKeyStructure 93 | KeyID uint32 94 | SenderChainKey *ratchet.SenderChainKeyStructure 95 | SigningKeyPrivate []byte 96 | SigningKeyPublic []byte 97 | } 98 | 99 | // SenderKeyState is a structure for maintaining a senderkey session state. 100 | type SenderKeyState struct { 101 | keys []*ratchet.SenderMessageKey 102 | keyID uint32 103 | senderChainKey *ratchet.SenderChainKey 104 | signingKeyPair *ecc.ECKeyPair 105 | serializer SenderKeyStateSerializer 106 | } 107 | 108 | // SigningKey returns the signing key pair of the sender key state. 109 | func (k *SenderKeyState) SigningKey() *ecc.ECKeyPair { 110 | return k.signingKeyPair 111 | } 112 | 113 | // SenderChainKey returns the sender chain key of the state. 114 | func (k *SenderKeyState) SenderChainKey() *ratchet.SenderChainKey { 115 | return k.senderChainKey 116 | } 117 | 118 | // KeyID returns the state's key id. 119 | func (k *SenderKeyState) KeyID() uint32 { 120 | return k.keyID 121 | } 122 | 123 | // HasSenderMessageKey will return true if the state has a key with the 124 | // given iteration. 125 | func (k *SenderKeyState) HasSenderMessageKey(iteration uint32) bool { 126 | for i := 0; i < len(k.keys); i++ { 127 | if k.keys[i].Iteration() == iteration { 128 | return true 129 | } 130 | } 131 | return false 132 | } 133 | 134 | // AddSenderMessageKey will add the given sender message key to the state. 135 | func (k *SenderKeyState) AddSenderMessageKey(senderMsgKey *ratchet.SenderMessageKey) { 136 | k.keys = append(k.keys, senderMsgKey) 137 | 138 | if len(k.keys) > maxMessageKeys { 139 | k.keys = k.keys[1:] 140 | } 141 | } 142 | 143 | // SetSenderChainKey will set the state's sender chain key with the given key. 144 | func (k *SenderKeyState) SetSenderChainKey(senderChainKey *ratchet.SenderChainKey) { 145 | k.senderChainKey = senderChainKey 146 | } 147 | 148 | // RemoveSenderMessageKey will remove the key in this state with the given iteration number. 149 | func (k *SenderKeyState) RemoveSenderMessageKey(iteration uint32) *ratchet.SenderMessageKey { 150 | for i := 0; i < len(k.keys); i++ { 151 | if k.keys[i].Iteration() == iteration { 152 | removed := k.keys[i] 153 | k.keys = append(k.keys[0:i], k.keys[i+1:]...) 154 | return removed 155 | } 156 | } 157 | 158 | return nil 159 | } 160 | 161 | // Serialize will return the state as bytes using the given serializer. 162 | func (k *SenderKeyState) Serialize() []byte { 163 | return k.serializer.Serialize(k.structure()) 164 | } 165 | 166 | // structure will return a serializable structure of the 167 | // the given state so it can be persistently stored. 168 | func (k *SenderKeyState) structure() *SenderKeyStateStructure { 169 | // Convert our sender message keys into a serializeable structure 170 | keys := make([]*ratchet.SenderMessageKeyStructure, len(k.keys)) 171 | for i := range k.keys { 172 | keys[i] = ratchet.NewStructFromSenderMessageKey(k.keys[i]) 173 | } 174 | 175 | // Build and return our state structure. 176 | return &SenderKeyStateStructure{ 177 | Keys: keys, 178 | KeyID: k.keyID, 179 | SenderChainKey: ratchet.NewStructFromSenderChainKey(k.senderChainKey), 180 | SigningKeyPrivate: bytehelper.ArrayToSlice(k.signingKeyPair.PrivateKey().Serialize()), 181 | SigningKeyPublic: k.signingKeyPair.PublicKey().Serialize(), 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /groups/state/store/Doc.go: -------------------------------------------------------------------------------- 1 | // Package store provides the storage interfaces for storing group sender 2 | // key records. 3 | package store 4 | -------------------------------------------------------------------------------- /groups/state/store/SenderKeyStore.go: -------------------------------------------------------------------------------- 1 | package store 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/groups/state/record" 5 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 6 | ) 7 | 8 | type SenderKey interface { 9 | StoreSenderKey(senderKeyName *protocol.SenderKeyName, keyRecord *record.SenderKey) 10 | LoadSenderKey(senderKeyName *protocol.SenderKeyName) *record.SenderKey 11 | } 12 | -------------------------------------------------------------------------------- /kdf/HKDF.go: -------------------------------------------------------------------------------- 1 | // Package kdf provides a key derivation function to calculate key output 2 | // and negotiate shared secrets for curve X25519 keys. 3 | package kdf 4 | 5 | import ( 6 | "crypto/sha256" 7 | "golang.org/x/crypto/curve25519" 8 | "golang.org/x/crypto/hkdf" 9 | "io" 10 | ) 11 | 12 | // HKDF is a hashed key derivation function type that can be used to derive keys. 13 | type HKDF func(inputKeyMaterial, salt, info []byte, outputLength int) ([]byte, error) 14 | 15 | // DeriveSecrets derives the requested number of bytes using HKDF with the given 16 | // input, salt, and info. 17 | func DeriveSecrets(inputKeyMaterial, salt, info []byte, outputLength int) ([]byte, error) { 18 | kdf := hkdf.New(sha256.New, inputKeyMaterial, salt, info) 19 | 20 | secrets := make([]byte, outputLength) 21 | length, err := io.ReadFull(kdf, secrets) 22 | if err != nil { 23 | return nil, err 24 | } 25 | if length != outputLength { 26 | return nil, err 27 | } 28 | 29 | return secrets, nil 30 | } 31 | 32 | // CalculateSharedSecret uses DH Curve25519 to find a shared secret. The result of this function 33 | // should be used in `DeriveSecrets` to output the Root and Chain keys. 34 | func CalculateSharedSecret(theirKey, ourKey [32]byte) [32]byte { 35 | var sharedSecret [32]byte 36 | curve25519.ScalarMult(&sharedSecret, &ourKey, &theirKey) 37 | 38 | return sharedSecret 39 | } 40 | 41 | // KeyMaterial is a structure for representing a cipherkey, mac, and iv 42 | type KeyMaterial struct { 43 | CipherKey []byte 44 | MacKey []byte 45 | IV []byte 46 | } 47 | -------------------------------------------------------------------------------- /keys/chain/ChainKey.go: -------------------------------------------------------------------------------- 1 | // Package chain provides chain keys used in double ratchet sessions. 2 | package chain 3 | 4 | import ( 5 | "crypto/hmac" 6 | "crypto/sha256" 7 | "github.com/RadicalApp/libsignal-protocol-go/kdf" 8 | "github.com/RadicalApp/libsignal-protocol-go/keys/message" 9 | ) 10 | 11 | var messageKeySeed = []byte{0x01} 12 | var chainKeySeed = []byte{0x02} 13 | 14 | // NewKey returns a new chain key with the given kdf, key, and index 15 | func NewKey(kdf kdf.HKDF, key []byte, index uint32) *Key { 16 | chainKey := Key{ 17 | kdf: kdf, 18 | key: key, 19 | index: index, 20 | } 21 | 22 | return &chainKey 23 | } 24 | 25 | // NewKeyFromStruct will return a chain key built from the given structure. 26 | func NewKeyFromStruct(structure *KeyStructure, kdf kdf.HKDF) *Key { 27 | return NewKey( 28 | kdf, 29 | structure.Key, 30 | structure.Index, 31 | ) 32 | } 33 | 34 | // NewStructFromKey will return a chain key structure for serialization. 35 | func NewStructFromKey(key *Key) *KeyStructure { 36 | return &KeyStructure{ 37 | Key: key.key, 38 | Index: key.index, 39 | } 40 | } 41 | 42 | // KeyStructure is a serializeable structure for chain keys. 43 | type KeyStructure struct { 44 | Key []byte 45 | Index uint32 46 | } 47 | 48 | // Key is used for generating message keys. This key "ratchets" every time a 49 | // message key is generated. Every time the chain key ratchets forward, its index 50 | // increases by one. 51 | type Key struct { 52 | kdf kdf.HKDF 53 | key []byte 54 | index uint32 // Index's maximum size: 4,294,967,295 55 | } 56 | 57 | // Current returns the current ChainKey struct. 58 | func (c *Key) Current() *Key { 59 | return c 60 | } 61 | 62 | // Key returns the ChainKey's key material. 63 | func (c *Key) Key() []byte { 64 | return c.key 65 | } 66 | 67 | // SetKey will set the ChainKey's key material. 68 | func (c *Key) SetKey(key []byte) { 69 | c.key = key 70 | } 71 | 72 | // Index returns how many times the ChainKey has been "ratcheted" forward. 73 | func (c *Key) Index() uint32 { 74 | return c.index 75 | } 76 | 77 | // SetIndex sets how many times the ChainKey has been "ratcheted" forward. 78 | func (c *Key) SetIndex(index uint32) { 79 | c.index = index 80 | } 81 | 82 | // NextKey uses the key derivation function to generate a new ChainKey. 83 | func (c *Key) NextKey() *Key { 84 | nextKey := c.BaseMaterial(chainKeySeed) 85 | return NewKey(c.kdf, nextKey, c.index+1) 86 | } 87 | 88 | // MessageKeys returns message keys, which includes the cipherkey, mac, iv, and index. 89 | func (c *Key) MessageKeys() *message.Keys { 90 | inputKeyMaterial := c.BaseMaterial(messageKeySeed) 91 | keyMaterialBytes, _ := c.kdf(inputKeyMaterial, nil, []byte(message.KdfSalt), message.DerivedSecretsSize) 92 | keyMaterial := newKeyMaterial(keyMaterialBytes) 93 | 94 | // Use the key material returned from the key derivation function for our cipherkey, mac, and iv. 95 | messageKeys := message.NewKeys( 96 | keyMaterial.CipherKey, // Use the first 32 bytes of the key material for the CipherKey 97 | keyMaterial.MacKey, // Use bytes 32-64 of the key material for the MacKey 98 | keyMaterial.IV, // Use the last 16 bytes for the IV. 99 | c.Index(), // Attach the chain key's index to the message keys. 100 | ) 101 | 102 | return messageKeys 103 | } 104 | 105 | // BaseMaterial uses hmac to derive the base material used in the key derivation function for a new key. 106 | func (c *Key) BaseMaterial(seed []byte) []byte { 107 | mac := hmac.New(sha256.New, c.key[:]) 108 | mac.Write(seed) 109 | 110 | return mac.Sum(nil) 111 | } 112 | 113 | // NewKeyMaterial takes an 80-byte slice derived from a key derivation function and splits 114 | // it into the cipherkey, mac, and iv. 115 | func newKeyMaterial(keyMaterialBytes []byte) *kdf.KeyMaterial { 116 | cipherKey := keyMaterialBytes[:32] // Use the first 32 bytes of the key material for the CipherKey 117 | macKey := keyMaterialBytes[32:64] // Use bytes 32-64 of the key material for the MacKey 118 | iv := keyMaterialBytes[64:80] // Use the last 16 bytes for the IV. 119 | 120 | keyMaterial := kdf.KeyMaterial{ 121 | CipherKey: cipherKey, 122 | MacKey: macKey, 123 | IV: iv, 124 | } 125 | 126 | return &keyMaterial 127 | } 128 | -------------------------------------------------------------------------------- /keys/identity/IdentityKey.go: -------------------------------------------------------------------------------- 1 | // Package identity provides identity keys used for verifying the identity 2 | // of a signal user. 3 | package identity 4 | 5 | import ( 6 | "encoding/hex" 7 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 8 | ) 9 | 10 | // NewKey generates a new IdentityKey from an ECPublicKey 11 | func NewKey(publicKey ecc.ECPublicKeyable) *Key { 12 | identityKey := Key{ 13 | publicKey: publicKey, 14 | } 15 | 16 | return &identityKey 17 | } 18 | 19 | // NewKeyFromBytes generates a new IdentityKey from public key bytes 20 | func NewKeyFromBytes(publicKey [32]byte, offset int) Key { 21 | identityKey := Key{ 22 | publicKey: ecc.NewDjbECPublicKey(publicKey), 23 | } 24 | 25 | return identityKey 26 | } 27 | 28 | // Key is a structure for representing an identity key. This same structure can 29 | // be used for verifying recipient's identity key or storing our own identity key. 30 | type Key struct { 31 | publicKey ecc.ECPublicKeyable 32 | } 33 | 34 | // Fingerprint gets the string fingerprint representation of the public key. 35 | func (k *Key) Fingerprint() string { 36 | return hex.EncodeToString(k.publicKey.Serialize()) 37 | } 38 | 39 | // PublicKey returns the EC Public key of the identity key 40 | func (k *Key) PublicKey() ecc.ECPublicKeyable { 41 | return k.publicKey 42 | } 43 | 44 | // Serialize returns the serialized version of the key 45 | func (k *Key) Serialize() []byte { 46 | return k.publicKey.Serialize() 47 | } 48 | -------------------------------------------------------------------------------- /keys/identity/IdentityKeyPair.go: -------------------------------------------------------------------------------- 1 | package identity 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | ) 6 | 7 | // NewKeyPair returns a new identity key with the given public and private keys. 8 | func NewKeyPair(publicKey *Key, privateKey ecc.ECPrivateKeyable) *KeyPair { 9 | keyPair := KeyPair{ 10 | publicKey: publicKey, 11 | privateKey: privateKey, 12 | } 13 | 14 | return &keyPair 15 | } 16 | 17 | // NewKeyPairFromBytes returns a new identity key from the given serialized bytes. 18 | //func NewKeyPairFromBytes(serialized []byte) KeyPair { 19 | //} 20 | 21 | // KeyPair is a holder for public and private identity key pair. 22 | type KeyPair struct { 23 | publicKey *Key 24 | privateKey ecc.ECPrivateKeyable 25 | } 26 | 27 | // PublicKey returns the identity key's public key. 28 | func (k *KeyPair) PublicKey() *Key { 29 | return k.publicKey 30 | } 31 | 32 | // PrivateKey returns the identity key's private key. 33 | func (k *KeyPair) PrivateKey() ecc.ECPrivateKeyable { 34 | return k.privateKey 35 | } 36 | 37 | // Serialize returns a byte array that represents the keypair. 38 | //func (k *KeyPair) Serialize() []byte { 39 | //} 40 | -------------------------------------------------------------------------------- /keys/message/MessageKey.go: -------------------------------------------------------------------------------- 1 | // Package message provides a structure for message keys, which are symmetric 2 | // keys used for the encryption/decryption of Signal messages. 3 | package message 4 | 5 | // DerivedSecretsSize is the size of the derived secrets for message keys. 6 | const DerivedSecretsSize = 80 7 | 8 | // CipherKeyLength is the length of the actual cipher key used for messages. 9 | const CipherKeyLength = 32 10 | 11 | // MacKeyLength is the length of the message authentication code in bytes. 12 | const MacKeyLength = 32 13 | 14 | // IVLength is the length of the initialization vector in bytes. 15 | const IVLength = 16 16 | 17 | // KdfSalt is used as the Salt for message keys to derive secrets using a Key Derivation Function 18 | const KdfSalt string = "WhisperMessageKeys" 19 | 20 | // NewKeys returns a new message keys structure with the given cipherKey, mac, iv, and index. 21 | func NewKeys(cipherKey, macKey, iv []byte, index uint32) *Keys { 22 | messageKeys := Keys{ 23 | cipherKey: cipherKey, 24 | macKey: macKey, 25 | iv: iv, 26 | index: index, 27 | } 28 | 29 | return &messageKeys 30 | } 31 | 32 | // NewKeysFromStruct will return a new message keys object from the 33 | // given serializeable structure. 34 | func NewKeysFromStruct(structure *KeysStructure) *Keys { 35 | return NewKeys( 36 | structure.CipherKey, 37 | structure.MacKey, 38 | structure.IV, 39 | structure.Index, 40 | ) 41 | } 42 | 43 | // NewStructFromKeys returns a serializeable structure of message keys. 44 | func NewStructFromKeys(keys *Keys) *KeysStructure { 45 | return &KeysStructure{ 46 | CipherKey: keys.cipherKey, 47 | MacKey: keys.macKey, 48 | IV: keys.iv, 49 | Index: keys.index, 50 | } 51 | } 52 | 53 | // KeysStructure is a serializeable structure of message keys. 54 | type KeysStructure struct { 55 | CipherKey []byte 56 | MacKey []byte 57 | IV []byte 58 | Index uint32 59 | } 60 | 61 | // Keys is a structure to hold all the keys for a single MessageKey, including the 62 | // cipherKey, mac, iv, and index of the chain key. MessageKeys are used to 63 | // encrypt individual messages. 64 | type Keys struct { 65 | cipherKey []byte 66 | macKey []byte 67 | iv []byte 68 | index uint32 69 | } 70 | 71 | // CipherKey is the key used to produce ciphertext. 72 | func (k *Keys) CipherKey() []byte { 73 | return k.cipherKey 74 | } 75 | 76 | // MacKey returns the message's message authentication code. 77 | func (k *Keys) MacKey() []byte { 78 | return k.macKey 79 | } 80 | 81 | // Iv returns the message keys' initialization vector. The IV is a fixed-size input 82 | // to a cryptographic primitive. 83 | func (k *Keys) Iv() []byte { 84 | return k.iv 85 | } 86 | 87 | // Index returns the number of times the chain key has been put through a key derivation 88 | // function to generate this message key. 89 | func (k *Keys) Index() uint32 { 90 | return k.index 91 | } 92 | -------------------------------------------------------------------------------- /keys/prekey/PreKeyBundle.go: -------------------------------------------------------------------------------- 1 | // Package prekey provides prekey bundle structures for calculating 2 | // a new Signal session with a user asyncronously. 3 | package prekey 4 | 5 | import ( 6 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 7 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 8 | "github.com/RadicalApp/libsignal-protocol-go/util/optional" 9 | ) 10 | 11 | // NewBundle returns a Bundle structure that contains a remote PreKey 12 | // and collection of associated items. 13 | func NewBundle(registrationID, deviceID uint32, preKeyID *optional.Uint32, signedPreKeyID uint32, 14 | preKeyPublic, signedPreKeyPublic ecc.ECPublicKeyable, signedPreKeySig [64]byte, 15 | identityKey *identity.Key) *Bundle { 16 | 17 | bundle := Bundle{ 18 | registrationID: registrationID, 19 | deviceID: deviceID, 20 | preKeyID: preKeyID, 21 | preKeyPublic: preKeyPublic, 22 | signedPreKeyID: signedPreKeyID, 23 | signedPreKeyPublic: signedPreKeyPublic, 24 | signedPreKeySignature: signedPreKeySig, 25 | identityKey: identityKey, 26 | } 27 | 28 | return &bundle 29 | } 30 | 31 | // Bundle is a structure that contains a remote PreKey and collection 32 | // of associated items. 33 | type Bundle struct { 34 | registrationID uint32 35 | deviceID uint32 36 | preKeyID *optional.Uint32 37 | preKeyPublic ecc.ECPublicKeyable 38 | signedPreKeyID uint32 39 | signedPreKeyPublic ecc.ECPublicKeyable 40 | signedPreKeySignature [64]byte 41 | identityKey *identity.Key 42 | } 43 | 44 | // DeviceID returns the device ID this PreKey belongs to. 45 | func (b *Bundle) DeviceID() uint32 { 46 | return b.deviceID 47 | } 48 | 49 | // PreKeyID returns the unique key ID for this PreKey. 50 | func (b *Bundle) PreKeyID() *optional.Uint32 { 51 | return b.preKeyID 52 | } 53 | 54 | // PreKey returns the public key for this PreKey. 55 | func (b *Bundle) PreKey() ecc.ECPublicKeyable { 56 | return b.preKeyPublic 57 | } 58 | 59 | // SignedPreKeyID returns the unique key ID for this 60 | // signed PreKey. 61 | func (b *Bundle) SignedPreKeyID() uint32 { 62 | return b.signedPreKeyID 63 | } 64 | 65 | // SignedPreKey returns the signed PreKey for this 66 | // PreKeyBundle. 67 | func (b *Bundle) SignedPreKey() ecc.ECPublicKeyable { 68 | return b.signedPreKeyPublic 69 | } 70 | 71 | // SignedPreKeySignature returns the signature over the 72 | // signed PreKey. 73 | func (b *Bundle) SignedPreKeySignature() [64]byte { 74 | return b.signedPreKeySignature 75 | } 76 | 77 | // IdentityKey returns the Identity Key of this PreKey's owner. 78 | func (b *Bundle) IdentityKey() *identity.Key { 79 | return b.identityKey 80 | } 81 | 82 | // RegistrationID returns the registration ID associated with 83 | // this PreKey. 84 | func (b *Bundle) RegistrationID() uint32 { 85 | return b.registrationID 86 | } 87 | -------------------------------------------------------------------------------- /keys/root/RootKey.go: -------------------------------------------------------------------------------- 1 | // Package root provides root keys which are used to derive new chain and 2 | // root keys in a ratcheting session. 3 | package root 4 | 5 | import ( 6 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 7 | "github.com/RadicalApp/libsignal-protocol-go/kdf" 8 | "github.com/RadicalApp/libsignal-protocol-go/keys/chain" 9 | "github.com/RadicalApp/libsignal-protocol-go/keys/session" 10 | ) 11 | 12 | // DerivedSecretsSize is the size of the derived secrets for root keys. 13 | const DerivedSecretsSize = 64 14 | 15 | // KdfInfo is used as the info for message keys to derive secrets using a Key Derivation Function 16 | const KdfInfo string = "WhisperRatchet" 17 | 18 | // NewKey returns a new RootKey given the key derivation function and bytes. 19 | func NewKey(kdf kdf.HKDF, key []byte) *Key { 20 | rootKey := Key{ 21 | kdf: kdf, 22 | key: key, 23 | } 24 | 25 | return &rootKey 26 | } 27 | 28 | // Key is a structure for RootKeys, which are used to derive a new set of chain and root 29 | // keys for every round trip of messages. 30 | type Key struct { 31 | kdf kdf.HKDF 32 | key []byte 33 | } 34 | 35 | // Bytes returns the RootKey in bytes. 36 | func (k *Key) Bytes() []byte { 37 | return k.key 38 | } 39 | 40 | // CreateChain creates a new RootKey and ChainKey from the recipient's ratchet key and our private key. 41 | func (k *Key) CreateChain(theirRatchetKey ecc.ECPublicKeyable, ourRatchetKey *ecc.ECKeyPair) (*session.KeyPair, error) { 42 | var keyMaterial []byte 43 | theirPublicKey := theirRatchetKey.PublicKey() 44 | ourPrivateKey := ourRatchetKey.PrivateKey().Serialize() 45 | 46 | // Use our key derivation function to calculate a shared secret. 47 | sharedSecret := kdf.CalculateSharedSecret(theirPublicKey, ourPrivateKey) 48 | copy(keyMaterial[:], sharedSecret[:]) 49 | derivedSecretBytes, err := kdf.DeriveSecrets(keyMaterial, k.key, []byte(KdfInfo), DerivedSecretsSize) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | // Split the derived secret bytes in half, using one half for the root key and the second for the chain key. 55 | derivedSecrets := session.NewDerivedSecrets(derivedSecretBytes) 56 | 57 | // Create new root and chain key structures from the derived secrets. 58 | rootKey := NewKey(k.kdf, derivedSecrets.RootKey()) 59 | chainKey := chain.NewKey(k.kdf, derivedSecrets.ChainKey(), 0) 60 | 61 | // Create a session keypair with the generated root and chain keys. 62 | keyPair := session.NewKeyPair( 63 | rootKey, 64 | chainKey, 65 | ) 66 | 67 | return keyPair, nil 68 | } 69 | -------------------------------------------------------------------------------- /keys/session/DerivedSecrets.go: -------------------------------------------------------------------------------- 1 | package session 2 | 3 | // NewDerivedSecrets returns a new RootKey/ChainKey pair from 64 bytes of key material 4 | // generated by the key derivation function. 5 | func NewDerivedSecrets(keyMaterial []byte) *DerivedSecrets { 6 | secrets := DerivedSecrets{ 7 | keyMaterial[:32], 8 | keyMaterial[32:], 9 | } 10 | 11 | return &secrets 12 | } 13 | 14 | // DerivedSecrets is a structure for holding the derived secrets for the 15 | // Root and Chain keys for a session. 16 | type DerivedSecrets struct { 17 | rootKey []byte 18 | chainKey []byte 19 | } 20 | 21 | // RootKey returns the RootKey bytes. 22 | func (d *DerivedSecrets) RootKey() []byte { 23 | return d.rootKey 24 | } 25 | 26 | // ChainKey returns the ChainKey bytes. 27 | func (d *DerivedSecrets) ChainKey() []byte { 28 | return d.chainKey 29 | } 30 | -------------------------------------------------------------------------------- /keys/session/Pair.go: -------------------------------------------------------------------------------- 1 | // Package session provides a simple structure for session keys, which is 2 | // a pair of root and chain keys for a session. 3 | package session 4 | 5 | import ( 6 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 7 | "github.com/RadicalApp/libsignal-protocol-go/keys/chain" 8 | "github.com/RadicalApp/libsignal-protocol-go/keys/message" 9 | ) 10 | 11 | // RootKeyable is an interface for all root key implementations that are part of 12 | // a session keypair. 13 | type RootKeyable interface { 14 | Bytes() []byte 15 | CreateChain(theirRatchetKey ecc.ECPublicKeyable, ourRatchetKey *ecc.ECKeyPair) (*KeyPair, error) 16 | } 17 | 18 | // ChainKeyable is an interface for all chain key implementations that are part of 19 | // a session keypair. 20 | type ChainKeyable interface { 21 | Key() []byte 22 | Index() uint32 23 | NextKey() *chain.Key 24 | MessageKeys() *message.Keys 25 | Current() *chain.Key 26 | } 27 | 28 | // NewKeyPair returns a new session key pair that holds a root and chain key. 29 | func NewKeyPair(rootKey RootKeyable, chainKey ChainKeyable) *KeyPair { 30 | keyPair := KeyPair{ 31 | RootKey: rootKey, 32 | ChainKey: chainKey, 33 | } 34 | 35 | return &keyPair 36 | } 37 | 38 | // KeyPair is a session key pair that holds a single root and chain key pair. These 39 | // keys are ratcheted after every message sent and every message round trip. 40 | type KeyPair struct { 41 | RootKey RootKeyable 42 | ChainKey ChainKeyable 43 | } 44 | -------------------------------------------------------------------------------- /logger/DefaultLogger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | ) 8 | 9 | // DefaultLogger is used if no logger has been set up. 10 | type defaultLogger struct { 11 | namespaces []string 12 | } 13 | 14 | // log simply logs the given message to stdout if the message 15 | // caller is allowed to log. 16 | func (d *defaultLogger) log(level, caller, msg string) { 17 | if !d.shouldLog(caller) { 18 | return 19 | } 20 | t := time.Now() 21 | fmt.Println( 22 | "["+level+"]", 23 | t.Format(time.RFC3339), 24 | caller, 25 | "▶ ", 26 | msg, 27 | ) 28 | } 29 | 30 | // shouldLog determines whether or not the given caller should 31 | // be allowed to log messages. 32 | func (d *defaultLogger) shouldLog(caller string) bool { 33 | shouldLog := false 34 | d.ensureNamespaces() 35 | for _, namespace := range d.namespaces { 36 | if namespace == "all" { 37 | shouldLog = true 38 | } 39 | if strings.Contains(caller, namespace) { 40 | shouldLog = true 41 | } 42 | } 43 | 44 | return shouldLog 45 | } 46 | 47 | // ensureNamespaces checks to see if our list of loggable namespaces 48 | // has been initialized or not. If not, it defaults to log all. 49 | func (d *defaultLogger) ensureNamespaces() { 50 | if d.namespaces == nil { 51 | d.namespaces = []string{"all"} 52 | } 53 | } 54 | 55 | // Debug is used to log debug messages. 56 | func (d *defaultLogger) Debug(caller, msg string) { 57 | d.log("DEBUG", caller, msg) 58 | } 59 | 60 | // Info is used to log info messages. 61 | func (d *defaultLogger) Info(caller, msg string) { 62 | d.log("INFO", caller, msg) 63 | } 64 | 65 | // Warning is used to log warning messages. 66 | func (d *defaultLogger) Warning(caller, msg string) { 67 | d.log("WARNING", caller, msg) 68 | } 69 | 70 | // Error is used to log error messages. 71 | func (d *defaultLogger) Error(caller, msg string) { 72 | d.log("ERROR", caller, msg) 73 | } 74 | 75 | // Configure takes a configuration string separated by commas 76 | // that contains all the callers that should be logged. This 77 | // allows granular logging of different go files. 78 | // 79 | // Example: 80 | // logger.Configure("RootKey.go,Curve.go") 81 | // logger.Configure("all") 82 | // 83 | func (d *defaultLogger) Configure(settings string) { 84 | d.namespaces = strings.Split(settings, ",") 85 | } 86 | -------------------------------------------------------------------------------- /logger/Logger.go: -------------------------------------------------------------------------------- 1 | // Package logger provides optional debug logging of the Signal library. 2 | package logger 3 | 4 | import ( 5 | "fmt" 6 | "runtime" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // Logger is a shared loggable interface that this library will use for all log messages. 12 | var Logger Loggable 13 | 14 | // Loggable is an interface for logging. 15 | type Loggable interface { 16 | Debug(caller, message string) 17 | Info(caller, message string) 18 | Warning(caller, message string) 19 | Error(caller, message string) 20 | Configure(settings string) 21 | } 22 | 23 | // Setup will configure the shared logger to use the provided logger. 24 | func Setup(logger *Loggable) { 25 | Logger = *logger 26 | } 27 | 28 | // ToString converts an arbitrary number of objects to a string for use in a logger. 29 | func toString(a ...interface{}) string { 30 | return fmt.Sprint(a...) 31 | } 32 | 33 | // EnsureLogger will use the default logger if one was not set up. 34 | func ensureLogger() { 35 | if Logger == nil { 36 | fmt.Println("Error: No logger was configured. Use `logger.Setup` to configure a logger.") 37 | Logger = &defaultLogger{} 38 | } 39 | } 40 | 41 | // GetCaller gets the go file name and line number that the logger was called from. 42 | func getCaller() string { 43 | var file string 44 | _, path, line, _ := runtime.Caller(2) 45 | paths := strings.Split(path, "/") 46 | if len(paths) > 0 { 47 | file = paths[len(paths)-1] 48 | } else { 49 | file = "" 50 | } 51 | 52 | return file + ":" + strconv.Itoa(line) 53 | } 54 | 55 | /* 56 | * Go methods used by the library for logging. 57 | */ 58 | 59 | // Debug prints debug level logs. 60 | func Debug(msg ...interface{}) { 61 | ensureLogger() 62 | Logger.Debug(getCaller(), toString(msg...)) 63 | } 64 | 65 | // Info prints info level logs. 66 | func Info(msg ...interface{}) { 67 | ensureLogger() 68 | Logger.Info(getCaller(), toString(msg...)) 69 | } 70 | 71 | // Warning prints warning level logs. 72 | func Warning(msg ...interface{}) { 73 | ensureLogger() 74 | Logger.Warning(getCaller(), toString(msg...)) 75 | } 76 | 77 | // Error prints error level logs. 78 | func Error(msg ...interface{}) { 79 | ensureLogger() 80 | Logger.Error(getCaller(), toString(msg...)) 81 | } 82 | 83 | // Configure allows arbitrary logger configuration settings. The 84 | // default logger uses this method to configure what Go files 85 | // are allowed to log. 86 | func Configure(settings string) { 87 | ensureLogger() 88 | Logger.Configure(settings) 89 | } 90 | -------------------------------------------------------------------------------- /protocol/CiphertextMessage.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | type CiphertextMessage interface { 4 | Serialize() []byte 5 | Type() uint32 6 | } 7 | 8 | const UnsupportedVersion = 1 9 | const CurrentVersion = 3 10 | 11 | const WHISPER_TYPE = 2 12 | const PREKEY_TYPE = 3 13 | const SENDERKEY_TYPE = 4 14 | const SENDERKEY_DISTRIBUTION_TYPE = 5 15 | -------------------------------------------------------------------------------- /protocol/Doc.go: -------------------------------------------------------------------------------- 1 | // Package protocol provides address, group, and message structures that 2 | // the Signal protocol uses for sending encrypted messages. 3 | package protocol 4 | -------------------------------------------------------------------------------- /protocol/PreKeySignalMessage.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "errors" 5 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 6 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 7 | "github.com/RadicalApp/libsignal-protocol-go/util/optional" 8 | "strconv" 9 | ) 10 | 11 | // PreKeySignalMessageSerializer is an interface for serializing and deserializing 12 | // PreKeySignalMessages into bytes. An implementation of this interface should be 13 | // used to encode/decode the object into JSON, Protobuffers, etc. 14 | type PreKeySignalMessageSerializer interface { 15 | Serialize(signalMessage *PreKeySignalMessageStructure) []byte 16 | Deserialize(serialized []byte) (*PreKeySignalMessageStructure, error) 17 | } 18 | 19 | // NewPreKeySignalMessageFromBytes will return a Signal Ciphertext message from the given 20 | // bytes using the given serializer. 21 | func NewPreKeySignalMessageFromBytes(serialized []byte, serializer PreKeySignalMessageSerializer, 22 | msgSerializer SignalMessageSerializer) (*PreKeySignalMessage, error) { 23 | // Use the given serializer to decode the signal message. 24 | signalMessageStructure, err := serializer.Deserialize(serialized) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | return NewPreKeySignalMessageFromStruct(signalMessageStructure, serializer, msgSerializer) 30 | } 31 | 32 | // NewPreKeySignalMessageFromStruct will return a new PreKeySignalMessage from the given 33 | // PreKeySignalMessageStructure. 34 | func NewPreKeySignalMessageFromStruct(structure *PreKeySignalMessageStructure, 35 | serializer PreKeySignalMessageSerializer, msgSerializer SignalMessageSerializer) (*PreKeySignalMessage, error) { 36 | 37 | // Throw an error if the given message structure is an unsupported version. 38 | if structure.Version <= UnsupportedVersion { 39 | err := "Legacy message: " + strconv.Itoa(structure.Version) 40 | return nil, errors.New(err) 41 | } 42 | 43 | // Throw an error if the given message structure is a future version. 44 | if structure.Version > CurrentVersion { 45 | err := "Unknown version: " + strconv.Itoa(structure.Version) 46 | return nil, errors.New(err) 47 | } 48 | 49 | // Throw an error if the structure is missing critical fields. 50 | if structure.BaseKey == nil || structure.IdentityKey == nil || structure.Message == nil { 51 | err := "Incomplete message." 52 | return nil, errors.New(err) 53 | } 54 | 55 | // Create the signal message object from the structure. 56 | preKeyWhisperMessage := &PreKeySignalMessage{structure: *structure, serializer: serializer} 57 | 58 | // Generate the base ECC key from bytes. 59 | var err error 60 | preKeyWhisperMessage.baseKey, err = ecc.DecodePoint(structure.BaseKey, 0) 61 | if err != nil { 62 | return nil, err 63 | } 64 | 65 | // Generate the identity key from bytes 66 | var identityKey ecc.ECPublicKeyable 67 | identityKey, err = ecc.DecodePoint(structure.IdentityKey, 0) 68 | if err != nil { 69 | return nil, err 70 | } 71 | preKeyWhisperMessage.identityKey = identity.NewKey(identityKey) 72 | 73 | // Generate the SignalMessage object from bytes. 74 | preKeyWhisperMessage.message, err = NewSignalMessageFromBytes(structure.Message, msgSerializer) 75 | if err != nil { 76 | return nil, err 77 | } 78 | 79 | return preKeyWhisperMessage, nil 80 | } 81 | 82 | // NewPreKeySignalMessage will return a new PreKeySignalMessage object. 83 | func NewPreKeySignalMessage(version int, registrationID uint32, preKeyID *optional.Uint32, signedPreKeyID uint32, 84 | baseKey ecc.ECPublicKeyable, identityKey *identity.Key, message *SignalMessage, serializer PreKeySignalMessageSerializer, 85 | msgSerializer SignalMessageSerializer) (*PreKeySignalMessage, error) { 86 | 87 | structure := &PreKeySignalMessageStructure{ 88 | Version: version, 89 | RegistrationID: registrationID, 90 | PreKeyID: preKeyID, 91 | SignedPreKeyID: signedPreKeyID, 92 | BaseKey: baseKey.Serialize(), 93 | IdentityKey: identityKey.PublicKey().Serialize(), 94 | Message: message.Serialize(), 95 | } 96 | return NewPreKeySignalMessageFromStruct(structure, serializer, msgSerializer) 97 | } 98 | 99 | // PreKeySignalMessageStructure is a serializable structure for 100 | // PreKeySignalMessages. 101 | type PreKeySignalMessageStructure struct { 102 | RegistrationID uint32 103 | PreKeyID *optional.Uint32 104 | SignedPreKeyID uint32 105 | BaseKey []byte 106 | IdentityKey []byte 107 | Message []byte 108 | Version int 109 | } 110 | 111 | // PreKeySignalMessage is an encrypted Signal message that is designed 112 | // to be used when building a session with someone for the first time. 113 | type PreKeySignalMessage struct { 114 | structure PreKeySignalMessageStructure 115 | baseKey ecc.ECPublicKeyable 116 | identityKey *identity.Key 117 | message *SignalMessage 118 | serializer PreKeySignalMessageSerializer 119 | } 120 | 121 | func (p *PreKeySignalMessage) MessageVersion() int { 122 | return p.structure.Version 123 | } 124 | 125 | func (p *PreKeySignalMessage) IdentityKey() *identity.Key { 126 | return p.identityKey 127 | } 128 | 129 | func (p *PreKeySignalMessage) RegistrationID() uint32 { 130 | return p.structure.RegistrationID 131 | } 132 | 133 | func (p *PreKeySignalMessage) PreKeyID() *optional.Uint32 { 134 | return p.structure.PreKeyID 135 | } 136 | 137 | func (p *PreKeySignalMessage) SignedPreKeyID() uint32 { 138 | return p.structure.SignedPreKeyID 139 | } 140 | 141 | func (p *PreKeySignalMessage) BaseKey() ecc.ECPublicKeyable { 142 | return p.baseKey 143 | } 144 | 145 | func (p *PreKeySignalMessage) WhisperMessage() *SignalMessage { 146 | return p.message 147 | } 148 | 149 | func (p *PreKeySignalMessage) Serialize() []byte { 150 | return p.serializer.Serialize(&p.structure) 151 | } 152 | 153 | func (p *PreKeySignalMessage) Type() uint32 { 154 | return PREKEY_TYPE 155 | } 156 | -------------------------------------------------------------------------------- /protocol/SenderKeyDistributionMessage.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "errors" 5 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 6 | "strconv" 7 | ) 8 | 9 | // SenderKeyDistributionMessageSerializer is an interface for serializing and deserializing 10 | // SenderKeyDistributionMessages into bytes. An implementation of this interface should be 11 | // used to encode/decode the object into JSON, Protobuffers, etc. 12 | type SenderKeyDistributionMessageSerializer interface { 13 | Serialize(signalMessage *SenderKeyDistributionMessageStructure) []byte 14 | Deserialize(serialized []byte) (*SenderKeyDistributionMessageStructure, error) 15 | } 16 | 17 | // NewSenderKeyDistributionMessageFromBytes will return a Signal Ciphertext message from the given 18 | // bytes using the given serializer. 19 | func NewSenderKeyDistributionMessageFromBytes(serialized []byte, 20 | serializer SenderKeyDistributionMessageSerializer) (*SenderKeyDistributionMessage, error) { 21 | 22 | // Use the given serializer to decode the signal message. 23 | signalMessageStructure, err := serializer.Deserialize(serialized) 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | return NewSenderKeyDistributionMessageFromStruct(signalMessageStructure, serializer) 29 | } 30 | 31 | // NewSenderKeyDistributionMessageFromStruct returns a Signal Ciphertext message from the 32 | // given serializable structure. 33 | func NewSenderKeyDistributionMessageFromStruct(structure *SenderKeyDistributionMessageStructure, 34 | serializer SenderKeyDistributionMessageSerializer) (*SenderKeyDistributionMessage, error) { 35 | 36 | // Throw an error if the given message structure is an unsupported version. 37 | if structure.Version <= UnsupportedVersion { 38 | err := "Legacy message: " + strconv.Itoa(int(structure.Version)) 39 | return nil, errors.New(err) 40 | } 41 | 42 | // Throw an error if the given message structure is a future version. 43 | if structure.Version > CurrentVersion { 44 | err := "Unknown version: " + strconv.Itoa(int(structure.Version)) 45 | return nil, errors.New(err) 46 | } 47 | 48 | // Throw an error if the structure is missing critical fields. 49 | if structure.SigningKey == nil || structure.ChainKey == nil { 50 | err := "Incomplete message." 51 | return nil, errors.New(err) 52 | } 53 | 54 | // Get the signing key object from bytes. 55 | signingKey, err := ecc.DecodePoint(structure.SigningKey, 0) 56 | if err != nil { 57 | return nil, err 58 | } 59 | 60 | // Create the signal message object from the structure. 61 | message := &SenderKeyDistributionMessage{ 62 | id: structure.ID, 63 | iteration: structure.Iteration, 64 | chainKey: structure.ChainKey, 65 | version: structure.Version, 66 | signatureKey: signingKey, 67 | serializer: serializer, 68 | } 69 | 70 | // Generate the ECC key from bytes. 71 | message.signatureKey, err = ecc.DecodePoint(structure.SigningKey, 0) 72 | if err != nil { 73 | return nil, err 74 | } 75 | 76 | return message, nil 77 | } 78 | 79 | // NewSenderKeyDistributionMessage returns a Signal Ciphertext message. 80 | func NewSenderKeyDistributionMessage(id uint32, iteration uint32, 81 | chainKey []byte, signatureKey ecc.ECPublicKeyable, 82 | serializer SenderKeyDistributionMessageSerializer) *SenderKeyDistributionMessage { 83 | 84 | return &SenderKeyDistributionMessage{ 85 | id: id, 86 | iteration: iteration, 87 | chainKey: chainKey, 88 | signatureKey: signatureKey, 89 | serializer: serializer, 90 | } 91 | } 92 | 93 | // SenderKeyDistributionMessageStructure is a serializeable structure for senderkey 94 | // distribution messages. 95 | type SenderKeyDistributionMessageStructure struct { 96 | ID uint32 97 | Iteration uint32 98 | ChainKey []byte 99 | SigningKey []byte 100 | Version uint32 101 | } 102 | 103 | // SenderKeyDistributionMessage is a structure for senderkey distribution messages. 104 | type SenderKeyDistributionMessage struct { 105 | id uint32 106 | iteration uint32 107 | chainKey []byte 108 | version uint32 109 | signatureKey ecc.ECPublicKeyable 110 | serializer SenderKeyDistributionMessageSerializer 111 | } 112 | 113 | // ID will return the message's id. 114 | func (p *SenderKeyDistributionMessage) ID() uint32 { 115 | return p.id 116 | } 117 | 118 | // Iteration will return the message's iteration. 119 | func (p *SenderKeyDistributionMessage) Iteration() uint32 { 120 | return p.iteration 121 | } 122 | 123 | // ChainKey will return the message's chain key in bytes. 124 | func (p *SenderKeyDistributionMessage) ChainKey() []byte { 125 | return p.chainKey 126 | } 127 | 128 | // SignatureKey will return the message's signature public key 129 | func (p *SenderKeyDistributionMessage) SignatureKey() ecc.ECPublicKeyable { 130 | return p.signatureKey 131 | } 132 | 133 | // Serialize will use the given serializer and return the message as 134 | // bytes. 135 | func (p *SenderKeyDistributionMessage) Serialize() []byte { 136 | structure := &SenderKeyDistributionMessageStructure{ 137 | ID: p.id, 138 | Iteration: p.iteration, 139 | ChainKey: p.chainKey, 140 | SigningKey: p.signatureKey.Serialize(), 141 | Version: CurrentVersion, 142 | } 143 | return p.serializer.Serialize(structure) 144 | } 145 | 146 | // Type will return the message's type. 147 | func (p *SenderKeyDistributionMessage) Type() uint32 { 148 | return SENDERKEY_DISTRIBUTION_TYPE 149 | } 150 | -------------------------------------------------------------------------------- /protocol/SenderKeyMessage.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "errors" 5 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 6 | "github.com/RadicalApp/libsignal-protocol-go/util/bytehelper" 7 | "strconv" 8 | ) 9 | 10 | // SenderKeyMessageSerializer is an interface for serializing and deserializing 11 | // SenderKeyMessages into bytes. An implementation of this interface should be 12 | // used to encode/decode the object into JSON, Protobuffers, etc. 13 | type SenderKeyMessageSerializer interface { 14 | Serialize(signalMessage *SenderKeyMessageStructure) []byte 15 | Deserialize(serialized []byte) (*SenderKeyMessageStructure, error) 16 | } 17 | 18 | // NewSenderKeyMessageFromBytes will return a Signal Ciphertext message from the given 19 | // bytes using the given serializer. 20 | func NewSenderKeyMessageFromBytes(serialized []byte, 21 | serializer SenderKeyMessageSerializer) (*SenderKeyMessage, error) { 22 | 23 | // Use the given serializer to decode the signal message. 24 | senderKeyMessageStructure, err := serializer.Deserialize(serialized) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | return NewSenderKeyMessageFromStruct(senderKeyMessageStructure, serializer) 30 | } 31 | 32 | // NewSenderKeyMessageFromStruct returns a Signal Ciphertext message from the 33 | // given serializable structure. 34 | func NewSenderKeyMessageFromStruct(structure *SenderKeyMessageStructure, 35 | serializer SenderKeyMessageSerializer) (*SenderKeyMessage, error) { 36 | 37 | // Throw an error if the given message structure is an unsupported version. 38 | if structure.Version <= UnsupportedVersion { 39 | err := "Legacy message: " + strconv.Itoa(int(structure.Version)) 40 | return nil, errors.New(err) 41 | } 42 | 43 | // Throw an error if the given message structure is a future version. 44 | if structure.Version > CurrentVersion { 45 | err := "Unknown version: " + strconv.Itoa(int(structure.Version)) 46 | return nil, errors.New(err) 47 | } 48 | 49 | // Throw an error if the structure is missing critical fields. 50 | if structure.CipherText == nil { 51 | err := "Incomplete message." 52 | return nil, errors.New(err) 53 | } 54 | 55 | // Create the signal message object from the structure. 56 | whisperMessage := &SenderKeyMessage{ 57 | keyID: structure.ID, 58 | version: structure.Version, 59 | iteration: structure.Iteration, 60 | ciphertext: structure.CipherText, 61 | signature: structure.Signature, 62 | serializer: serializer, 63 | } 64 | 65 | return whisperMessage, nil 66 | } 67 | 68 | // NewSenderKeyMessage returns a SenderKeyMessage. 69 | func NewSenderKeyMessage(keyID uint32, iteration uint32, ciphertext []byte, 70 | signatureKey ecc.ECPrivateKeyable, serializer SenderKeyMessageSerializer) *SenderKeyMessage { 71 | 72 | // Ensure we have a valid signature key 73 | if signatureKey == nil { 74 | panic("Signature is nil. Unable to sign new senderkey message.") 75 | } 76 | 77 | // Build our SenderKeyMessage. 78 | senderKeyMessage := &SenderKeyMessage{ 79 | keyID: keyID, 80 | iteration: iteration, 81 | ciphertext: ciphertext, 82 | version: CurrentVersion, 83 | serializer: serializer, 84 | } 85 | 86 | // Sign the serialized message and include it in the message. This will be included 87 | // in the signed serialized version of the message. 88 | signature := ecc.CalculateSignature(signatureKey, senderKeyMessage.Serialize()) 89 | senderKeyMessage.signature = bytehelper.ArrayToSlice64(signature) 90 | 91 | return senderKeyMessage 92 | } 93 | 94 | // SenderKeyMessageStructure is a serializeable structure for SenderKey messages. 95 | type SenderKeyMessageStructure struct { 96 | ID uint32 97 | Iteration uint32 98 | CipherText []byte 99 | Version uint32 100 | Signature []byte 101 | } 102 | 103 | // SenderKeyMessage is a structure for messages using senderkey groups. 104 | type SenderKeyMessage struct { 105 | version uint32 106 | keyID uint32 107 | iteration uint32 108 | ciphertext []byte 109 | signature []byte 110 | serializer SenderKeyMessageSerializer 111 | } 112 | 113 | // KeyID returns the SenderKeyMessage key ID. 114 | func (p *SenderKeyMessage) KeyID() uint32 { 115 | return p.keyID 116 | } 117 | 118 | // Iteration returns the SenderKeyMessage iteration. 119 | func (p *SenderKeyMessage) Iteration() uint32 { 120 | return p.iteration 121 | } 122 | 123 | // Ciphertext returns the SenderKeyMessage encrypted ciphertext. 124 | func (p *SenderKeyMessage) Ciphertext() []byte { 125 | return p.ciphertext 126 | } 127 | 128 | // Version returns the Signal message version of the message. 129 | func (p *SenderKeyMessage) Version() uint32 { 130 | return p.version 131 | } 132 | 133 | // Serialize will use the given serializer to return the message as bytes 134 | // excluding the signature. This should be used for signing and verifying 135 | // message signatures. 136 | func (p *SenderKeyMessage) Serialize() []byte { 137 | structure := &SenderKeyMessageStructure{ 138 | ID: p.keyID, 139 | Iteration: p.iteration, 140 | CipherText: p.ciphertext, 141 | Version: p.version, 142 | } 143 | 144 | return p.serializer.Serialize(structure) 145 | } 146 | 147 | // SignedSerialize will use the given serializer to return the message as 148 | // bytes with the message signature included. This should be used when 149 | // sending the message over the network. 150 | func (p *SenderKeyMessage) SignedSerialize() []byte { 151 | structure := &SenderKeyMessageStructure{ 152 | ID: p.keyID, 153 | Iteration: p.iteration, 154 | CipherText: p.ciphertext, 155 | Version: p.version, 156 | Signature: p.signature, 157 | } 158 | 159 | return p.serializer.Serialize(structure) 160 | } 161 | 162 | // Signature returns the SenderKeyMessage signature 163 | func (p *SenderKeyMessage) Signature() [64]byte { 164 | return bytehelper.SliceToArray64(p.signature) 165 | } 166 | 167 | // Type returns the sender key type. 168 | func (p *SenderKeyMessage) Type() uint32 { 169 | return SENDERKEY_TYPE 170 | } 171 | -------------------------------------------------------------------------------- /protocol/SenderKeyName.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | // NewSenderKeyName returns a new SenderKeyName object. 4 | func NewSenderKeyName(groupID string, sender *SignalAddress) *SenderKeyName { 5 | return &SenderKeyName{ 6 | groupID: groupID, 7 | sender: sender, 8 | } 9 | } 10 | 11 | // SenderKeyName is a structure for a group session address. 12 | type SenderKeyName struct { 13 | groupID string 14 | sender *SignalAddress 15 | } 16 | 17 | // GroupID returns the sender key group id 18 | func (n *SenderKeyName) GroupID() string { 19 | return n.groupID 20 | } 21 | 22 | // Sender returns the Signal address of sending user in the group. 23 | func (n *SenderKeyName) Sender() *SignalAddress { 24 | return n.sender 25 | } 26 | -------------------------------------------------------------------------------- /protocol/SignalMessage.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha256" 6 | "errors" 7 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 8 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 9 | "github.com/RadicalApp/libsignal-protocol-go/logger" 10 | "github.com/RadicalApp/libsignal-protocol-go/util/bytehelper" 11 | "strconv" 12 | ) 13 | 14 | const macLength int = 8 15 | 16 | // SignalMessageSerializer is an interface for serializing and deserializing 17 | // SignalMessages into bytes. An implementation of this interface should be 18 | // used to encode/decode the object into JSON, Protobuffers, etc. 19 | type SignalMessageSerializer interface { 20 | Serialize(signalMessage *SignalMessageStructure) []byte 21 | Deserialize(serialized []byte) (*SignalMessageStructure, error) 22 | } 23 | 24 | // NewSignalMessageFromBytes will return a Signal Ciphertext message from the given 25 | // bytes using the given serializer. 26 | func NewSignalMessageFromBytes(serialized []byte, serializer SignalMessageSerializer) (*SignalMessage, error) { 27 | // Use the given serializer to decode the signal message. 28 | signalMessageStructure, err := serializer.Deserialize(serialized) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | return NewSignalMessageFromStruct(signalMessageStructure, serializer) 34 | } 35 | 36 | // NewSignalMessageFromStruct returns a Signal Ciphertext message from the 37 | // given serializable structure. 38 | func NewSignalMessageFromStruct(structure *SignalMessageStructure, serializer SignalMessageSerializer) (*SignalMessage, error) { 39 | // Throw an error if the given message structure is an unsupported version. 40 | if structure.Version <= UnsupportedVersion { 41 | err := "Legacy message: " + strconv.Itoa(structure.Version) 42 | return nil, errors.New(err) 43 | } 44 | 45 | // Throw an error if the given message structure is a future version. 46 | if structure.Version > CurrentVersion { 47 | err := "Unknown version: " + strconv.Itoa(structure.Version) 48 | return nil, errors.New(err) 49 | } 50 | 51 | // Throw an error if the structure is missing critical fields. 52 | if structure.CipherText == nil || structure.RatchetKey == nil { 53 | err := "Incomplete message." 54 | return nil, errors.New(err) 55 | } 56 | 57 | // Create the signal message object from the structure. 58 | whisperMessage := &SignalMessage{structure: *structure, serializer: serializer} 59 | 60 | // Generate the ECC key from bytes. 61 | var err error 62 | whisperMessage.senderRatchetKey, err = ecc.DecodePoint(structure.RatchetKey, 0) 63 | if err != nil { 64 | return nil, err 65 | } 66 | 67 | return whisperMessage, nil 68 | } 69 | 70 | // NewSignalMessage returns a Signal Ciphertext message. 71 | func NewSignalMessage(messageVersion int, counter, previousCounter uint32, macKey []byte, 72 | senderRatchetKey ecc.ECPublicKeyable, ciphertext []byte, senderIdentityKey, 73 | receiverIdentityKey *identity.Key, serializer SignalMessageSerializer) (*SignalMessage, error) { 74 | 75 | // Build the signal message structure with the given data. 76 | structure := &SignalMessageStructure{ 77 | Version: messageVersion, 78 | Counter: counter, 79 | PreviousCounter: previousCounter, 80 | RatchetKey: senderRatchetKey.Serialize(), 81 | CipherText: ciphertext, 82 | } 83 | 84 | // Get the message authentication code from the serialized structure. 85 | mac, err := getMac( 86 | messageVersion, senderIdentityKey, receiverIdentityKey, 87 | macKey, serializer.Serialize(structure), 88 | ) 89 | if err != nil { 90 | return nil, err 91 | } 92 | structure.Mac = mac 93 | 94 | // Generate a SignalMessage with the structure. 95 | whisperMessage, err := NewSignalMessageFromStruct(structure, serializer) 96 | if err != nil { 97 | return nil, err 98 | } 99 | 100 | return whisperMessage, nil 101 | } 102 | 103 | // SignalMessageStructure is a serializeable structure of a signal message 104 | // object. 105 | type SignalMessageStructure struct { 106 | RatchetKey []byte 107 | Counter uint32 108 | PreviousCounter uint32 109 | CipherText []byte 110 | Version int 111 | Mac []byte 112 | } 113 | 114 | // SignalMessage is a cipher message that contains a message encrypted 115 | // with the Signal protocol. 116 | type SignalMessage struct { 117 | structure SignalMessageStructure 118 | senderRatchetKey ecc.ECPublicKeyable 119 | serializer SignalMessageSerializer 120 | } 121 | 122 | // SenderRatchetKey returns the SignalMessage's sender ratchet key. This 123 | // key is used for ratcheting the chain forward to negotiate a new shared 124 | // secret that cannot be derived from previous chains. 125 | func (s *SignalMessage) SenderRatchetKey() ecc.ECPublicKeyable { 126 | return s.senderRatchetKey 127 | } 128 | 129 | // MessageVersion returns the message version this SignalMessage supports. 130 | func (s *SignalMessage) MessageVersion() int { 131 | return s.structure.Version 132 | } 133 | 134 | // Counter will return the SignalMessage counter. 135 | func (s *SignalMessage) Counter() uint32 { 136 | return s.structure.Counter 137 | } 138 | 139 | // Body will return the SignalMessage's ciphertext in bytes. 140 | func (s *SignalMessage) Body() []byte { 141 | return s.structure.CipherText 142 | } 143 | 144 | // VerifyMac will return an error if the message's message authentication code 145 | // is invalid. This should be used on SignalMessages that have been constructed 146 | // from a sent message. 147 | func (s *SignalMessage) VerifyMac(messageVersion int, senderIdentityKey, 148 | receiverIdentityKey *identity.Key, macKey []byte) error { 149 | 150 | // Create a copy of the message without the mac. We'll use this to calculate 151 | // the message authentication code. 152 | structure := s.structure 153 | signalMessage, err := NewSignalMessageFromStruct(&structure, s.serializer) 154 | if err != nil { 155 | return err 156 | } 157 | signalMessage.structure.Mac = nil 158 | 159 | // Calculate the message authentication code from the serialized structure. 160 | ourMac, err := getMac( 161 | messageVersion, 162 | senderIdentityKey, 163 | receiverIdentityKey, 164 | macKey, 165 | signalMessage.Serialize(), 166 | ) 167 | if err != nil { 168 | logger.Error(err) 169 | return err 170 | } 171 | 172 | // Get the message authentication code that was sent to us as part of 173 | // the signal message structure. 174 | theirMac := s.structure.Mac 175 | 176 | logger.Debug("Verifying macs...") 177 | logger.Debug(" Our MAC: ", ourMac) 178 | logger.Debug(" Their MAC: ", theirMac) 179 | 180 | // Return an error if our calculated mac doesn't match the mac sent to us. 181 | if !hmac.Equal(ourMac, theirMac) { 182 | return errors.New("Bad Mac!") 183 | } 184 | 185 | return nil 186 | } 187 | 188 | // Serialize will return the Signal Message as bytes. 189 | func (s *SignalMessage) Serialize() []byte { 190 | return s.serializer.Serialize(&s.structure) 191 | } 192 | 193 | // Structure will return a serializeable structure of the Signal Message. 194 | func (s *SignalMessage) Structure() *SignalMessageStructure { 195 | structure := s.structure 196 | return &structure 197 | } 198 | 199 | // Type will return the type of Signal Message this is. 200 | func (s *SignalMessage) Type() uint32 { 201 | return WHISPER_TYPE 202 | } 203 | 204 | // getMac will calculate the mac using the given message version, identity 205 | // keys, macKey and SignalMessageStructure. The MAC key is a private key held 206 | // by both parties that is concatenated with the message and hashed. 207 | func getMac(messageVersion int, senderIdentityKey, receiverIdentityKey *identity.Key, 208 | macKey, serialized []byte) ([]byte, error) { 209 | 210 | mac := hmac.New(sha256.New, macKey[:]) 211 | 212 | if messageVersion >= 3 { 213 | mac.Write(senderIdentityKey.PublicKey().Serialize()) 214 | mac.Write(receiverIdentityKey.PublicKey().Serialize()) 215 | } 216 | 217 | mac.Write(serialized) 218 | 219 | fullMac := mac.Sum(nil) 220 | 221 | return bytehelper.Trim(fullMac, macLength), nil 222 | } 223 | -------------------------------------------------------------------------------- /protocol/SignalProtocolAddress.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | const ADDRESS_SEPARATOR = "~" 8 | 9 | // NewSignalAddress returns a new signal address. 10 | func NewSignalAddress(name string, deviceID uint32) *SignalAddress { 11 | addr := SignalAddress{ 12 | name: name, 13 | deviceID: deviceID, 14 | } 15 | 16 | return &addr 17 | } 18 | 19 | // SignalAddress is a combination of a name and a device ID. 20 | type SignalAddress struct { 21 | name string 22 | deviceID uint32 23 | } 24 | 25 | // Name returns the signal address's name. 26 | func (s *SignalAddress) Name() string { 27 | return s.name 28 | } 29 | 30 | // DeviceID returns the signal address's device ID. 31 | func (s *SignalAddress) DeviceID() uint32 { 32 | return s.deviceID 33 | } 34 | 35 | // String returns a string of both the address name and device id. 36 | func (s *SignalAddress) String() string { 37 | return s.name + ADDRESS_SEPARATOR + fmt.Sprint(s.deviceID) 38 | } 39 | -------------------------------------------------------------------------------- /ratchet/Ratchet.go: -------------------------------------------------------------------------------- 1 | // Package ratchet provides the methods necessary to establish a new double 2 | // ratchet session. 3 | package ratchet 4 | 5 | import ( 6 | "encoding/base64" 7 | "encoding/binary" 8 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 9 | "github.com/RadicalApp/libsignal-protocol-go/kdf" 10 | "github.com/RadicalApp/libsignal-protocol-go/keys/chain" 11 | "github.com/RadicalApp/libsignal-protocol-go/keys/root" 12 | "github.com/RadicalApp/libsignal-protocol-go/keys/session" 13 | ) 14 | 15 | var b64 = base64.StdEncoding.EncodeToString 16 | 17 | func genDiscontinuity() [32]byte { 18 | var discontinuity [32]byte 19 | for i := range discontinuity { 20 | discontinuity[i] = 0xFF 21 | } 22 | return discontinuity 23 | } 24 | 25 | // CalculateSenderSession calculates the key agreement for a recipient. This 26 | // should be used when we are trying to send a message to someone for the 27 | // first time. 28 | func CalculateSenderSession(parameters *SenderParameters) (*session.KeyPair, error) { 29 | var secret [32]byte 30 | var publicKey [32]byte 31 | var privateKey [32]byte 32 | masterSecret := make([]byte, 0, 32*5) // Create a master shared secret that is 5 different 32-byte values 33 | discontinuity := genDiscontinuity() 34 | masterSecret = append(masterSecret, discontinuity[:]...) 35 | 36 | // Calculate the agreement using their signed prekey and our identity key. 37 | publicKey = parameters.TheirSignedPreKey().PublicKey() 38 | privateKey = parameters.OurIdentityKey().PrivateKey().Serialize() 39 | secret = kdf.CalculateSharedSecret( 40 | publicKey, 41 | privateKey, 42 | ) 43 | masterSecret = append(masterSecret, secret[:]...) 44 | 45 | // Calculate the agreement using their identity key and our base key. 46 | publicKey = parameters.TheirIdentityKey().PublicKey().PublicKey() 47 | privateKey = parameters.OurBaseKey().PrivateKey().Serialize() 48 | secret = kdf.CalculateSharedSecret( 49 | publicKey, 50 | privateKey, 51 | ) 52 | masterSecret = append(masterSecret, secret[:]...) 53 | 54 | // Calculate the agreement using their signed prekey and our base key. 55 | publicKey = parameters.TheirSignedPreKey().PublicKey() 56 | privateKey = parameters.OurBaseKey().PrivateKey().Serialize() 57 | secret = kdf.CalculateSharedSecret( 58 | publicKey, 59 | privateKey, 60 | ) 61 | masterSecret = append(masterSecret, secret[:]...) 62 | 63 | // If they have a one-time prekey, use it to calculate the shared secret with their 64 | // one time key and our base key. 65 | if parameters.TheirOneTimePreKey() != nil { 66 | publicKey = parameters.TheirOneTimePreKey().PublicKey() 67 | privateKey = parameters.OurBaseKey().PrivateKey().Serialize() 68 | secret = kdf.CalculateSharedSecret( 69 | publicKey, 70 | privateKey, 71 | ) 72 | masterSecret = append(masterSecret, secret[:]...) 73 | 74 | } 75 | 76 | // Derive the root and chain keys based on the master secret. 77 | derivedKeysBytes, err := kdf.DeriveSecrets(masterSecret, nil, []byte(root.KdfInfo), root.DerivedSecretsSize) 78 | if err != nil { 79 | return nil, err 80 | } 81 | derivedKeys := session.NewDerivedSecrets(derivedKeysBytes) 82 | chainKey := chain.NewKey(kdf.DeriveSecrets, derivedKeys.ChainKey(), 0) 83 | rootKey := root.NewKey(kdf.DeriveSecrets, derivedKeys.RootKey()) 84 | 85 | // Add the root and chain keys to a structure that will hold both keys. 86 | sessionKeys := session.NewKeyPair(rootKey, chainKey) 87 | 88 | return sessionKeys, nil 89 | } 90 | 91 | // CalculateReceiverSession calculates the key agreement for a sender. This should 92 | // be used when we are receiving a message from someone for the first time. 93 | func CalculateReceiverSession(parameters *ReceiverParameters) (*session.KeyPair, error) { 94 | var secret [32]byte 95 | var publicKey [32]byte 96 | var privateKey [32]byte 97 | masterSecret := make([]byte, 0, 32*5) // Create a master shared secret that is 5 different 32-byte values 98 | discontinuity := genDiscontinuity() 99 | masterSecret = append(masterSecret, discontinuity[:]...) 100 | 101 | // Calculate the agreement using their identity key and our signed pre key. 102 | publicKey = parameters.TheirIdentityKey().PublicKey().PublicKey() 103 | privateKey = parameters.OurSignedPreKey().PrivateKey().Serialize() 104 | secret = kdf.CalculateSharedSecret( 105 | publicKey, 106 | privateKey, 107 | ) 108 | masterSecret = append(masterSecret, secret[:]...) 109 | 110 | // Calculate the agreement using their base key and our identity key. 111 | publicKey = parameters.TheirBaseKey().PublicKey() 112 | privateKey = parameters.OurIdentityKeyPair().PrivateKey().Serialize() 113 | secret = kdf.CalculateSharedSecret( 114 | publicKey, 115 | privateKey, 116 | ) 117 | masterSecret = append(masterSecret, secret[:]...) 118 | 119 | // Calculate the agreement using their base key and our signed prekey. 120 | publicKey = parameters.TheirBaseKey().PublicKey() 121 | privateKey = parameters.OurSignedPreKey().PrivateKey().Serialize() 122 | secret = kdf.CalculateSharedSecret( 123 | publicKey, 124 | privateKey, 125 | ) 126 | masterSecret = append(masterSecret, secret[:]...) 127 | 128 | // If we had a one-time prekey, use it to calculate the shared secret with our 129 | // one time key and their base key. 130 | if parameters.OurOneTimePreKey() != nil { 131 | publicKey = parameters.TheirBaseKey().PublicKey() 132 | privateKey = parameters.OurOneTimePreKey().PrivateKey().Serialize() 133 | secret = kdf.CalculateSharedSecret( 134 | publicKey, 135 | privateKey, 136 | ) 137 | masterSecret = append(masterSecret, secret[:]...) 138 | 139 | } 140 | 141 | // Derive the root and chain keys based on the master secret. 142 | derivedKeysBytes, err := kdf.DeriveSecrets(masterSecret, nil, []byte(root.KdfInfo), root.DerivedSecretsSize) 143 | if err != nil { 144 | return nil, err 145 | } 146 | derivedKeys := session.NewDerivedSecrets(derivedKeysBytes) 147 | chainKey := chain.NewKey(kdf.DeriveSecrets, derivedKeys.ChainKey(), 0) 148 | rootKey := root.NewKey(kdf.DeriveSecrets, derivedKeys.RootKey()) 149 | 150 | // Add the root and chain keys to a structure that will hold both keys. 151 | sessionKeys := session.NewKeyPair(rootKey, chainKey) 152 | 153 | return sessionKeys, nil 154 | } 155 | 156 | // CalculateSymmetricSession calculates the key agreement between two users. This 157 | // works by both clients exchanging KeyExchange messages to first establish a session. 158 | // This is useful for establishing a session if both users are online. 159 | func CalculateSymmetricSession(parameters *SymmetricParameters) (*session.KeyPair, error) { 160 | // Compare the base public keys so we can deterministically know whether we should 161 | // be setting up a sender or receiver session. If our key converted to an integer is 162 | // less than the other user's, act as a sender. 163 | if isSender(parameters.OurBaseKey.PublicKey(), parameters.TheirBaseKey) { 164 | senderParameters := &SenderParameters{ 165 | ourBaseKey: parameters.OurBaseKey, 166 | ourIdentityKeyPair: parameters.OurIdentityKeyPair, 167 | theirRatchetKey: parameters.TheirRatchetKey, 168 | theirIdentityKey: parameters.TheirIdentityKey, 169 | theirSignedPreKey: parameters.TheirBaseKey, 170 | } 171 | 172 | return CalculateSenderSession(senderParameters) 173 | } 174 | 175 | // If our base public key was larger than the other user's, act as a receiver. 176 | receiverParameters := &ReceiverParameters{ 177 | ourIdentityKeyPair: parameters.OurIdentityKeyPair, 178 | ourRatchetKey: parameters.OurRatchetKey, 179 | ourSignedPreKey: parameters.OurBaseKey, 180 | theirBaseKey: parameters.TheirBaseKey, 181 | theirIdentityKey: parameters.TheirIdentityKey, 182 | } 183 | 184 | return CalculateReceiverSession(receiverParameters) 185 | } 186 | 187 | // isSender is a private method for determining if a symmetric session should 188 | // be calculated as the sender or receiver. It does so by converting the given 189 | // keys into integers and comparing the size of those integers. 190 | func isSender(ourKey, theirKey ecc.ECPublicKeyable) bool { 191 | ourKeyInt := binary.BigEndian.Uint32(ourKey.Serialize()) 192 | theirKeyInt := binary.BigEndian.Uint32(theirKey.Serialize()) 193 | 194 | return ourKeyInt < theirKeyInt 195 | } 196 | -------------------------------------------------------------------------------- /ratchet/ReceiverParameters.go: -------------------------------------------------------------------------------- 1 | package ratchet 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 6 | ) 7 | 8 | // NewReceiverParameters creates a structure with all the keys needed to construct 9 | // a new session when we are receiving a message from a user for the first time. 10 | func NewReceiverParameters(ourIdentityKey *identity.KeyPair, ourSignedPreKey *ecc.ECKeyPair, 11 | ourOneTimePreKey *ecc.ECKeyPair, ourRatchetKey *ecc.ECKeyPair, 12 | theirBaseKey ecc.ECPublicKeyable, theirIdentityKey *identity.Key) *ReceiverParameters { 13 | 14 | receiverParams := ReceiverParameters{ 15 | ourIdentityKeyPair: ourIdentityKey, 16 | ourSignedPreKey: ourSignedPreKey, 17 | ourOneTimePreKey: ourOneTimePreKey, 18 | ourRatchetKey: ourRatchetKey, 19 | theirBaseKey: theirBaseKey, 20 | theirIdentityKey: theirIdentityKey, 21 | } 22 | 23 | return &receiverParams 24 | } 25 | 26 | // NewEmptyReceiverParameters creates an empty structure with the receiver parameters 27 | // needed to create a session. You should use the `set` functions to set all the 28 | // necessary keys needed to build a session. 29 | func NewEmptyReceiverParameters() *ReceiverParameters { 30 | receiverParams := ReceiverParameters{} 31 | 32 | return &receiverParams 33 | } 34 | 35 | // ReceiverParameters describes the session parameters if we are receiving 36 | // a message from someone for the first time. These parameters are used as 37 | // the basis for deriving a shared secret with the sender. 38 | type ReceiverParameters struct { 39 | ourIdentityKeyPair *identity.KeyPair 40 | ourSignedPreKey *ecc.ECKeyPair 41 | ourOneTimePreKey *ecc.ECKeyPair 42 | ourRatchetKey *ecc.ECKeyPair 43 | 44 | theirBaseKey ecc.ECPublicKeyable 45 | theirIdentityKey *identity.Key 46 | } 47 | 48 | // OurIdentityKeyPair returns the identity key of the receiver. 49 | func (r *ReceiverParameters) OurIdentityKeyPair() *identity.KeyPair { 50 | return r.ourIdentityKeyPair 51 | } 52 | 53 | // OurSignedPreKey returns the signed prekey of the receiver. 54 | func (r *ReceiverParameters) OurSignedPreKey() *ecc.ECKeyPair { 55 | return r.ourSignedPreKey 56 | } 57 | 58 | // OurOneTimePreKey returns the one time prekey of the receiver. 59 | func (r *ReceiverParameters) OurOneTimePreKey() *ecc.ECKeyPair { 60 | return r.ourOneTimePreKey 61 | } 62 | 63 | // OurRatchetKey returns the ratchet key of the receiver. 64 | func (r *ReceiverParameters) OurRatchetKey() *ecc.ECKeyPair { 65 | return r.ourRatchetKey 66 | } 67 | 68 | // TheirBaseKey returns the base key of the sender. 69 | func (r *ReceiverParameters) TheirBaseKey() ecc.ECPublicKeyable { 70 | return r.theirBaseKey 71 | } 72 | 73 | // TheirIdentityKey returns the identity key of the sender. 74 | func (r *ReceiverParameters) TheirIdentityKey() *identity.Key { 75 | return r.theirIdentityKey 76 | } 77 | 78 | // SetOurIdentityKeyPair sets the identity key of the receiver. 79 | func (r *ReceiverParameters) SetOurIdentityKeyPair(ourIdentityKey *identity.KeyPair) { 80 | r.ourIdentityKeyPair = ourIdentityKey 81 | } 82 | 83 | // SetOurSignedPreKey sets the signed prekey of the receiver. 84 | func (r *ReceiverParameters) SetOurSignedPreKey(ourSignedPreKey *ecc.ECKeyPair) { 85 | r.ourSignedPreKey = ourSignedPreKey 86 | } 87 | 88 | // SetOurOneTimePreKey sets the one time prekey of the receiver. 89 | func (r *ReceiverParameters) SetOurOneTimePreKey(ourOneTimePreKey *ecc.ECKeyPair) { 90 | r.ourOneTimePreKey = ourOneTimePreKey 91 | } 92 | 93 | // SetOurRatchetKey sets the ratchet key of the receiver. 94 | func (r *ReceiverParameters) SetOurRatchetKey(ourRatchetKey *ecc.ECKeyPair) { 95 | r.ourRatchetKey = ourRatchetKey 96 | } 97 | 98 | // SetTheirBaseKey sets the base key of the sender. 99 | func (r *ReceiverParameters) SetTheirBaseKey(theirBaseKey ecc.ECPublicKeyable) { 100 | r.theirBaseKey = theirBaseKey 101 | } 102 | 103 | // SetTheirIdentityKey sets the identity key of the sender. 104 | func (r *ReceiverParameters) SetTheirIdentityKey(theirIdentityKey *identity.Key) { 105 | r.theirIdentityKey = theirIdentityKey 106 | } 107 | -------------------------------------------------------------------------------- /ratchet/SenderParameters.go: -------------------------------------------------------------------------------- 1 | package ratchet 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 6 | ) 7 | 8 | // NewSenderParameters creates a structure with all the keys needed to construct 9 | // a new session when we are sending a message to a recipient for the first time. 10 | func NewSenderParameters(ourIdentityKey *identity.KeyPair, ourBaseKey *ecc.ECKeyPair, 11 | theirIdentityKey *identity.Key, theirSignedPreKey ecc.ECPublicKeyable, 12 | theirRatchetKey ecc.ECPublicKeyable, theirOneTimePreKey ecc.ECPublicKeyable) *SenderParameters { 13 | 14 | senderParams := SenderParameters{ 15 | ourIdentityKeyPair: ourIdentityKey, 16 | ourBaseKey: ourBaseKey, 17 | theirIdentityKey: theirIdentityKey, 18 | theirSignedPreKey: theirSignedPreKey, 19 | theirOneTimePreKey: theirOneTimePreKey, 20 | theirRatchetKey: theirRatchetKey, 21 | } 22 | 23 | return &senderParams 24 | } 25 | 26 | // NewEmptySenderParameters creates an empty structure with the sender parameters 27 | // needed to create a session. You should use the `set` functions to set all the 28 | // necessary keys needed to build a session. 29 | func NewEmptySenderParameters() *SenderParameters { 30 | senderParams := SenderParameters{} 31 | 32 | return &senderParams 33 | } 34 | 35 | // SenderParameters describes the session parameters if we are sending the 36 | // recipient a message for the first time. These parameters are used as the 37 | // basis for deriving a shared secret with a recipient. 38 | type SenderParameters struct { 39 | ourIdentityKeyPair *identity.KeyPair 40 | ourBaseKey *ecc.ECKeyPair 41 | 42 | theirIdentityKey *identity.Key 43 | theirSignedPreKey ecc.ECPublicKeyable 44 | theirOneTimePreKey ecc.ECPublicKeyable 45 | theirRatchetKey ecc.ECPublicKeyable 46 | } 47 | 48 | // OurIdentityKey returns the identity key pair of the sender. 49 | func (s *SenderParameters) OurIdentityKey() *identity.KeyPair { 50 | return s.ourIdentityKeyPair 51 | } 52 | 53 | // OurBaseKey returns the base ECC key pair of the sender. 54 | func (s *SenderParameters) OurBaseKey() *ecc.ECKeyPair { 55 | return s.ourBaseKey 56 | } 57 | 58 | // TheirIdentityKey returns the identity public key of the receiver. 59 | func (s *SenderParameters) TheirIdentityKey() *identity.Key { 60 | return s.theirIdentityKey 61 | } 62 | 63 | // TheirSignedPreKey returns the signed pre key of the receiver. 64 | func (s *SenderParameters) TheirSignedPreKey() ecc.ECPublicKeyable { 65 | return s.theirSignedPreKey 66 | } 67 | 68 | // TheirOneTimePreKey returns the receiver's one time prekey. 69 | func (s *SenderParameters) TheirOneTimePreKey() ecc.ECPublicKeyable { 70 | return s.theirOneTimePreKey 71 | } 72 | 73 | // TheirRatchetKey returns the receiver's ratchet key. 74 | func (s *SenderParameters) TheirRatchetKey() ecc.ECPublicKeyable { 75 | return s.theirRatchetKey 76 | } 77 | 78 | // SetOurIdentityKey sets the identity key pair of the sender. 79 | func (s *SenderParameters) SetOurIdentityKey(ourIdentityKey *identity.KeyPair) { 80 | s.ourIdentityKeyPair = ourIdentityKey 81 | } 82 | 83 | // SetOurBaseKey sets the base ECC key pair of the sender. 84 | func (s *SenderParameters) SetOurBaseKey(ourBaseKey *ecc.ECKeyPair) { 85 | s.ourBaseKey = ourBaseKey 86 | } 87 | 88 | // SetTheirIdentityKey sets the identity public key of the receiver. 89 | func (s *SenderParameters) SetTheirIdentityKey(theirIdentityKey *identity.Key) { 90 | s.theirIdentityKey = theirIdentityKey 91 | } 92 | 93 | // SetTheirSignedPreKey sets the signed pre key of the receiver. 94 | func (s *SenderParameters) SetTheirSignedPreKey(theirSignedPreKey ecc.ECPublicKeyable) { 95 | s.theirSignedPreKey = theirSignedPreKey 96 | } 97 | 98 | // SetTheirOneTimePreKey sets the receiver's one time prekey. 99 | func (s *SenderParameters) SetTheirOneTimePreKey(theirOneTimePreKey ecc.ECPublicKeyable) { 100 | s.theirOneTimePreKey = theirOneTimePreKey 101 | } 102 | 103 | // SetTheirRatchetKey sets the receiver's ratchet key. 104 | func (s *SenderParameters) SetTheirRatchetKey(theirRatchetKey ecc.ECPublicKeyable) { 105 | s.theirRatchetKey = theirRatchetKey 106 | } 107 | -------------------------------------------------------------------------------- /ratchet/SymmetricParameters.go: -------------------------------------------------------------------------------- 1 | package ratchet 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 6 | ) 7 | 8 | // SymmetricParameters describes the session parameters for sessions where 9 | // both users are online, which doesn't use prekeys for setup. 10 | type SymmetricParameters struct { 11 | OurBaseKey *ecc.ECKeyPair 12 | OurRatchetKey *ecc.ECKeyPair 13 | OurIdentityKeyPair *identity.KeyPair 14 | 15 | TheirBaseKey ecc.ECPublicKeyable 16 | TheirRatchetKey ecc.ECPublicKeyable 17 | TheirIdentityKey *identity.Key 18 | } 19 | -------------------------------------------------------------------------------- /serialize/JSONSerializer.go: -------------------------------------------------------------------------------- 1 | package serialize 2 | 3 | import ( 4 | "encoding/json" 5 | groupRecord "github.com/RadicalApp/libsignal-protocol-go/groups/state/record" 6 | "github.com/RadicalApp/libsignal-protocol-go/logger" 7 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 8 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 9 | ) 10 | 11 | // NewJSONSerializer will return a serializer for all Signal objects that will 12 | // be responsible for converting objects to and from JSON bytes. 13 | func NewJSONSerializer() *Serializer { 14 | serializer := NewSerializer() 15 | 16 | serializer.SignalMessage = &JSONSignalMessageSerializer{} 17 | serializer.PreKeySignalMessage = &JSONPreKeySignalMessageSerializer{} 18 | serializer.SignedPreKeyRecord = &JSONSignedPreKeyRecordSerializer{} 19 | serializer.PreKeyRecord = &JSONPreKeyRecordSerializer{} 20 | serializer.State = &JSONStateSerializer{} 21 | serializer.Session = &JSONSessionSerializer{} 22 | serializer.SenderKeyMessage = &JSONSenderKeyMessageSerializer{} 23 | serializer.SenderKeyDistributionMessage = &JSONSenderKeyDistributionMessageSerializer{} 24 | serializer.SenderKeyRecord = &JSONSenderKeySessionSerializer{} 25 | serializer.SenderKeyState = &JSONSenderKeyStateSerializer{} 26 | 27 | return serializer 28 | } 29 | 30 | // JSONSignalMessageSerializer is a structure for serializing signal messages into 31 | // and from JSON. 32 | type JSONSignalMessageSerializer struct{} 33 | 34 | // Serialize will take a signal message structure and convert it to JSON bytes. 35 | func (j *JSONSignalMessageSerializer) Serialize(signalMessage *protocol.SignalMessageStructure) []byte { 36 | serialized, err := json.Marshal(*signalMessage) 37 | if err != nil { 38 | logger.Error("Error serializing signal message: ", err) 39 | } 40 | logger.Debug("Serialize result: ", string(serialized)) 41 | 42 | return serialized 43 | } 44 | 45 | // Deserialize will take in JSON bytes and return a signal message structure. 46 | func (j *JSONSignalMessageSerializer) Deserialize(serialized []byte) (*protocol.SignalMessageStructure, error) { 47 | var signalMessage protocol.SignalMessageStructure 48 | err := json.Unmarshal(serialized, &signalMessage) 49 | if err != nil { 50 | logger.Error("Error deserializing signal message: ", err) 51 | return nil, err 52 | } 53 | 54 | return &signalMessage, nil 55 | } 56 | 57 | // JSONPreKeySignalMessageSerializer is a structure for serializing prekey signal messages 58 | // into and from JSON. 59 | type JSONPreKeySignalMessageSerializer struct{} 60 | 61 | // Serialize will take a prekey signal message structure and convert it to JSON bytes. 62 | func (j *JSONPreKeySignalMessageSerializer) Serialize(signalMessage *protocol.PreKeySignalMessageStructure) []byte { 63 | serialized, err := json.Marshal(signalMessage) 64 | if err != nil { 65 | logger.Error("Error serializing prekey signal message: ", err) 66 | } 67 | logger.Debug("Serialize result: ", string(serialized)) 68 | 69 | return serialized 70 | } 71 | 72 | // Deserialize will take in JSON bytes and return a prekey signal message structure. 73 | func (j *JSONPreKeySignalMessageSerializer) Deserialize(serialized []byte) (*protocol.PreKeySignalMessageStructure, error) { 74 | var preKeySignalMessage protocol.PreKeySignalMessageStructure 75 | err := json.Unmarshal(serialized, &preKeySignalMessage) 76 | if err != nil { 77 | logger.Error("Error deserializing prekey signal message: ", err) 78 | return nil, err 79 | } 80 | 81 | return &preKeySignalMessage, nil 82 | } 83 | 84 | // JSONSignedPreKeyRecordSerializer is a structure for serializing signed prekey records 85 | // into and from JSON. 86 | type JSONSignedPreKeyRecordSerializer struct{} 87 | 88 | // Serialize will take a signed prekey record structure and convert it to JSON bytes. 89 | func (j *JSONSignedPreKeyRecordSerializer) Serialize(signedPreKey *record.SignedPreKeyStructure) []byte { 90 | serialized, err := json.Marshal(signedPreKey) 91 | if err != nil { 92 | logger.Error("Error serializing signed prekey record: ", err) 93 | } 94 | logger.Debug("Serialize result: ", string(serialized)) 95 | 96 | return serialized 97 | } 98 | 99 | // Deserialize will take in JSON bytes and return a signed prekey record structure. 100 | func (j *JSONSignedPreKeyRecordSerializer) Deserialize(serialized []byte) (*record.SignedPreKeyStructure, error) { 101 | var signedPreKeyStructure record.SignedPreKeyStructure 102 | err := json.Unmarshal(serialized, &signedPreKeyStructure) 103 | if err != nil { 104 | logger.Error("Error deserializing signed prekey record: ", err) 105 | return nil, err 106 | } 107 | 108 | return &signedPreKeyStructure, nil 109 | } 110 | 111 | // JSONPreKeyRecordSerializer is a structure for serializing prekey records 112 | // into and from JSON. 113 | type JSONPreKeyRecordSerializer struct{} 114 | 115 | // Serialize will take a prekey record structure and convert it to JSON bytes. 116 | func (j *JSONPreKeyRecordSerializer) Serialize(preKey *record.PreKeyStructure) []byte { 117 | serialized, err := json.Marshal(preKey) 118 | if err != nil { 119 | logger.Error("Error serializing prekey record: ", err) 120 | } 121 | logger.Debug("Serialize result: ", string(serialized)) 122 | 123 | return serialized 124 | } 125 | 126 | // Deserialize will take in JSON bytes and return a prekey record structure. 127 | func (j *JSONPreKeyRecordSerializer) Deserialize(serialized []byte) (*record.PreKeyStructure, error) { 128 | var preKeyStructure record.PreKeyStructure 129 | err := json.Unmarshal(serialized, &preKeyStructure) 130 | if err != nil { 131 | logger.Error("Error deserializing prekey record: ", err) 132 | return nil, err 133 | } 134 | 135 | return &preKeyStructure, nil 136 | } 137 | 138 | // JSONStateSerializer is a structure for serializing session states into 139 | // and from JSON. 140 | type JSONStateSerializer struct{} 141 | 142 | // Serialize will take a session state structure and convert it to JSON bytes. 143 | func (j *JSONStateSerializer) Serialize(state *record.StateStructure) []byte { 144 | serialized, err := json.Marshal(state) 145 | if err != nil { 146 | logger.Error("Error serializing session state: ", err) 147 | } 148 | logger.Debug("Serialize result: ", string(serialized)) 149 | 150 | return serialized 151 | } 152 | 153 | // Deserialize will take in JSON bytes and return a session state structure. 154 | func (j *JSONStateSerializer) Deserialize(serialized []byte) (*record.StateStructure, error) { 155 | var stateStructure record.StateStructure 156 | err := json.Unmarshal(serialized, &stateStructure) 157 | if err != nil { 158 | logger.Error("Error deserializing session state: ", err) 159 | return nil, err 160 | } 161 | 162 | return &stateStructure, nil 163 | } 164 | 165 | // JSONSessionSerializer is a structure for serializing session records into 166 | // and from JSON. 167 | type JSONSessionSerializer struct{} 168 | 169 | // Serialize will take a session structure and convert it to JSON bytes. 170 | func (j *JSONSessionSerializer) Serialize(session *record.SessionStructure) []byte { 171 | serialized, err := json.Marshal(session) 172 | if err != nil { 173 | logger.Error("Error serializing session: ", err) 174 | } 175 | logger.Debug("Serialize result: ", string(serialized)) 176 | 177 | return serialized 178 | } 179 | 180 | // Deserialize will take in JSON bytes and return a session structure, which can be 181 | // used to create a new Session Record object. 182 | func (j *JSONSessionSerializer) Deserialize(serialized []byte) (*record.SessionStructure, error) { 183 | var sessionStructure record.SessionStructure 184 | err := json.Unmarshal(serialized, &sessionStructure) 185 | if err != nil { 186 | logger.Error("Error deserializing session: ", err) 187 | return nil, err 188 | } 189 | 190 | return &sessionStructure, nil 191 | } 192 | 193 | // JSONSenderKeyDistributionMessageSerializer is a structure for serializing senderkey 194 | // distribution records to and from JSON. 195 | type JSONSenderKeyDistributionMessageSerializer struct{} 196 | 197 | // Serialize will take a senderkey distribution message and convert it to JSON bytes. 198 | func (j *JSONSenderKeyDistributionMessageSerializer) Serialize(message *protocol.SenderKeyDistributionMessageStructure) []byte { 199 | serialized, err := json.Marshal(message) 200 | if err != nil { 201 | logger.Error("Error serializing senderkey distribution message: ", err) 202 | } 203 | logger.Debug("Serialize result: ", string(serialized)) 204 | 205 | return serialized 206 | } 207 | 208 | // Deserialize will take in JSON bytes and return a message structure, which can be 209 | // used to create a new SenderKey Distribution object. 210 | func (j *JSONSenderKeyDistributionMessageSerializer) Deserialize(serialized []byte) (*protocol.SenderKeyDistributionMessageStructure, error) { 211 | var msgStructure protocol.SenderKeyDistributionMessageStructure 212 | err := json.Unmarshal(serialized, &msgStructure) 213 | if err != nil { 214 | logger.Error("Error deserializing senderkey distribution message: ", err) 215 | return nil, err 216 | } 217 | 218 | return &msgStructure, nil 219 | } 220 | 221 | // JSONSenderKeyMessageSerializer is a structure for serializing senderkey 222 | // messages to and from JSON. 223 | type JSONSenderKeyMessageSerializer struct{} 224 | 225 | // Serialize will take a senderkey message and convert it to JSON bytes. 226 | func (j *JSONSenderKeyMessageSerializer) Serialize(message *protocol.SenderKeyMessageStructure) []byte { 227 | serialized, err := json.Marshal(message) 228 | if err != nil { 229 | logger.Error("Error serializing senderkey distribution message: ", err) 230 | } 231 | logger.Debug("Serialize result: ", string(serialized)) 232 | 233 | return serialized 234 | } 235 | 236 | // Deserialize will take in JSON bytes and return a message structure, which can be 237 | // used to create a new SenderKey message object. 238 | func (j *JSONSenderKeyMessageSerializer) Deserialize(serialized []byte) (*protocol.SenderKeyMessageStructure, error) { 239 | var msgStructure protocol.SenderKeyMessageStructure 240 | err := json.Unmarshal(serialized, &msgStructure) 241 | if err != nil { 242 | logger.Error("Error deserializing senderkey message: ", err) 243 | return nil, err 244 | } 245 | 246 | return &msgStructure, nil 247 | } 248 | 249 | // JSONSenderKeyStateSerializer is a structure for serializing group session states into 250 | // and from JSON. 251 | type JSONSenderKeyStateSerializer struct{} 252 | 253 | // Serialize will take a session state structure and convert it to JSON bytes. 254 | func (j *JSONSenderKeyStateSerializer) Serialize(state *groupRecord.SenderKeyStateStructure) []byte { 255 | serialized, err := json.Marshal(state) 256 | if err != nil { 257 | logger.Error("Error serializing session state: ", err) 258 | } 259 | logger.Debug("Serialize result: ", string(serialized)) 260 | 261 | return serialized 262 | } 263 | 264 | // Deserialize will take in JSON bytes and return a session state structure. 265 | func (j *JSONSenderKeyStateSerializer) Deserialize(serialized []byte) (*groupRecord.SenderKeyStateStructure, error) { 266 | var stateStructure groupRecord.SenderKeyStateStructure 267 | err := json.Unmarshal(serialized, &stateStructure) 268 | if err != nil { 269 | logger.Error("Error deserializing session state: ", err) 270 | return nil, err 271 | } 272 | 273 | return &stateStructure, nil 274 | } 275 | 276 | // JSONSenderKeySessionSerializer is a structure for serializing session records into 277 | // and from JSON. 278 | type JSONSenderKeySessionSerializer struct{} 279 | 280 | // Serialize will take a session structure and convert it to JSON bytes. 281 | func (j *JSONSenderKeySessionSerializer) Serialize(session *groupRecord.SenderKeyStructure) []byte { 282 | serialized, err := json.Marshal(session) 283 | if err != nil { 284 | logger.Error("Error serializing session: ", err) 285 | } 286 | logger.Debug("Serialize result: ", string(serialized)) 287 | 288 | return serialized 289 | } 290 | 291 | // Deserialize will take in JSON bytes and return a session structure, which can be 292 | // used to create a new Session Record object. 293 | func (j *JSONSenderKeySessionSerializer) Deserialize(serialized []byte) (*groupRecord.SenderKeyStructure, error) { 294 | var sessionStructure groupRecord.SenderKeyStructure 295 | err := json.Unmarshal(serialized, &sessionStructure) 296 | if err != nil { 297 | logger.Error("Error deserializing session: ", err) 298 | return nil, err 299 | } 300 | 301 | return &sessionStructure, nil 302 | } 303 | -------------------------------------------------------------------------------- /serialize/Serializer.go: -------------------------------------------------------------------------------- 1 | // Package serialize provides a serialization structure to serialize and 2 | // deserialize Signal objects into storeable and transportable bytes. 3 | package serialize 4 | 5 | import ( 6 | groupRecord "github.com/RadicalApp/libsignal-protocol-go/groups/state/record" 7 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 8 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 9 | ) 10 | 11 | // NewSerializer will return a new serializer object that will be used 12 | // to encode/decode Signal objects into bytes. 13 | func NewSerializer() *Serializer { 14 | return &Serializer{} 15 | } 16 | 17 | // Serializer is a structure to serialize Signal objects 18 | // into bytes. This allows you to use any serialization format 19 | // to store or send Signal objects. 20 | type Serializer struct { 21 | SenderKeyRecord groupRecord.SenderKeySerializer 22 | SenderKeyState groupRecord.SenderKeyStateSerializer 23 | SignalMessage protocol.SignalMessageSerializer 24 | PreKeySignalMessage protocol.PreKeySignalMessageSerializer 25 | SenderKeyMessage protocol.SenderKeyMessageSerializer 26 | SenderKeyDistributionMessage protocol.SenderKeyDistributionMessageSerializer 27 | SignedPreKeyRecord record.SignedPreKeySerializer 28 | PreKeyRecord record.PreKeySerializer 29 | State record.StateSerializer 30 | Session record.SessionSerializer 31 | } 32 | -------------------------------------------------------------------------------- /session/Session.go: -------------------------------------------------------------------------------- 1 | // Package session provides the methods necessary to build sessions 2 | package session 3 | 4 | import ( 5 | "errors" 6 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 7 | "github.com/RadicalApp/libsignal-protocol-go/keys/prekey" 8 | "github.com/RadicalApp/libsignal-protocol-go/logger" 9 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 10 | "github.com/RadicalApp/libsignal-protocol-go/ratchet" 11 | "github.com/RadicalApp/libsignal-protocol-go/serialize" 12 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 13 | "github.com/RadicalApp/libsignal-protocol-go/state/store" 14 | "github.com/RadicalApp/libsignal-protocol-go/util/medium" 15 | "github.com/RadicalApp/libsignal-protocol-go/util/optional" 16 | ) 17 | 18 | // Define error constants used for error messages. 19 | const untrustedIdentityError string = "Untrusted identity" 20 | const noSignedPreKeyError string = "No signed prekey!" 21 | const invalidSignatureError string = "Invalid signature on device key!" 22 | const nilOneTimePreKeyError string = "Prekey store returned a nil one time prekey! Was the key already processed?" 23 | 24 | // NewBuilder constructs a session builder. 25 | func NewBuilder(sessionStore store.Session, preKeyStore store.PreKey, 26 | signedStore store.SignedPreKey, identityStore store.IdentityKey, 27 | remoteAddress *protocol.SignalAddress, serializer *serialize.Serializer) *Builder { 28 | 29 | builder := Builder{ 30 | sessionStore: sessionStore, 31 | preKeyStore: preKeyStore, 32 | signedPreKeyStore: signedStore, 33 | identityKeyStore: identityStore, 34 | remoteAddress: remoteAddress, 35 | serializer: serializer, 36 | } 37 | 38 | return &builder 39 | } 40 | 41 | // NewBuilderFromSignal Store constructs a session builder using a 42 | // SignalProtocol Store. 43 | func NewBuilderFromSignal(signalStore store.SignalProtocol, 44 | remoteAddress *protocol.SignalAddress, serializer *serialize.Serializer) *Builder { 45 | 46 | builder := Builder{ 47 | sessionStore: signalStore, 48 | preKeyStore: signalStore, 49 | signedPreKeyStore: signalStore, 50 | identityKeyStore: signalStore, 51 | remoteAddress: remoteAddress, 52 | serializer: serializer, 53 | } 54 | 55 | return &builder 56 | } 57 | 58 | // Builder is responsible for setting up encrypted sessions. 59 | // Once a session has been established, SessionCipher can be 60 | // used to encrypt/decrypt messages in that session. 61 | // 62 | // Sessions are built from one of three different vectors: 63 | // * PreKeyBundle retrieved from a server. 64 | // * PreKeySignalMessage received from a client. 65 | // * KeyExchangeMessage sent to or received from a client. 66 | // 67 | // Sessions are constructed per recipientId + deviceId tuple. 68 | // Remote logical users are identified by their recipientId, 69 | // and each logical recipientId can have multiple physical 70 | // devices. 71 | type Builder struct { 72 | sessionStore store.Session 73 | preKeyStore store.PreKey 74 | signedPreKeyStore store.SignedPreKey 75 | identityKeyStore store.IdentityKey 76 | remoteAddress *protocol.SignalAddress 77 | serializer *serialize.Serializer 78 | } 79 | 80 | // Process builds a new session from a session record and pre 81 | // key signal message. 82 | func (b *Builder) Process(message *protocol.PreKeySignalMessage) (unsignedPreKeyID *optional.Uint32, err error) { 83 | 84 | // Load or create session record for this session. 85 | sessionRecord := b.sessionStore.LoadSession(b.remoteAddress) 86 | 87 | // Check to see if the keys are trusted. 88 | theirIdentityKey := message.IdentityKey() 89 | if !(b.identityKeyStore.IsTrustedIdentity(b.remoteAddress, theirIdentityKey)) { 90 | return nil, errors.New(untrustedIdentityError) 91 | } 92 | 93 | // Use version 3 of the signal/axolotl protocol. 94 | unsignedPreKeyID, err = b.processV3(sessionRecord, message) 95 | if err != nil { 96 | return nil, err 97 | } 98 | 99 | // Save the identity key to our identity store. 100 | b.identityKeyStore.SaveIdentity(b.remoteAddress, theirIdentityKey) 101 | 102 | // Return the unsignedPreKeyID 103 | return unsignedPreKeyID, nil 104 | } 105 | 106 | // ProcessV3 builds a new session from a session record and pre key 107 | // signal message. After a session is constructed in this way, the embedded 108 | // SignalMessage can be decrypted. 109 | func (b *Builder) processV3(sessionRecord *record.Session, 110 | message *protocol.PreKeySignalMessage) (unsignedPreKeyID *optional.Uint32, err error) { 111 | 112 | logger.Debug("Processing message with PreKeyID: ", message.PreKeyID()) 113 | 114 | // Check to see if we've already set up a session for this V3 message. 115 | sessionExists := sessionRecord.HasSessionState( 116 | message.MessageVersion(), 117 | message.BaseKey().Serialize(), 118 | ) 119 | if sessionExists { 120 | logger.Warning("We've already setup a session for this V3 message, letting bundled message fall through...") 121 | return nil, nil 122 | } 123 | 124 | // Load our signed prekey from our signed prekey store. 125 | ourSignedPreKeyRecord := b.signedPreKeyStore.LoadSignedPreKey(message.SignedPreKeyID()) 126 | ourSignedPreKey := ourSignedPreKeyRecord.KeyPair() 127 | 128 | // Build the parameters of the session. 129 | parameters := ratchet.NewEmptyReceiverParameters() 130 | parameters.SetTheirBaseKey(message.BaseKey()) 131 | parameters.SetTheirIdentityKey(message.IdentityKey()) 132 | parameters.SetOurIdentityKeyPair(b.identityKeyStore.GetIdentityKeyPair()) 133 | parameters.SetOurSignedPreKey(ourSignedPreKey) 134 | parameters.SetOurRatchetKey(ourSignedPreKey) 135 | 136 | // Set our one time pre key with the one from our prekey store 137 | // if the message contains a valid pre key id 138 | if message.PreKeyID() != nil { 139 | oneTimePreKey := b.preKeyStore.LoadPreKey(message.PreKeyID().Value) 140 | if oneTimePreKey == nil { 141 | logger.Error(nilOneTimePreKeyError) 142 | return nil, errors.New(nilOneTimePreKeyError) 143 | } 144 | parameters.SetOurOneTimePreKey(oneTimePreKey.KeyPair()) 145 | } else { 146 | parameters.SetOurOneTimePreKey(nil) 147 | } 148 | 149 | // If this is a fresh record, archive our current state. 150 | if !sessionRecord.IsFresh() { 151 | sessionRecord.ArchiveCurrentState() 152 | } 153 | 154 | ///////// Initialize our session ///////// 155 | sessionState := sessionRecord.SessionState() 156 | derivedKeys, sessionErr := ratchet.CalculateReceiverSession(parameters) 157 | if sessionErr != nil { 158 | return nil, sessionErr 159 | } 160 | sessionState.SetVersion(protocol.CurrentVersion) 161 | sessionState.SetRemoteIdentityKey(parameters.TheirIdentityKey()) 162 | sessionState.SetLocalIdentityKey(parameters.OurIdentityKeyPair().PublicKey()) 163 | sessionState.SetSenderChain(parameters.OurRatchetKey(), derivedKeys.ChainKey) 164 | sessionState.SetRootKey(derivedKeys.RootKey) 165 | 166 | // Set the session's registration ids and base key 167 | sessionState.SetLocalRegistrationID(b.identityKeyStore.GetLocalRegistrationId()) 168 | sessionState.SetRemoteRegistrationID(message.RegistrationID()) 169 | sessionState.SetSenderBaseKey(message.BaseKey().Serialize()) 170 | 171 | // Remove the PreKey from our store and return the message prekey id if it is valid. 172 | if message.PreKeyID() != nil && message.PreKeyID().Value != medium.MaxValue { 173 | logger.Debug("Removing preKey from our prekey store: ", message.PreKeyID().Value) 174 | b.preKeyStore.RemovePreKey(message.PreKeyID().Value) 175 | return message.PreKeyID(), nil 176 | } 177 | return nil, nil 178 | } 179 | 180 | // ProcessBundle builds a new session from a PreKeyBundle retrieved 181 | // from a server. 182 | func (b *Builder) ProcessBundle(preKey *prekey.Bundle) error { 183 | // Check to see if the keys are trusted. 184 | if !(b.identityKeyStore.IsTrustedIdentity(b.remoteAddress, preKey.IdentityKey())) { 185 | return errors.New(untrustedIdentityError) 186 | } 187 | 188 | // Check to see if the bundle has a signed pre key. 189 | if preKey.SignedPreKey() == nil { 190 | return errors.New(noSignedPreKeyError) 191 | } 192 | 193 | // Verify the signature of the pre key 194 | preKeyPublic := preKey.IdentityKey().PublicKey() 195 | preKeyBytes := preKey.SignedPreKey().Serialize() 196 | preKeySignature := preKey.SignedPreKeySignature() 197 | if !ecc.VerifySignature(preKeyPublic, preKeyBytes, preKeySignature) { 198 | return errors.New(invalidSignatureError) 199 | } 200 | 201 | // Load our session and generate keys. 202 | sessionRecord := b.sessionStore.LoadSession(b.remoteAddress) 203 | ourBaseKey, err := ecc.GenerateKeyPair() 204 | if err != nil { 205 | return err 206 | } 207 | theirSignedPreKey := preKey.SignedPreKey() 208 | theirOneTimePreKey := preKey.PreKey() 209 | theirOneTimePreKeyID := preKey.PreKeyID() 210 | 211 | // Build the parameters of the session 212 | parameters := ratchet.NewEmptySenderParameters() 213 | parameters.SetOurBaseKey(ourBaseKey) 214 | parameters.SetOurIdentityKey(b.identityKeyStore.GetIdentityKeyPair()) 215 | parameters.SetTheirIdentityKey(preKey.IdentityKey()) 216 | parameters.SetTheirSignedPreKey(theirSignedPreKey) 217 | parameters.SetTheirRatchetKey(theirSignedPreKey) 218 | parameters.SetTheirOneTimePreKey(theirOneTimePreKey) 219 | 220 | // If this is a fresh record, archive our current state. 221 | if !sessionRecord.IsFresh() { 222 | sessionRecord.ArchiveCurrentState() 223 | } 224 | 225 | ///////// Initialize our session ///////// 226 | sessionState := sessionRecord.SessionState() 227 | derivedKeys, sessionErr := ratchet.CalculateSenderSession(parameters) 228 | if sessionErr != nil { 229 | return sessionErr 230 | } 231 | // Generate an ephemeral "ratchet" key that will be advertised to 232 | // the receiving user. 233 | sendingRatchetKey, keyErr := ecc.GenerateKeyPair() 234 | if keyErr != nil { 235 | return keyErr 236 | } 237 | sendingChain, chainErr := derivedKeys.RootKey.CreateChain( 238 | parameters.TheirRatchetKey(), 239 | sendingRatchetKey, 240 | ) 241 | if chainErr != nil { 242 | return chainErr 243 | } 244 | 245 | // Calculate the sender session. 246 | sessionState.SetVersion(protocol.CurrentVersion) 247 | sessionState.SetRemoteIdentityKey(parameters.TheirIdentityKey()) 248 | sessionState.SetLocalIdentityKey(parameters.OurIdentityKey().PublicKey()) 249 | sessionState.AddReceiverChain(parameters.TheirRatchetKey(), derivedKeys.ChainKey.Current()) 250 | sessionState.SetSenderChain(sendingRatchetKey, sendingChain.ChainKey) 251 | sessionState.SetRootKey(sendingChain.RootKey) 252 | 253 | // Update our session record with the unackowledged prekey message 254 | sessionState.SetUnacknowledgedPreKeyMessage( 255 | theirOneTimePreKeyID, 256 | preKey.SignedPreKeyID(), 257 | ourBaseKey.PublicKey(), 258 | ) 259 | 260 | // Set the local registration ID based on the registration id in our identity key store. 261 | sessionState.SetLocalRegistrationID( 262 | b.identityKeyStore.GetLocalRegistrationId(), 263 | ) 264 | 265 | // Set the remote registration ID based on the given prekey bundle registrationID. 266 | sessionState.SetRemoteRegistrationID( 267 | preKey.RegistrationID(), 268 | ) 269 | 270 | // Set the sender base key in our session record state. 271 | sessionState.SetSenderBaseKey( 272 | ourBaseKey.PublicKey().Serialize(), 273 | ) 274 | 275 | // Store the session in our session store and save the identity in our identity store. 276 | b.sessionStore.StoreSession(b.remoteAddress, sessionRecord) 277 | b.identityKeyStore.SaveIdentity(b.remoteAddress, preKey.IdentityKey()) 278 | 279 | return nil 280 | } 281 | -------------------------------------------------------------------------------- /state/record/ChainState.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | "github.com/RadicalApp/libsignal-protocol-go/kdf" 6 | "github.com/RadicalApp/libsignal-protocol-go/keys/chain" 7 | "github.com/RadicalApp/libsignal-protocol-go/keys/message" 8 | "github.com/RadicalApp/libsignal-protocol-go/util/bytehelper" 9 | ) 10 | 11 | // NewReceiverChainPair will return a new ReceiverChainPair object. 12 | func NewReceiverChainPair(receiverChain *Chain, index int) *ReceiverChainPair { 13 | return &ReceiverChainPair{ 14 | ReceiverChain: receiverChain, 15 | Index: index, 16 | } 17 | } 18 | 19 | // ReceiverChainPair is a structure for a receiver chain key and index number. 20 | type ReceiverChainPair struct { 21 | ReceiverChain *Chain 22 | Index int 23 | } 24 | 25 | // NewChain returns a new Chain structure for SessionState. 26 | func NewChain(senderRatchetKeyPair *ecc.ECKeyPair, chainKey *chain.Key, 27 | messageKeys []*message.Keys) *Chain { 28 | 29 | return &Chain{ 30 | senderRatchetKeyPair: senderRatchetKeyPair, 31 | chainKey: chainKey, 32 | messageKeys: messageKeys, 33 | } 34 | } 35 | 36 | // NewChainFromStructure will return a new Chain with the given 37 | // chain structure. 38 | func NewChainFromStructure(structure *ChainStructure) (*Chain, error) { 39 | // Alias to SliceToArray 40 | getArray := bytehelper.SliceToArray 41 | 42 | // Build the sender ratchet key from bytes. 43 | senderRatchetKeyPublic, err := ecc.DecodePoint(structure.SenderRatchetKeyPublic, 0) 44 | if err != nil { 45 | return nil, err 46 | } 47 | var senderRatchetKeyPrivate ecc.ECPrivateKeyable 48 | if len(structure.SenderRatchetKeyPrivate) == 32 { 49 | senderRatchetKeyPrivate = ecc.NewDjbECPrivateKey(getArray(structure.SenderRatchetKeyPrivate)) 50 | } 51 | senderRatchetKeyPair := ecc.NewECKeyPair(senderRatchetKeyPublic, senderRatchetKeyPrivate) 52 | 53 | // Build our message keys from the message key structures. 54 | messageKeys := make([]*message.Keys, len(structure.MessageKeys)) 55 | for i := range structure.MessageKeys { 56 | messageKeys[i] = message.NewKeysFromStruct(structure.MessageKeys[i]) 57 | } 58 | 59 | // Build our new chain state. 60 | chainState := NewChain( 61 | senderRatchetKeyPair, 62 | chain.NewKeyFromStruct(structure.ChainKey, kdf.DeriveSecrets), 63 | messageKeys, 64 | ) 65 | 66 | return chainState, nil 67 | } 68 | 69 | // ChainStructure is a serializeable structure for chain states. 70 | type ChainStructure struct { 71 | SenderRatchetKeyPublic []byte 72 | SenderRatchetKeyPrivate []byte 73 | ChainKey *chain.KeyStructure 74 | MessageKeys []*message.KeysStructure 75 | } 76 | 77 | // Chain is a structure used inside the SessionState that keeps 78 | // track of an ongoing ratcheting chain for a session. 79 | type Chain struct { 80 | senderRatchetKeyPair *ecc.ECKeyPair 81 | chainKey *chain.Key 82 | messageKeys []*message.Keys 83 | } 84 | 85 | // SenderRatchetKey returns the sender's EC keypair. 86 | func (c *Chain) SenderRatchetKey() *ecc.ECKeyPair { 87 | return c.senderRatchetKeyPair 88 | } 89 | 90 | // SetSenderRatchetKey will set the chain state with the given EC 91 | // key pair. 92 | func (c *Chain) SetSenderRatchetKey(key *ecc.ECKeyPair) { 93 | c.senderRatchetKeyPair = key 94 | } 95 | 96 | // ChainKey will return the chain key in the chain state. 97 | func (c *Chain) ChainKey() *chain.Key { 98 | return c.chainKey 99 | } 100 | 101 | // SetChainKey will set the chain state's chain key. 102 | func (c *Chain) SetChainKey(key *chain.Key) { 103 | c.chainKey = key 104 | } 105 | 106 | // MessageKeys will return the message keys associated with the 107 | // chain state. 108 | func (c *Chain) MessageKeys() []*message.Keys { 109 | return c.messageKeys 110 | } 111 | 112 | // SetMessageKeys will set the chain state with the given message 113 | // keys. 114 | func (c *Chain) SetMessageKeys(keys []*message.Keys) { 115 | c.messageKeys = keys 116 | } 117 | 118 | // AddMessageKeys will append the chain state with the given 119 | // message keys. 120 | func (c *Chain) AddMessageKeys(keys *message.Keys) { 121 | c.messageKeys = append(c.messageKeys, keys) 122 | } 123 | 124 | // PopFirstMessageKeys will remove the first message key from 125 | // the chain's list of message keys. 126 | func (c *Chain) PopFirstMessageKeys() *message.Keys { 127 | removed := c.messageKeys[0] 128 | c.messageKeys = c.messageKeys[1:] 129 | 130 | return removed 131 | } 132 | 133 | // structure returns a serializeable structure of the chain state. 134 | func (c *Chain) structure() *ChainStructure { 135 | // Alias to ArrayToSlice 136 | getSlice := bytehelper.ArrayToSlice 137 | 138 | // Convert our message keys into a serializeable structure. 139 | messageKeys := make([]*message.KeysStructure, len(c.messageKeys)) 140 | for i := range c.messageKeys { 141 | messageKeys[i] = message.NewStructFromKeys(c.messageKeys[i]) 142 | } 143 | 144 | // Convert our sender ratchet key private 145 | var senderRatchetKeyPrivate []byte 146 | if c.senderRatchetKeyPair.PrivateKey() != nil { 147 | senderRatchetKeyPrivate = getSlice(c.senderRatchetKeyPair.PrivateKey().Serialize()) 148 | } 149 | 150 | // Build the chain structure. 151 | return &ChainStructure{ 152 | SenderRatchetKeyPublic: c.senderRatchetKeyPair.PublicKey().Serialize(), 153 | SenderRatchetKeyPrivate: senderRatchetKeyPrivate, 154 | ChainKey: chain.NewStructFromKey(c.chainKey), 155 | MessageKeys: messageKeys, 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /state/record/Doc.go: -------------------------------------------------------------------------------- 1 | // Package record provides the state and record of an ongoing double 2 | // ratchet session. 3 | package record 4 | -------------------------------------------------------------------------------- /state/record/PendingKeyExchangeState.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 6 | "github.com/RadicalApp/libsignal-protocol-go/util/bytehelper" 7 | ) 8 | 9 | // NewPendingKeyExchange will return a new PendingKeyExchange object. 10 | func NewPendingKeyExchange(sequence uint32, localBaseKeyPair, localRatchetKeyPair *ecc.ECKeyPair, 11 | localIdentityKeyPair *identity.KeyPair) *PendingKeyExchange { 12 | 13 | return &PendingKeyExchange{ 14 | sequence: sequence, 15 | localBaseKeyPair: localBaseKeyPair, 16 | localRatchetKeyPair: localRatchetKeyPair, 17 | localIdentityKeyPair: localIdentityKeyPair, 18 | } 19 | } 20 | 21 | // NewPendingKeyExchangeFromStruct will return a PendingKeyExchange object from 22 | // the given structure. This is used to get a deserialized pending prekey exchange 23 | // fetched from persistent storage. 24 | func NewPendingKeyExchangeFromStruct(structure *PendingKeyExchangeStructure) *PendingKeyExchange { 25 | // Return nil if no structure was provided. 26 | if structure == nil { 27 | return nil 28 | } 29 | 30 | // Alias the SliceToArray method. 31 | getArray := bytehelper.SliceToArray 32 | 33 | // Convert the bytes in the given structure to ECC objects. 34 | localBaseKeyPair := ecc.NewECKeyPair( 35 | ecc.NewDjbECPublicKey(getArray(structure.LocalBaseKeyPublic)), 36 | ecc.NewDjbECPrivateKey(getArray(structure.LocalBaseKeyPrivate)), 37 | ) 38 | localRatchetKeyPair := ecc.NewECKeyPair( 39 | ecc.NewDjbECPublicKey(getArray(structure.LocalRatchetKeyPublic)), 40 | ecc.NewDjbECPrivateKey(getArray(structure.LocalRatchetKeyPrivate)), 41 | ) 42 | localIdentityKeyPair := identity.NewKeyPair( 43 | identity.NewKey(ecc.NewDjbECPublicKey(getArray(structure.LocalIdentityKeyPublic))), 44 | ecc.NewDjbECPrivateKey(getArray(structure.LocalIdentityKeyPrivate)), 45 | ) 46 | 47 | // Return the PendingKeyExchange with the deserialized keys. 48 | return &PendingKeyExchange{ 49 | sequence: structure.Sequence, 50 | localBaseKeyPair: localBaseKeyPair, 51 | localRatchetKeyPair: localRatchetKeyPair, 52 | localIdentityKeyPair: localIdentityKeyPair, 53 | } 54 | } 55 | 56 | // PendingKeyExchangeStructure is a serializable structure for pending 57 | // key exchanges. This structure is used for persistent storage of the 58 | // key exchange state. 59 | type PendingKeyExchangeStructure struct { 60 | Sequence uint32 61 | LocalBaseKeyPublic []byte 62 | LocalBaseKeyPrivate []byte 63 | LocalRatchetKeyPublic []byte 64 | LocalRatchetKeyPrivate []byte 65 | LocalIdentityKeyPublic []byte 66 | LocalIdentityKeyPrivate []byte 67 | } 68 | 69 | // PendingKeyExchange is a structure for storing a pending 70 | // key exchange for a session state. 71 | type PendingKeyExchange struct { 72 | sequence uint32 73 | localBaseKeyPair *ecc.ECKeyPair 74 | localRatchetKeyPair *ecc.ECKeyPair 75 | localIdentityKeyPair *identity.KeyPair 76 | } 77 | 78 | // structre will return a serializable structure of a pending key exchange 79 | // so it can be persistently stored. 80 | func (p *PendingKeyExchange) structure() *PendingKeyExchangeStructure { 81 | getSlice := bytehelper.ArrayToSlice 82 | return &PendingKeyExchangeStructure{ 83 | Sequence: p.sequence, 84 | LocalBaseKeyPublic: getSlice(p.localBaseKeyPair.PublicKey().PublicKey()), 85 | LocalBaseKeyPrivate: getSlice(p.localBaseKeyPair.PrivateKey().Serialize()), 86 | LocalRatchetKeyPublic: getSlice(p.localRatchetKeyPair.PublicKey().PublicKey()), 87 | LocalRatchetKeyPrivate: getSlice(p.localRatchetKeyPair.PrivateKey().Serialize()), 88 | LocalIdentityKeyPublic: getSlice(p.localIdentityKeyPair.PublicKey().PublicKey().PublicKey()), 89 | LocalIdentityKeyPrivate: getSlice(p.localIdentityKeyPair.PrivateKey().Serialize()), 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /state/record/PendingPreKeyState.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | "github.com/RadicalApp/libsignal-protocol-go/util/optional" 6 | ) 7 | 8 | // NewPendingPreKey will return a new pending pre key object. 9 | func NewPendingPreKey(preKeyID *optional.Uint32, signedPreKeyID uint32, 10 | baseKey ecc.ECPublicKeyable) *PendingPreKey { 11 | 12 | return &PendingPreKey{ 13 | preKeyID: preKeyID, 14 | signedPreKeyID: signedPreKeyID, 15 | baseKey: baseKey, 16 | } 17 | } 18 | 19 | // NewPendingPreKeyFromStruct will return a new pending prekey object from the 20 | // given structure. 21 | func NewPendingPreKeyFromStruct(preKey *PendingPreKeyStructure) (*PendingPreKey, error) { 22 | baseKey, err := ecc.DecodePoint(preKey.BaseKey, 0) 23 | if err != nil { 24 | return nil, err 25 | } 26 | 27 | pendingPreKey := NewPendingPreKey( 28 | preKey.PreKeyID, 29 | preKey.SignedPreKeyID, 30 | baseKey, 31 | ) 32 | 33 | return pendingPreKey, nil 34 | } 35 | 36 | // PendingPreKeyStructure is a serializeable structure for pending 37 | // prekeys. 38 | type PendingPreKeyStructure struct { 39 | PreKeyID *optional.Uint32 40 | SignedPreKeyID uint32 41 | BaseKey []byte 42 | } 43 | 44 | // PendingPreKey is a structure for pending pre keys 45 | // for a session state. 46 | type PendingPreKey struct { 47 | preKeyID *optional.Uint32 48 | signedPreKeyID uint32 49 | baseKey ecc.ECPublicKeyable 50 | } 51 | 52 | // structure will return a serializeable structure of the pending prekey. 53 | func (p *PendingPreKey) structure() *PendingPreKeyStructure { 54 | return &PendingPreKeyStructure{ 55 | PreKeyID: p.preKeyID, 56 | SignedPreKeyID: p.signedPreKeyID, 57 | BaseKey: p.baseKey.Serialize(), 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /state/record/PreKeyRecord.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | "github.com/RadicalApp/libsignal-protocol-go/util/bytehelper" 6 | "github.com/RadicalApp/libsignal-protocol-go/util/optional" 7 | ) 8 | 9 | // PreKeySerializer is an interface for serializing and deserializing 10 | // PreKey objects into bytes. An implementation of this interface should be 11 | // used to encode/decode the object into JSON, Protobuffers, etc. 12 | type PreKeySerializer interface { 13 | Serialize(preKey *PreKeyStructure) []byte 14 | Deserialize(serialized []byte) (*PreKeyStructure, error) 15 | } 16 | 17 | // NewPreKeyFromBytes will return a prekey record from the given bytes using the given serializer. 18 | func NewPreKeyFromBytes(serialized []byte, serializer PreKeySerializer) (*PreKey, error) { 19 | // Use the given serializer to decode the signal message. 20 | preKeyStructure, err := serializer.Deserialize(serialized) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | return NewPreKeyFromStruct(preKeyStructure, serializer) 26 | } 27 | 28 | // NewPreKeyFromStruct returns a PreKey record using the given serializable structure. 29 | func NewPreKeyFromStruct(structure *PreKeyStructure, serializer PreKeySerializer) (*PreKey, error) { 30 | // Create the prekey record from the structure. 31 | preKey := &PreKey{ 32 | structure: *structure, 33 | serializer: serializer, 34 | } 35 | 36 | // Generate the ECC key from bytes. 37 | publicKey := ecc.NewDjbECPublicKey(bytehelper.SliceToArray(structure.PublicKey)) 38 | privateKey := ecc.NewDjbECPrivateKey(bytehelper.SliceToArray(structure.PrivateKey)) 39 | keyPair := ecc.NewECKeyPair(publicKey, privateKey) 40 | preKey.keyPair = keyPair 41 | 42 | return preKey, nil 43 | } 44 | 45 | // NewPreKey record returns a new pre key record that can 46 | // be stored in a PreKeyStore. 47 | func NewPreKey(id uint32, keyPair *ecc.ECKeyPair, serializer PreKeySerializer) *PreKey { 48 | return &PreKey{ 49 | structure: PreKeyStructure{ 50 | ID: id, 51 | PublicKey: keyPair.PublicKey().Serialize(), 52 | PrivateKey: bytehelper.ArrayToSlice(keyPair.PrivateKey().Serialize()), 53 | }, 54 | keyPair: keyPair, 55 | serializer: serializer, 56 | } 57 | } 58 | 59 | // PreKeyStructure is a structure for serializing PreKey records. 60 | type PreKeyStructure struct { 61 | ID uint32 62 | PublicKey []byte 63 | PrivateKey []byte 64 | } 65 | 66 | // PreKey record is a structure for storing pre keys inside 67 | // a PreKeyStore. 68 | type PreKey struct { 69 | structure PreKeyStructure 70 | keyPair *ecc.ECKeyPair 71 | serializer PreKeySerializer 72 | } 73 | 74 | // ID returns the pre key record's id. 75 | func (p *PreKey) ID() *optional.Uint32 { 76 | // TODO: manually set this to empty if empty 77 | return optional.NewOptionalUint32(p.structure.ID) 78 | } 79 | 80 | // KeyPair returns the pre key record's key pair. 81 | func (p *PreKey) KeyPair() *ecc.ECKeyPair { 82 | return p.keyPair 83 | } 84 | 85 | // Serialize uses the PreKey serializer to return the PreKey 86 | // as serialized bytes. 87 | func (p *PreKey) Serialize() []byte { 88 | structure := p.structure 89 | return p.serializer.Serialize(&structure) 90 | } 91 | -------------------------------------------------------------------------------- /state/record/SessionRecord.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "bytes" 5 | ) 6 | 7 | // archivedStatesMaxLength describes how many previous session 8 | // states we should keep track of. 9 | const archivedStatesMaxLength int = 40 10 | 11 | // SessionSerializer is an interface for serializing and deserializing 12 | // a Signal Session into bytes. An implementation of this interface should be 13 | // used to encode/decode the object into JSON, Protobuffers, etc. 14 | type SessionSerializer interface { 15 | Serialize(state *SessionStructure) []byte 16 | Deserialize(serialized []byte) (*SessionStructure, error) 17 | } 18 | 19 | // NewSessionFromBytes will return a Signal Session from the given 20 | // bytes using the given serializer. 21 | func NewSessionFromBytes(serialized []byte, serializer SessionSerializer, stateSerializer StateSerializer) (*Session, error) { 22 | // Use the given serializer to decode the session. 23 | sessionStructure, err := serializer.Deserialize(serialized) 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | return NewSessionFromStructure(sessionStructure, serializer, stateSerializer) 29 | } 30 | 31 | // NewSession creates a new session record and uses the given session and state 32 | // serializers to convert the object into storeable bytes. 33 | func NewSession(serializer SessionSerializer, stateSerializer StateSerializer) *Session { 34 | record := Session{ 35 | sessionState: NewState(stateSerializer), 36 | previousStates: []*State{}, 37 | fresh: true, 38 | serializer: serializer, 39 | } 40 | 41 | return &record 42 | } 43 | 44 | // NewSessionFromStructure will return a new Signal Session from the given 45 | // session structure and serializer. 46 | func NewSessionFromStructure(structure *SessionStructure, serializer SessionSerializer, 47 | stateSerializer StateSerializer) (*Session, error) { 48 | 49 | // Build our previous states from structure. 50 | previousStates := make([]*State, len(structure.PreviousStates)) 51 | for i := range structure.PreviousStates { 52 | var err error 53 | previousStates[i], err = NewStateFromStructure(structure.PreviousStates[i], stateSerializer) 54 | if err != nil { 55 | return nil, err 56 | } 57 | } 58 | 59 | // Build our current state from structure. 60 | sessionState, err := NewStateFromStructure(structure.SessionState, stateSerializer) 61 | if err != nil { 62 | return nil, err 63 | } 64 | 65 | // Build and return our session. 66 | session := &Session{ 67 | previousStates: previousStates, 68 | sessionState: sessionState, 69 | serializer: serializer, 70 | fresh: false, 71 | } 72 | 73 | return session, nil 74 | } 75 | 76 | // NewSessionFromState creates a new session record from the given 77 | // session state. 78 | func NewSessionFromState(sessionState *State, serializer SessionSerializer) *Session { 79 | record := Session{ 80 | sessionState: sessionState, 81 | previousStates: []*State{}, 82 | fresh: false, 83 | serializer: serializer, 84 | } 85 | 86 | return &record 87 | } 88 | 89 | // SessionStructure is a public, serializeable structure for Signal 90 | // Sessions. The states defined in the session are immuteable, as 91 | // they should not be changed by anyone but the serializer. 92 | type SessionStructure struct { 93 | SessionState *StateStructure 94 | PreviousStates []*StateStructure 95 | } 96 | 97 | // Session encapsulates the state of an ongoing session. 98 | type Session struct { 99 | serializer SessionSerializer 100 | sessionState *State 101 | previousStates []*State 102 | fresh bool 103 | } 104 | 105 | // SetState sets the session record's current state to the given 106 | // one. 107 | func (r *Session) SetState(sessionState *State) { 108 | r.sessionState = sessionState 109 | } 110 | 111 | // IsFresh is used to determine if this is a brand new session 112 | // or if a session record has already existed. 113 | func (r *Session) IsFresh() bool { 114 | return r.fresh 115 | } 116 | 117 | // SessionState returns the session state object of the current 118 | // session record. 119 | func (r *Session) SessionState() *State { 120 | return r.sessionState 121 | } 122 | 123 | // PreviousSessionStates returns a list of all currently maintained 124 | // "previous" session states. 125 | func (r *Session) PreviousSessionStates() []*State { 126 | return r.previousStates 127 | } 128 | 129 | // HasSessionState will check this record to see if the sender's 130 | // base key exists in the current and previous states. 131 | func (r *Session) HasSessionState(version int, senderBaseKey []byte) bool { 132 | // Ensure the session state version is identical to this one. 133 | if r.sessionState.Version() == version { 134 | return false 135 | } 136 | 137 | // Ensure the session state has a sender base key. 138 | if r.sessionState.SenderBaseKey() == nil { 139 | return false 140 | } 141 | 142 | // Check our session state and compare the base key to this base key. 143 | if bytes.Compare(senderBaseKey, r.sessionState.SenderBaseKey()) == 0 { 144 | return true 145 | } 146 | 147 | // Loop through all of our previous states and see if this 148 | // exists in our state. 149 | for i := range r.previousStates { 150 | if bytes.Compare(senderBaseKey, r.previousStates[i].SenderBaseKey()) == 0 { 151 | return true 152 | } 153 | } 154 | 155 | return false 156 | } 157 | 158 | // ArchiveCurrentState moves the current session state into the list 159 | // of "previous" session states, and replaces the current session state 160 | // with a fresh reset instance. 161 | func (r *Session) ArchiveCurrentState() { 162 | r.PromoteState(NewState(r.sessionState.serializer)) 163 | } 164 | 165 | // PromoteState takes the given session state and replaces it with the 166 | // current state, pushing the previous current state to "previousStates". 167 | func (r *Session) PromoteState(promotedState *State) { 168 | r.previousStates = r.prependStates(r.previousStates, r.sessionState) 169 | r.sessionState = promotedState 170 | 171 | // Remove the last state if it has reached our maximum length 172 | if len(r.previousStates) > archivedStatesMaxLength { 173 | r.previousStates = r.removeLastState(r.previousStates) 174 | } 175 | } 176 | 177 | // Serialize will return the session as serialized bytes so it can be 178 | // persistently stored. 179 | func (r *Session) Serialize() []byte { 180 | return r.serializer.Serialize(r.structure()) 181 | } 182 | 183 | // prependStates takes an array/slice of states and prepends it with 184 | // the given session state. 185 | func (r *Session) prependStates(states []*State, sessionState *State) []*State { 186 | return append([]*State{sessionState}, states...) 187 | } 188 | 189 | // removeLastState takes an array/slice of states and removes the 190 | // last element from it. 191 | func (r *Session) removeLastState(states []*State) []*State { 192 | return states[:len(states)-1] 193 | } 194 | 195 | // structure will return a simple serializable session structure 196 | // from the given structure. This is used for serialization to persistently 197 | // store a session record. 198 | func (r *Session) structure() *SessionStructure { 199 | previousStates := make([]*StateStructure, len(r.previousStates)) 200 | for i := range r.previousStates { 201 | previousStates[i] = r.previousStates[i].structure() 202 | } 203 | return &SessionStructure{ 204 | SessionState: r.sessionState.structure(), 205 | PreviousStates: previousStates, 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /state/record/SignedPreKeyRecord.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | "github.com/RadicalApp/libsignal-protocol-go/util/bytehelper" 6 | ) 7 | 8 | // SignedPreKeySerializer is an interface for serializing and deserializing 9 | // SignedPreKey objects into bytes. An implementation of this interface should be 10 | // used to encode/decode the object into JSON, Protobuffers, etc. 11 | type SignedPreKeySerializer interface { 12 | Serialize(signedPreKey *SignedPreKeyStructure) []byte 13 | Deserialize(serialized []byte) (*SignedPreKeyStructure, error) 14 | } 15 | 16 | // NewSignedPreKeyFromBytes will return a signed prekey record from the given 17 | // bytes using the given serializer. 18 | func NewSignedPreKeyFromBytes(serialized []byte, serializer SignedPreKeySerializer) (*SignedPreKey, error) { 19 | // Use the given serializer to decode the signal message. 20 | signedPreKeyStructure, err := serializer.Deserialize(serialized) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | return NewSignedPreKeyFromStruct(signedPreKeyStructure, serializer) 26 | } 27 | 28 | // NewSignedPreKeyFromStruct returns a SignedPreKey record using the given 29 | // serializable structure. 30 | func NewSignedPreKeyFromStruct(structure *SignedPreKeyStructure, 31 | serializer SignedPreKeySerializer) (*SignedPreKey, error) { 32 | 33 | // Create the signed prekey record from the structure. 34 | signedPreKey := &SignedPreKey{ 35 | structure: *structure, 36 | serializer: serializer, 37 | signature: bytehelper.SliceToArray64(structure.Signature), 38 | } 39 | 40 | // Generate the ECC key from bytes. 41 | publicKey := ecc.NewDjbECPublicKey(bytehelper.SliceToArray(structure.PublicKey)) 42 | privateKey := ecc.NewDjbECPrivateKey(bytehelper.SliceToArray(structure.PrivateKey)) 43 | keyPair := ecc.NewECKeyPair(publicKey, privateKey) 44 | signedPreKey.keyPair = keyPair 45 | 46 | return signedPreKey, nil 47 | } 48 | 49 | // NewSignedPreKey record creates a new signed pre key record 50 | // with the given properties. 51 | func NewSignedPreKey(id uint32, timestamp int64, keyPair *ecc.ECKeyPair, 52 | sig [64]byte, serializer SignedPreKeySerializer) *SignedPreKey { 53 | 54 | return &SignedPreKey{ 55 | structure: SignedPreKeyStructure{ 56 | ID: id, 57 | Timestamp: timestamp, 58 | PublicKey: keyPair.PublicKey().Serialize(), 59 | PrivateKey: bytehelper.ArrayToSlice(keyPair.PrivateKey().Serialize()), 60 | Signature: bytehelper.ArrayToSlice64(sig), 61 | }, 62 | keyPair: keyPair, 63 | signature: sig, 64 | serializer: serializer, 65 | } 66 | } 67 | 68 | // SignedPreKeyStructure is a flat structure of a signed pre key, used 69 | // for serialization and deserialization. 70 | type SignedPreKeyStructure struct { 71 | ID uint32 72 | PublicKey []byte 73 | PrivateKey []byte 74 | Signature []byte 75 | Timestamp int64 76 | } 77 | 78 | // SignedPreKey record is a structure for storing a signed 79 | // pre key in a SignedPreKey store. 80 | type SignedPreKey struct { 81 | structure SignedPreKeyStructure 82 | keyPair *ecc.ECKeyPair 83 | signature [64]byte 84 | serializer SignedPreKeySerializer 85 | } 86 | 87 | // ID returns the record's id. 88 | func (s *SignedPreKey) ID() uint32 { 89 | return s.structure.ID 90 | } 91 | 92 | // Timestamp returns the record's timestamp 93 | func (s *SignedPreKey) Timestamp() int64 { 94 | return s.structure.Timestamp 95 | } 96 | 97 | // KeyPair returns the signed pre key record's key pair. 98 | func (s *SignedPreKey) KeyPair() *ecc.ECKeyPair { 99 | return s.keyPair 100 | } 101 | 102 | // Signature returns the record's signed prekey signature. 103 | func (s *SignedPreKey) Signature() [64]byte { 104 | return s.signature 105 | } 106 | 107 | // Serialize uses the SignedPreKey serializer to return the SignedPreKey 108 | // as serialized bytes. 109 | func (s *SignedPreKey) Serialize() []byte { 110 | structure := s.structure 111 | return s.serializer.Serialize(&structure) 112 | } 113 | -------------------------------------------------------------------------------- /state/record/UnacknowledgedPreKey.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 5 | "github.com/RadicalApp/libsignal-protocol-go/util/optional" 6 | ) 7 | 8 | // NewUnackPreKeyMessageItems returns message items that are unacknowledged. 9 | func NewUnackPreKeyMessageItems(preKeyID *optional.Uint32, signedPreKeyID uint32, 10 | baseKey ecc.ECPublicKeyable) *UnackPreKeyMessageItems { 11 | 12 | return &UnackPreKeyMessageItems{ 13 | preKeyID: preKeyID, 14 | signedPreKeyID: signedPreKeyID, 15 | baseKey: baseKey, 16 | } 17 | } 18 | 19 | // NewUnackPreKeyMessageItemsFromStruct will return a new unacknowledged prekey 20 | // message items object from the given structure. 21 | func NewUnackPreKeyMessageItemsFromStruct(structure *UnackPreKeyMessageItemsStructure) *UnackPreKeyMessageItems { 22 | baseKey, _ := ecc.DecodePoint(structure.BaseKey, 0) 23 | return NewUnackPreKeyMessageItems( 24 | structure.PreKeyID, 25 | structure.SignedPreKeyID, 26 | baseKey, 27 | ) 28 | } 29 | 30 | // UnackPreKeyMessageItemsStructure is a serializable structure for unackowledged 31 | // prekey message items. 32 | type UnackPreKeyMessageItemsStructure struct { 33 | PreKeyID *optional.Uint32 34 | SignedPreKeyID uint32 35 | BaseKey []byte 36 | } 37 | 38 | // UnackPreKeyMessageItems is a structure for messages that have not been 39 | // acknowledged. 40 | type UnackPreKeyMessageItems struct { 41 | preKeyID *optional.Uint32 42 | signedPreKeyID uint32 43 | baseKey ecc.ECPublicKeyable 44 | } 45 | 46 | // PreKeyID returns the prekey id of the unacknowledged message. 47 | func (u *UnackPreKeyMessageItems) PreKeyID() *optional.Uint32 { 48 | return u.preKeyID 49 | } 50 | 51 | // SignedPreKeyID returns the signed prekey id of the unacknowledged message. 52 | func (u *UnackPreKeyMessageItems) SignedPreKeyID() uint32 { 53 | return u.signedPreKeyID 54 | } 55 | 56 | // BaseKey returns the ECC public key of the unacknowledged message. 57 | func (u *UnackPreKeyMessageItems) BaseKey() ecc.ECPublicKeyable { 58 | return u.baseKey 59 | } 60 | 61 | // structure will return a serializable base structure 62 | // for unacknowledged prekey message items. 63 | func (u *UnackPreKeyMessageItems) structure() *UnackPreKeyMessageItemsStructure { 64 | return &UnackPreKeyMessageItemsStructure{ 65 | PreKeyID: u.preKeyID, 66 | SignedPreKeyID: u.signedPreKeyID, 67 | BaseKey: u.baseKey.Serialize(), 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /state/store/Doc.go: -------------------------------------------------------------------------------- 1 | // Package store provides the storage interfaces for storing the state of 2 | // ongoing double ratchet sessions and keys. 3 | package store 4 | -------------------------------------------------------------------------------- /state/store/IdentityKeyStore.go: -------------------------------------------------------------------------------- 1 | package store 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 5 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 6 | ) 7 | 8 | // IdentityKey provides an interface to identity information. 9 | type IdentityKey interface { 10 | // Get the local client's identity key pair. 11 | GetIdentityKeyPair() *identity.KeyPair 12 | 13 | // Return the local client's registration ID. 14 | // 15 | // Clients should maintain a registration ID, a random number between 1 and 16380 16 | // that's generated once at install time. 17 | GetLocalRegistrationId() uint32 18 | 19 | // Save a remote client's identity key in our identity store. 20 | SaveIdentity(address *protocol.SignalAddress, identityKey *identity.Key) 21 | 22 | // Verify a remote client's identity key. 23 | // 24 | // Determine whether a remote client's identity is trusted. Trust is based on 25 | // 'trust on first use'. This means that an identity key is considered 'trusted' 26 | // if there is no entry for the recipient in the local store, or if it matches the 27 | // saved key for a recipient in the local store. 28 | IsTrustedIdentity(address *protocol.SignalAddress, identityKey *identity.Key) bool 29 | } 30 | -------------------------------------------------------------------------------- /state/store/MessageKeyStore.go: -------------------------------------------------------------------------------- 1 | package store 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/keys/message" 5 | ) 6 | 7 | // MessageKey store is an interface describing the optional local storage 8 | // of message keys. 9 | type MessageKey interface { 10 | // Load a local message key by id 11 | LoadMessageKey(keyID uint32) *message.Keys 12 | 13 | // Store a local message key 14 | StoreMessageKey(keyID uint32, key *message.Keys) 15 | 16 | // Check to see if the store contains a message key with id. 17 | ContainsMessageKey(keyID uint32) bool 18 | 19 | // Delete a message key from local storage. 20 | RemoveMessageKey(keyID uint32) 21 | } 22 | -------------------------------------------------------------------------------- /state/store/PreKeyStore.go: -------------------------------------------------------------------------------- 1 | package store 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 5 | ) 6 | 7 | // PreKey store is an interface describing the local storage 8 | // of PreKeyRecords 9 | type PreKey interface { 10 | // Load a local PreKeyRecord 11 | LoadPreKey(preKeyID uint32) *record.PreKey 12 | 13 | // Store a local PreKeyRecord 14 | StorePreKey(preKeyID uint32, preKeyRecord *record.PreKey) 15 | 16 | // Check to see if the store contains a PreKeyRecord 17 | ContainsPreKey(preKeyID uint32) bool 18 | 19 | // Delete a PreKeyRecord from local storage. 20 | RemovePreKey(preKeyID uint32) 21 | } 22 | -------------------------------------------------------------------------------- /state/store/SessionStore.go: -------------------------------------------------------------------------------- 1 | package store 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 5 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 6 | ) 7 | 8 | // Session store is an interface for the persistent storage of session 9 | // state information for remote clients. 10 | type Session interface { 11 | LoadSession(address *protocol.SignalAddress) *record.Session 12 | GetSubDeviceSessions(name string) []uint32 13 | StoreSession(remoteAddress *protocol.SignalAddress, record *record.Session) 14 | ContainsSession(remoteAddress *protocol.SignalAddress) bool 15 | DeleteSession(remoteAddress *protocol.SignalAddress) 16 | DeleteAllSessions() 17 | } 18 | -------------------------------------------------------------------------------- /state/store/SignalProtocolStore.go: -------------------------------------------------------------------------------- 1 | package store 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/groups/state/store" 5 | ) 6 | 7 | // SignalProtocol store is an interface that implements the 8 | // methods for all stores needed in the Signal Protocol. 9 | type SignalProtocol interface { 10 | IdentityKey 11 | PreKey 12 | Session 13 | SignedPreKey 14 | store.SenderKey 15 | } 16 | -------------------------------------------------------------------------------- /state/store/SignedPreKeyStore.go: -------------------------------------------------------------------------------- 1 | package store 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 5 | ) 6 | 7 | // SignedPreKey store is an interface that describes how to persistently 8 | // store signed PreKeys. 9 | type SignedPreKey interface { 10 | // LoadSignedPreKey loads a local SignedPreKeyRecord 11 | LoadSignedPreKey(signedPreKeyID uint32) *record.SignedPreKey 12 | 13 | // LoadSignedPreKeys loads all local SignedPreKeyRecords 14 | LoadSignedPreKeys() []*record.SignedPreKey 15 | 16 | // Store a local SignedPreKeyRecord 17 | StoreSignedPreKey(signedPreKeyID uint32, record *record.SignedPreKey) 18 | 19 | // Check to see if store contains the given record 20 | ContainsSignedPreKey(signedPreKeyID uint32) bool 21 | 22 | // Delete a SignedPreKeyRecord from local storage 23 | RemoveSignedPreKey(signedPreKeyID uint32) 24 | } 25 | -------------------------------------------------------------------------------- /tests/fingerprint_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "fmt" 5 | "github.com/RadicalApp/libsignal-protocol-go/fingerprint" 6 | "testing" 7 | ) 8 | 9 | // TestFingerprint will test printing key fingerprints. 10 | func TestFingerprint(t *testing.T) { 11 | 12 | // Create a serializer object that will be used to encode/decode data. 13 | serializer := newSerializer() 14 | 15 | // Create our users who will talk to each other. 16 | alice := newUser("Alice", 1, serializer) 17 | bob := newUser("Bob", 2, serializer) 18 | 19 | fp := fingerprint.NewDisplay( 20 | alice.identityKeyPair.PublicKey().Serialize(), 21 | bob.identityKeyPair.PublicKey().Serialize(), 22 | ) 23 | 24 | fmt.Println(fp.DisplayText()) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /tests/group_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/groups" 5 | "github.com/RadicalApp/libsignal-protocol-go/keys/prekey" 6 | "github.com/RadicalApp/libsignal-protocol-go/logger" 7 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 8 | "github.com/RadicalApp/libsignal-protocol-go/serialize" 9 | "github.com/RadicalApp/libsignal-protocol-go/session" 10 | "testing" 11 | ) 12 | 13 | // TestGroupSessionBuilder checks building of a group session. 14 | func TestGroupSessionBuilder(t *testing.T) { 15 | 16 | // Create a serializer object that will be used to encode/decode data. 17 | serializer := newSerializer() 18 | 19 | // Create our users who will talk to each other. 20 | alice := newUser("Alice", 1, serializer) 21 | bob := newUser("Bob", 2, serializer) 22 | groupName := "123" 23 | 24 | // ***** Build one-to-one session with group members ***** 25 | 26 | // Create a session builder to create a session between Alice -> Bob. 27 | alice.buildSession(bob.address, serializer) 28 | bob.buildSession(alice.address, serializer) 29 | 30 | // Create a PreKeyBundle from Bob's prekey records and other 31 | // data. 32 | logger.Debug("Fetching Bob's prekey with ID: ", bob.preKeys[0].ID()) 33 | retrivedPreKey := prekey.NewBundle( 34 | bob.registrationID, 35 | bob.deviceID, 36 | bob.preKeys[0].ID(), 37 | bob.signedPreKey.ID(), 38 | bob.preKeys[0].KeyPair().PublicKey(), 39 | bob.signedPreKey.KeyPair().PublicKey(), 40 | bob.signedPreKey.Signature(), 41 | bob.identityKeyPair.PublicKey(), 42 | ) 43 | 44 | // Process Bob's retrieved prekey to establish a session. 45 | logger.Debug("Building sender's (Alice) session...") 46 | err := alice.sessionBuilder.ProcessBundle(retrivedPreKey) 47 | if err != nil { 48 | logger.Error("Unable to process retrieved prekey bundle") 49 | t.FailNow() 50 | } 51 | 52 | // Create a session builder to create a session between Alice -> Bob. 53 | aliceSenderKeyName := protocol.NewSenderKeyName(groupName, alice.address) 54 | aliceSkdm, err := alice.groupBuilder.Create(aliceSenderKeyName) 55 | if err != nil { 56 | logger.Error("Unable to create group session") 57 | t.FailNow() 58 | } 59 | aliceSendingCipher := groups.NewGroupCipher(alice.groupBuilder, aliceSenderKeyName, alice.senderKeyStore) 60 | 61 | // Create a one-to-one session cipher to encrypt the skdm to Bob. 62 | aliceBobSessionCipher := session.NewCipher(alice.sessionBuilder, bob.address) 63 | encryptedSkdm, err := aliceBobSessionCipher.Encrypt(aliceSkdm.Serialize()) 64 | if err != nil { 65 | logger.Error("Unable to encrypt message: ", err) 66 | t.FailNow() 67 | } 68 | 69 | // ***** Bob receive senderkey distribution message from Alice ***** 70 | 71 | // Emulate receiving the message as JSON over the network. 72 | logger.Debug("Building message from bytes on Bob's end.") 73 | receivedMessage, err := protocol.NewPreKeySignalMessageFromBytes(encryptedSkdm.Serialize(), serializer.PreKeySignalMessage, serializer.SignalMessage) 74 | if err != nil { 75 | logger.Error("Unable to emulate receiving message as JSON: ", err) 76 | t.FailNow() 77 | } 78 | 79 | // Create a session builder 80 | logger.Debug("Building receiver's (Bob) session...") 81 | unsignedPreKeyID, err := bob.sessionBuilder.Process(receivedMessage) 82 | if err != nil { 83 | logger.Error("Unable to process prekeysignal message: ", err) 84 | t.FailNow() 85 | } 86 | logger.Debug("Got PreKeyID: ", unsignedPreKeyID) 87 | 88 | // Try and decrypt the senderkey distribution message 89 | bobAliceSessionCipher := session.NewCipher(bob.sessionBuilder, alice.address) 90 | msg, err := bobAliceSessionCipher.Decrypt(receivedMessage.WhisperMessage()) 91 | if err != nil { 92 | logger.Error("Unable to decrypt message: ", err) 93 | t.FailNow() 94 | } 95 | bobReceivedSkdm, err := protocol.NewSenderKeyDistributionMessageFromBytes(msg, serializer.SenderKeyDistributionMessage) 96 | if err != nil { 97 | logger.Error("Unable to create senderkey distribution message from bytes: ", err) 98 | t.FailNow() 99 | } 100 | 101 | // ***** Alice Send ***** 102 | 103 | // Encrypt some messages to send with Alice's group cipher 104 | logger.Debug("Alice sending messages to Bob...") 105 | alicePlainMessages, aliceEncryptedMessages := sendGroupMessages(1000, aliceSendingCipher, serializer, t) 106 | 107 | // Build bob's side of the session. 108 | bob.groupBuilder.Process(aliceSenderKeyName, bobReceivedSkdm) 109 | receivingBobCipher := groups.NewGroupCipher(bob.groupBuilder, aliceSenderKeyName, bob.senderKeyStore) 110 | 111 | // Decrypt the messages sent by alice. 112 | logger.Debug("Bob receiving messages from Alice...") 113 | receiveGroupMessages(aliceEncryptedMessages, alicePlainMessages, receivingBobCipher, t) 114 | 115 | // ***** Bob send senderkey distribution message to Alice ***** 116 | 117 | // Create a group builder with Bob's address. 118 | bobSenderKeyName := protocol.NewSenderKeyName(groupName, bob.address) 119 | bobSkdm, err := bob.groupBuilder.Create(bobSenderKeyName) 120 | if err != nil { 121 | logger.Error("Unable to create group session") 122 | t.FailNow() 123 | } 124 | bobSendingCipher := groups.NewGroupCipher(bob.groupBuilder, bobSenderKeyName, bob.senderKeyStore) 125 | 126 | // Encrypt the senderKey distribution message to send to Alice. 127 | bobEncryptedSkdm, err := bobAliceSessionCipher.Encrypt(bobSkdm.Serialize()) 128 | if err != nil { 129 | logger.Error("Unable to encrypt message: ", err) 130 | t.FailNow() 131 | } 132 | 133 | // Emulate receiving the message as JSON over the network. 134 | logger.Debug("Building message from bytes on Alice's end.") 135 | aliceReceivedMessage, err := protocol.NewSignalMessageFromBytes(bobEncryptedSkdm.Serialize(), serializer.SignalMessage) 136 | if err != nil { 137 | logger.Error("Unable to emulate receiving message as JSON: ", err) 138 | t.FailNow() 139 | } 140 | 141 | // ***** Alice receives senderkey distribution message from Bob ***** 142 | 143 | // Decrypt the received message. 144 | msg, err = aliceBobSessionCipher.Decrypt(aliceReceivedMessage) 145 | if err != nil { 146 | logger.Error("Unable to decrypt message: ", err) 147 | t.FailNow() 148 | } 149 | aliceReceivedSkdm, err := protocol.NewSenderKeyDistributionMessageFromBytes(msg, serializer.SenderKeyDistributionMessage) 150 | if err != nil { 151 | logger.Error("Unable to create senderkey distribution message from bytes: ", err) 152 | t.FailNow() 153 | } 154 | 155 | // ***** Bob Send ***** 156 | 157 | // Encrypt some messages to send with Bob's group cipher 158 | logger.Debug("Bob sending messages to Alice...") 159 | bobPlainMessages, bobEncryptedMessages := sendGroupMessages(1000, bobSendingCipher, serializer, t) 160 | 161 | // Build alice's side of the session. 162 | alice.groupBuilder.Process(bobSenderKeyName, aliceReceivedSkdm) 163 | receivingAliceCipher := groups.NewGroupCipher(alice.groupBuilder, bobSenderKeyName, alice.senderKeyStore) 164 | 165 | // Decrypt the messages sent by bob. 166 | logger.Debug("Alice receiving messages from Bob...") 167 | receiveGroupMessages(bobEncryptedMessages, bobPlainMessages, receivingAliceCipher, t) 168 | } 169 | 170 | // sendGroupMessages will generate and return a list of plaintext and encrypted messages. 171 | func sendGroupMessages(count int, cipher *groups.GroupCipher, serializer *serialize.Serializer, t *testing.T) ([]string, []protocol.CiphertextMessage) { 172 | texts := []string{ 173 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", 174 | "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.", 175 | "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", 176 | "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", 177 | } 178 | messageStrings := make([]string, count) 179 | for i := 0; i < count; i++ { 180 | messageStrings[i] = texts[i%len(texts)] 181 | } 182 | 183 | messages := make([]protocol.CiphertextMessage, count) 184 | for i, str := range messageStrings { 185 | msg := encryptGroupMessage(str, cipher, serializer, t) 186 | messages[i] = msg 187 | } 188 | 189 | return messageStrings, messages 190 | } 191 | 192 | // receiveMessages is a helper function to receive a bunch of encrypted messages and decrypt them. 193 | func receiveGroupMessages(messages []protocol.CiphertextMessage, messageStrings []string, cipher *groups.GroupCipher, t *testing.T) { 194 | for i, receivedMessage := range messages { 195 | msg := decryptGroupMessage(receivedMessage, cipher, t) 196 | if messageStrings[i] != msg { 197 | logger.Error("Decrypted message does not match original: ", messageStrings[i], " != ", msg) 198 | t.FailNow() 199 | } 200 | } 201 | } 202 | 203 | // encryptMessage is a helper function to send encrypted messages with the given cipher. 204 | func encryptGroupMessage(message string, cipher *groups.GroupCipher, serializer *serialize.Serializer, t *testing.T) protocol.CiphertextMessage { 205 | plaintextMessage := []byte(message) 206 | logger.Info("Encrypting message: ", string(plaintextMessage)) 207 | encrypted, err := cipher.Encrypt(plaintextMessage) 208 | if err != nil { 209 | logger.Error("Unable to encrypt message: ", err) 210 | t.FailNow() 211 | } 212 | logger.Info("Encrypted message: ", encrypted) 213 | 214 | // Emulate receiving the message as JSON over the network. 215 | logger.Debug("Building message from bytes to emulate sending over the network.") 216 | var encryptedMessage protocol.CiphertextMessage 217 | switch encrypted.(type) { 218 | case *protocol.SenderKeyMessage: 219 | message := encrypted.(*protocol.SenderKeyMessage) 220 | encryptedMessage, err = protocol.NewSenderKeyMessageFromBytes(message.SignedSerialize(), serializer.SenderKeyMessage) 221 | if err != nil { 222 | logger.Error("Unable to emulate receiving message as JSON: ", err) 223 | t.FailNow() 224 | } 225 | } 226 | logger.Info(encryptedMessage) 227 | 228 | return encryptedMessage 229 | } 230 | 231 | // decryptMessage is a helper function to decrypt messages of a session. 232 | func decryptGroupMessage(message protocol.CiphertextMessage, cipher *groups.GroupCipher, t *testing.T) string { 233 | senderKeyMessage := message.(*protocol.SenderKeyMessage) 234 | //if !ok { 235 | // logger.Error("Wrong message type in decrypting group message.") 236 | // t.FailNow() 237 | //} 238 | 239 | msg, err := cipher.Decrypt(senderKeyMessage) 240 | if err != nil { 241 | logger.Error("Unable to decrypt message: ", err) 242 | t.FailNow() 243 | } 244 | logger.Info("Decrypted message: ", string(msg)) 245 | 246 | return string(msg) 247 | } 248 | -------------------------------------------------------------------------------- /tests/identity_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "github.com/RadicalApp/complete" 5 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 6 | "github.com/RadicalApp/libsignal-protocol-go/logger" 7 | "github.com/RadicalApp/libsignal-protocol-go/util/keyhelper" 8 | "sync" 9 | "testing" 10 | ) 11 | 12 | // TestIdentityKeys checks generating, signing, and verifying of identity keys. 13 | func TestIdentityKeys(t *testing.T) { 14 | logger.Info("Testing identity key generation...") 15 | 16 | // Generate an identity keypair 17 | identityKeyPair, err := keyhelper.GenerateIdentityKeyPair() 18 | if err != nil { 19 | t.Error("Error generating identity keys") 20 | } 21 | privateKey := identityKeyPair.PrivateKey() 22 | publicKey := identityKeyPair.PublicKey() 23 | logger.Info(" Identity KeyPair:", identityKeyPair) 24 | 25 | // Sign the text "Hello" with the identity key 26 | message := []byte("Hello") 27 | unsignedMessage := []byte("SHIT!") 28 | logger.Info("Signing bytes:", message) 29 | signature := ecc.CalculateSignature(privateKey, message) 30 | logger.Info(" Signature:", signature) 31 | 32 | // Validate the signature using the private key 33 | //valid := ecc.Verify(publicKey.PublicKey().PublicKey(), message, &signature) 34 | logger.Info("Verifying signature against bytes:", message) 35 | valid := ecc.VerifySignature(publicKey.PublicKey(), message, signature) 36 | logger.Info(" Valid signature:", valid) 37 | if !(valid) { 38 | t.Error("Signature verification failed.") 39 | } 40 | 41 | // Try checking the signature on text that is different 42 | logger.Info("Verifying signature against unsigned bytes:", unsignedMessage) 43 | valid = ecc.VerifySignature(publicKey.PublicKey(), unsignedMessage, signature) 44 | logger.Info(" Valid signature:", valid) 45 | if valid { 46 | t.Error("Signature verification should have failed here.") 47 | } 48 | 49 | } 50 | 51 | // TestIdentityKeysAsync tries to test creation of identity keys in an async way. 52 | func TestIdentityKeysAsync(t *testing.T) { 53 | logger.Info("Testing async generation of identity keys...") 54 | 55 | // Create a waitgroup to wait for async tasks to finish for this test 56 | wg := sync.WaitGroup{} 57 | wg.Add(1) 58 | 59 | // Generate completion handlers for key generation. 60 | success := func(r *complete.Result) { 61 | logger.Info(r) 62 | wg.Done() 63 | } 64 | failure := func(err string) { 65 | logger.Error(err) 66 | wg.Done() 67 | } 68 | completion := complete.NewCompletion( 69 | success, 70 | failure, 71 | ) 72 | 73 | // Create identity keys asyncronously 74 | keyhelper.GenerateIdentityKeyPairAsync(completion) 75 | 76 | // Wait for wg to call "Done()" method. 77 | wg.Wait() 78 | 79 | } 80 | -------------------------------------------------------------------------------- /tests/prekey_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/logger" 5 | "github.com/RadicalApp/libsignal-protocol-go/serialize" 6 | "github.com/RadicalApp/libsignal-protocol-go/util/keyhelper" 7 | "testing" 8 | ) 9 | 10 | // TestPreKeys checks generating prekeys. 11 | func TestPreKeys(t *testing.T) { 12 | 13 | // Create a serializer object that will be used to encode/decode data. 14 | serializer := serialize.NewSerializer() 15 | serializer.SignalMessage = &serialize.JSONSignalMessageSerializer{} 16 | serializer.PreKeySignalMessage = &serialize.JSONPreKeySignalMessageSerializer{} 17 | serializer.SignedPreKeyRecord = &serialize.JSONSignedPreKeyRecordSerializer{} 18 | 19 | logger.Info("Testing prekey generation...") 20 | identityKeyPair, err := keyhelper.GenerateIdentityKeyPair() 21 | if err != nil { 22 | t.Error(err) 23 | } 24 | 25 | logger.Info("Generating prekeys") 26 | preKeys, _ := keyhelper.GeneratePreKeys(1, 100, serializer.PreKeyRecord) 27 | logger.Info("Generated PreKeys: ", preKeys) 28 | 29 | logger.Info("Generating Signed PreKey") 30 | signedPreKey, _ := keyhelper.GenerateSignedPreKey(identityKeyPair, 1, serializer.SignedPreKeyRecord) 31 | logger.Info("Signed PreKey: ", signedPreKey) 32 | } 33 | -------------------------------------------------------------------------------- /tests/registrationid_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "fmt" 5 | "github.com/RadicalApp/libsignal-protocol-go/util/keyhelper" 6 | "testing" 7 | ) 8 | 9 | func TestRegistrationID(t *testing.T) { 10 | regID := keyhelper.GenerateRegistrationID() 11 | fmt.Println(regID) 12 | } 13 | -------------------------------------------------------------------------------- /tests/saved_message_keys_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/keys/message" 5 | "github.com/RadicalApp/libsignal-protocol-go/keys/prekey" 6 | "github.com/RadicalApp/libsignal-protocol-go/logger" 7 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 8 | "github.com/RadicalApp/libsignal-protocol-go/session" 9 | "testing" 10 | ) 11 | 12 | // TestSavedMessageKeys tests the ability to save message keys for use in 13 | // decrypting messages in the future. 14 | func TestSavedMessageKeys(t *testing.T) { 15 | 16 | // Create a serializer object that will be used to encode/decode data. 17 | serializer := newSerializer() 18 | 19 | // Create our users who will talk to each other. 20 | alice := newUser("Alice", 1, serializer) 21 | bob := newUser("Bob", 2, serializer) 22 | 23 | // Create a session builder to create a session between Alice -> Bob. 24 | alice.buildSession(bob.address, serializer) 25 | bob.buildSession(alice.address, serializer) 26 | 27 | // Create a PreKeyBundle from Bob's prekey records and other 28 | // data. 29 | logger.Debug("Fetching Bob's prekey with ID: ", bob.preKeys[0].ID()) 30 | retrievedPreKey := prekey.NewBundle( 31 | bob.registrationID, 32 | bob.deviceID, 33 | bob.preKeys[0].ID(), 34 | bob.signedPreKey.ID(), 35 | bob.preKeys[0].KeyPair().PublicKey(), 36 | bob.signedPreKey.KeyPair().PublicKey(), 37 | bob.signedPreKey.Signature(), 38 | bob.identityKeyPair.PublicKey(), 39 | ) 40 | 41 | // Process Bob's retrieved prekey to establish a session. 42 | logger.Debug("Building sender's (Alice) session...") 43 | err := alice.sessionBuilder.ProcessBundle(retrievedPreKey) 44 | if err != nil { 45 | logger.Error("Unable to process retrieved prekey bundle") 46 | t.FailNow() 47 | } 48 | 49 | // Create a session cipher to encrypt messages to Bob. 50 | plaintextMessage := []byte("Hello!") 51 | logger.Info("Plaintext message: ", string(plaintextMessage)) 52 | sessionCipher := session.NewCipher(alice.sessionBuilder, bob.address) 53 | message, err := sessionCipher.Encrypt(plaintextMessage) 54 | if err != nil { 55 | logger.Error("Unable to encrypt message: ", err) 56 | t.FailNow() 57 | } 58 | 59 | logger.Info("Encrypted message: ", message) 60 | 61 | ///////////// RECEIVER SESSION CREATION /////////////// 62 | 63 | // Emulate receiving the message as JSON over the network. 64 | logger.Debug("Building message from bytes on Bob's end.") 65 | receivedMessage, err := protocol.NewPreKeySignalMessageFromBytes(message.Serialize(), serializer.PreKeySignalMessage, serializer.SignalMessage) 66 | if err != nil { 67 | logger.Error("Unable to emulate receiving message as JSON: ", err) 68 | t.FailNow() 69 | } 70 | 71 | // Create a session builder 72 | logger.Debug("Building receiver's (Bob) session...") 73 | unsignedPreKeyID, err := bob.sessionBuilder.Process(receivedMessage) 74 | if err != nil { 75 | logger.Error("Unable to process prekeysignal message: ", err) 76 | t.FailNow() 77 | } 78 | logger.Debug("Got PreKeyID: ", unsignedPreKeyID) 79 | 80 | // Try and decrypt the message and get the message key. 81 | bobSessionCipher := session.NewCipher(bob.sessionBuilder, alice.address) 82 | msg, key, err := bobSessionCipher.DecryptAndGetKey(receivedMessage.WhisperMessage()) 83 | if err != nil { 84 | logger.Error("Unable to decrypt message: ", err) 85 | t.FailNow() 86 | } 87 | logger.Info("Decrypted message: ", string(msg)) 88 | if string(msg) != string(plaintextMessage) { 89 | logger.Error("Decrypted string does not match - Encrypted: ", string(plaintextMessage), " Decrypted: ", string(msg)) 90 | t.FailNow() 91 | } 92 | 93 | // Try using the message key to decrypt the message again. 94 | logger.Info("Testing using saved message key to decrypt again.") 95 | for i := 0; i < 10; i++ { 96 | testDecryptingWithKey(bobSessionCipher, receivedMessage.WhisperMessage(), key, plaintextMessage, t) 97 | } 98 | } 99 | 100 | func testDecryptingWithKey(cipher *session.Cipher, receivedMessage *protocol.SignalMessage, key *message.Keys, plaintextMessage []byte, t *testing.T) { 101 | msg, err := cipher.DecryptWithKey(receivedMessage, key) 102 | if err != nil { 103 | t.FailNow() 104 | } 105 | logger.Info("Decrypted message: ", string(msg)) 106 | if string(msg) != string(plaintextMessage) { 107 | logger.Error("Decrypted string does not match - Encrypted: ", string(plaintextMessage), " Decrypted: ", string(msg)) 108 | t.FailNow() 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /tests/serializer.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/serialize" 5 | ) 6 | 7 | // newSerializer will return a JSON serializer for testing. 8 | func newSerializer() *serialize.Serializer { 9 | serializer := serialize.NewJSONSerializer() 10 | 11 | return serializer 12 | } 13 | -------------------------------------------------------------------------------- /tests/serializer_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "fmt" 5 | "github.com/RadicalApp/libsignal-protocol-go/keys/prekey" 6 | "github.com/RadicalApp/libsignal-protocol-go/logger" 7 | "github.com/RadicalApp/libsignal-protocol-go/session" 8 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 9 | "github.com/kr/pretty" 10 | "testing" 11 | ) 12 | 13 | // TestSerializing tests serialization and deserialization of Signal objects. 14 | func TestSerializing(t *testing.T) { 15 | 16 | // Create a serializer object that will be used to encode/decode data. 17 | serializer := newSerializer() 18 | 19 | // Create our users who will talk to each other. 20 | alice := newUser("Alice", 1, serializer) 21 | bob := newUser("Bob", 2, serializer) 22 | 23 | // Create a session builder to create a session between Alice -> Bob. 24 | alice.buildSession(bob.address, serializer) 25 | bob.buildSession(alice.address, serializer) 26 | 27 | // Create a PreKeyBundle from Bob's prekey records and other 28 | // data. 29 | retrivedPreKey := prekey.NewBundle( 30 | bob.registrationID, 31 | bob.deviceID, 32 | bob.preKeys[0].ID(), 33 | bob.signedPreKey.ID(), 34 | bob.preKeys[0].KeyPair().PublicKey(), 35 | bob.signedPreKey.KeyPair().PublicKey(), 36 | bob.signedPreKey.Signature(), 37 | bob.identityKeyPair.PublicKey(), 38 | ) 39 | 40 | // Process Bob's retrieved prekey to establish a session. 41 | alice.sessionBuilder.ProcessBundle(retrivedPreKey) 42 | 43 | // Create a session cipher to encrypt messages to Bob. 44 | plaintextMessage := []byte("Hello!") 45 | sessionCipher := session.NewCipher(alice.sessionBuilder, bob.address) 46 | sessionCipher.Encrypt(plaintextMessage) 47 | 48 | // Serialize our session so it can be stored. 49 | loadedSession := alice.sessionStore.LoadSession(bob.address) 50 | serializedSession := loadedSession.Serialize() 51 | logger.Debug(string(serializedSession)) 52 | 53 | // Try deserializing our session back into an object. 54 | deserializedSession, err := record.NewSessionFromBytes(serializedSession, serializer.Session, serializer.State) 55 | if err != nil { 56 | logger.Error("Failed to deserialize session.") 57 | t.FailNow() 58 | } 59 | 60 | fmt.Printf("Original Session Record: %# v\n", pretty.Formatter(loadedSession)) 61 | fmt.Printf("Deserialized Session Record: %# v\n", pretty.Formatter(deserializedSession)) 62 | 63 | } 64 | -------------------------------------------------------------------------------- /tests/sharedsecret_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "encoding/base64" 5 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 6 | "github.com/RadicalApp/libsignal-protocol-go/kdf" 7 | "github.com/RadicalApp/libsignal-protocol-go/logger" 8 | "testing" 9 | ) 10 | 11 | // TestSharedSecret tests the key derivation function's ability to 12 | // calculate a shared secret given two pairs of ECDH keys. 13 | func TestSharedSecret(t *testing.T) { 14 | logger.Configure("sharedsecret_test.go") 15 | logger.Info("Testing identity key generation...") 16 | b64 := base64.StdEncoding.EncodeToString 17 | 18 | // Generate an keypair for Alice 19 | aliceKeyPair, err := ecc.GenerateKeyPair() 20 | if err != nil { 21 | t.Error("Error generating identity keys") 22 | } 23 | alicePrivateKey := aliceKeyPair.PrivateKey().Serialize() 24 | p := aliceKeyPair.PublicKey() 25 | alicePublicKey := p.PublicKey() 26 | logger.Info(" Alice PrivateKey: ", b64(alicePrivateKey[:])) 27 | logger.Info(" Alice PublicKey: ", b64(alicePublicKey[:])) 28 | 29 | // Generate an keypair for Bob 30 | bobKeyPair, err := ecc.GenerateKeyPair() 31 | if err != nil { 32 | t.Error("Error generating identity keys") 33 | } 34 | bobPrivateKey := bobKeyPair.PrivateKey().Serialize() 35 | p = bobKeyPair.PublicKey() 36 | bobPublicKey := p.PublicKey() 37 | logger.Info(" Bob PrivateKey: ", b64(bobPrivateKey[:])) 38 | logger.Info(" Bob PublicKey: ", b64(bobPublicKey[:])) 39 | 40 | // Calculate the shared secret as Alice. 41 | aliceSharedSecret := kdf.CalculateSharedSecret(bobPublicKey, alicePrivateKey) 42 | aliceHashedSecret, _ := kdf.DeriveSecrets(aliceSharedSecret[:], nil, []byte("Dust"), 64) 43 | logger.Info("Alice Shared Secret: ", b64(aliceSharedSecret[:])) 44 | logger.Info("Alice Hashed Secret: ", b64(aliceHashedSecret)) 45 | 46 | // Calculate the shared secret as Bob. 47 | bobSharedSecret := kdf.CalculateSharedSecret(alicePublicKey, bobPrivateKey) 48 | bobHashedSecret, _ := kdf.DeriveSecrets(bobSharedSecret[:], nil, []byte("Dust"), 64) 49 | logger.Info("Bob Shared Secret: ", b64(bobSharedSecret[:])) 50 | logger.Info("Bob Hashed Secret: ", b64(bobHashedSecret)) 51 | 52 | // Check to make sure Alice and Bob calculated the same shared secret. 53 | if b64(aliceSharedSecret[:]) != b64(bobSharedSecret[:]) { 54 | logger.Error("Computed secrets do not match: ", b64(aliceSharedSecret[:]), " != ", b64(bobSharedSecret[:])) 55 | t.Fail() 56 | } 57 | 58 | // Check to make sure that Alice and Bob also hashed the same secret the same way using KDF. 59 | if b64(aliceHashedSecret) != b64(bobHashedSecret) { 60 | logger.Error("Hashed secrets do not match: ", b64(aliceHashedSecret), " != ", b64(bobHashedSecret)) 61 | t.Fail() 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/stores.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | groupRecord "github.com/RadicalApp/libsignal-protocol-go/groups/state/record" 5 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 6 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 7 | "github.com/RadicalApp/libsignal-protocol-go/serialize" 8 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 9 | ) 10 | 11 | // Define some in-memory stores for testing. 12 | 13 | // IdentityKeyStore 14 | func NewInMemoryIdentityKey(identityKey *identity.KeyPair, localRegistrationID uint32) *InMemoryIdentityKey { 15 | return &InMemoryIdentityKey{ 16 | trustedKeys: make(map[*protocol.SignalAddress]*identity.Key), 17 | identityKeyPair: identityKey, 18 | localRegistrationID: localRegistrationID, 19 | } 20 | } 21 | 22 | type InMemoryIdentityKey struct { 23 | trustedKeys map[*protocol.SignalAddress]*identity.Key 24 | identityKeyPair *identity.KeyPair 25 | localRegistrationID uint32 26 | } 27 | 28 | func (i *InMemoryIdentityKey) GetIdentityKeyPair() *identity.KeyPair { 29 | return i.identityKeyPair 30 | } 31 | 32 | func (i *InMemoryIdentityKey) GetLocalRegistrationId() uint32 { 33 | return i.localRegistrationID 34 | } 35 | 36 | func (i *InMemoryIdentityKey) SaveIdentity(address *protocol.SignalAddress, identityKey *identity.Key) { 37 | i.trustedKeys[address] = identityKey 38 | } 39 | 40 | func (i *InMemoryIdentityKey) IsTrustedIdentity(address *protocol.SignalAddress, identityKey *identity.Key) bool { 41 | trusted := i.trustedKeys[address] 42 | return (trusted == nil || trusted.Fingerprint() == identityKey.Fingerprint()) 43 | } 44 | 45 | // PreKeyStore 46 | func NewInMemoryPreKey() *InMemoryPreKey { 47 | return &InMemoryPreKey{ 48 | store: make(map[uint32]*record.PreKey), 49 | } 50 | } 51 | 52 | type InMemoryPreKey struct { 53 | store map[uint32]*record.PreKey 54 | } 55 | 56 | func (i *InMemoryPreKey) LoadPreKey(preKeyID uint32) *record.PreKey { 57 | return i.store[preKeyID] 58 | } 59 | 60 | func (i *InMemoryPreKey) StorePreKey(preKeyID uint32, preKeyRecord *record.PreKey) { 61 | i.store[preKeyID] = preKeyRecord 62 | } 63 | 64 | func (i *InMemoryPreKey) ContainsPreKey(preKeyID uint32) bool { 65 | _, ok := i.store[preKeyID] 66 | return ok 67 | } 68 | 69 | func (i *InMemoryPreKey) RemovePreKey(preKeyID uint32) { 70 | delete(i.store, preKeyID) 71 | } 72 | 73 | // SessionStore 74 | func NewInMemorySession(serializer *serialize.Serializer) *InMemorySession { 75 | return &InMemorySession{ 76 | sessions: make(map[*protocol.SignalAddress]*record.Session), 77 | serializer: serializer, 78 | } 79 | } 80 | 81 | type InMemorySession struct { 82 | sessions map[*protocol.SignalAddress]*record.Session 83 | serializer *serialize.Serializer 84 | } 85 | 86 | func (i *InMemorySession) LoadSession(address *protocol.SignalAddress) *record.Session { 87 | if i.ContainsSession(address) { 88 | return i.sessions[address] 89 | } 90 | sessionRecord := record.NewSession(i.serializer.Session, i.serializer.State) 91 | i.sessions[address] = sessionRecord 92 | 93 | return sessionRecord 94 | } 95 | 96 | func (i *InMemorySession) GetSubDeviceSessions(name string) []uint32 { 97 | var deviceIDs []uint32 98 | 99 | for key := range i.sessions { 100 | if key.Name() == name && key.DeviceID() != 1 { 101 | deviceIDs = append(deviceIDs, key.DeviceID()) 102 | } 103 | } 104 | 105 | return deviceIDs 106 | } 107 | 108 | func (i *InMemorySession) StoreSession(remoteAddress *protocol.SignalAddress, record *record.Session) { 109 | i.sessions[remoteAddress] = record 110 | } 111 | 112 | func (i *InMemorySession) ContainsSession(remoteAddress *protocol.SignalAddress) bool { 113 | _, ok := i.sessions[remoteAddress] 114 | return ok 115 | } 116 | 117 | func (i *InMemorySession) DeleteSession(remoteAddress *protocol.SignalAddress) { 118 | delete(i.sessions, remoteAddress) 119 | } 120 | 121 | func (i *InMemorySession) DeleteAllSessions() { 122 | i.sessions = make(map[*protocol.SignalAddress]*record.Session) 123 | } 124 | 125 | // SignedPreKeyStore 126 | func NewInMemorySignedPreKey() *InMemorySignedPreKey { 127 | return &InMemorySignedPreKey{ 128 | store: make(map[uint32]*record.SignedPreKey), 129 | } 130 | } 131 | 132 | type InMemorySignedPreKey struct { 133 | store map[uint32]*record.SignedPreKey 134 | } 135 | 136 | func (i *InMemorySignedPreKey) LoadSignedPreKey(signedPreKeyID uint32) *record.SignedPreKey { 137 | return i.store[signedPreKeyID] 138 | } 139 | 140 | func (i *InMemorySignedPreKey) LoadSignedPreKeys() []*record.SignedPreKey { 141 | var preKeys []*record.SignedPreKey 142 | 143 | for _, record := range i.store { 144 | preKeys = append(preKeys, record) 145 | } 146 | 147 | return preKeys 148 | } 149 | 150 | func (i *InMemorySignedPreKey) StoreSignedPreKey(signedPreKeyID uint32, record *record.SignedPreKey) { 151 | i.store[signedPreKeyID] = record 152 | } 153 | 154 | func (i *InMemorySignedPreKey) ContainsSignedPreKey(signedPreKeyID uint32) bool { 155 | _, ok := i.store[signedPreKeyID] 156 | return ok 157 | } 158 | 159 | func (i *InMemorySignedPreKey) RemoveSignedPreKey(signedPreKeyID uint32) { 160 | delete(i.store, signedPreKeyID) 161 | } 162 | 163 | func NewInMemorySenderKey() *InMemorySenderKey { 164 | return &InMemorySenderKey{ 165 | store: make(map[*protocol.SenderKeyName]*groupRecord.SenderKey), 166 | } 167 | } 168 | 169 | type InMemorySenderKey struct { 170 | store map[*protocol.SenderKeyName]*groupRecord.SenderKey 171 | } 172 | 173 | func (i *InMemorySenderKey) StoreSenderKey(senderKeyName *protocol.SenderKeyName, keyRecord *groupRecord.SenderKey) { 174 | i.store[senderKeyName] = keyRecord 175 | } 176 | 177 | func (i *InMemorySenderKey) LoadSenderKey(senderKeyName *protocol.SenderKeyName) *groupRecord.SenderKey { 178 | return i.store[senderKeyName] 179 | } 180 | -------------------------------------------------------------------------------- /tests/user.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "github.com/RadicalApp/libsignal-protocol-go/groups" 5 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 6 | "github.com/RadicalApp/libsignal-protocol-go/protocol" 7 | "github.com/RadicalApp/libsignal-protocol-go/serialize" 8 | "github.com/RadicalApp/libsignal-protocol-go/session" 9 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 10 | "github.com/RadicalApp/libsignal-protocol-go/util/keyhelper" 11 | ) 12 | 13 | // user is a structure for a signal user. 14 | type user struct { 15 | name string 16 | deviceID uint32 17 | address *protocol.SignalAddress 18 | 19 | identityKeyPair *identity.KeyPair 20 | registrationID uint32 21 | 22 | preKeys []*record.PreKey 23 | signedPreKey *record.SignedPreKey 24 | 25 | sessionStore *InMemorySession 26 | preKeyStore *InMemoryPreKey 27 | signedPreKeyStore *InMemorySignedPreKey 28 | identityStore *InMemoryIdentityKey 29 | senderKeyStore *InMemorySenderKey 30 | 31 | sessionBuilder *session.Builder 32 | groupBuilder *groups.SessionBuilder 33 | } 34 | 35 | // buildSession will build a session with the given address. 36 | func (u *user) buildSession(address *protocol.SignalAddress, serializer *serialize.Serializer) { 37 | u.sessionBuilder = session.NewBuilder( 38 | u.sessionStore, 39 | u.preKeyStore, 40 | u.signedPreKeyStore, 41 | u.identityStore, 42 | address, 43 | serializer, 44 | ) 45 | } 46 | 47 | // buildGroupSession will build a group session using sender keys. 48 | func (u *user) buildGroupSession(serializer *serialize.Serializer) { 49 | u.groupBuilder = groups.NewGroupSessionBuilder(u.senderKeyStore, serializer) 50 | } 51 | 52 | // newUser creates a new signal user for session testing. 53 | func newUser(name string, deviceID uint32, serializer *serialize.Serializer) *user { 54 | signalUser := &user{} 55 | 56 | // Generate an identity keypair 57 | signalUser.identityKeyPair, _ = keyhelper.GenerateIdentityKeyPair() 58 | 59 | // Generate a registration id 60 | signalUser.registrationID = keyhelper.GenerateRegistrationID() 61 | 62 | // Generate PreKeys 63 | signalUser.preKeys, _ = keyhelper.GeneratePreKeys(0, 100, serializer.PreKeyRecord) 64 | 65 | // Generate Signed PreKey 66 | signalUser.signedPreKey, _ = keyhelper.GenerateSignedPreKey(signalUser.identityKeyPair, 0, serializer.SignedPreKeyRecord) 67 | 68 | // Create all our record stores using an in-memory implementation. 69 | signalUser.sessionStore = NewInMemorySession(serializer) 70 | signalUser.preKeyStore = NewInMemoryPreKey() 71 | signalUser.signedPreKeyStore = NewInMemorySignedPreKey() 72 | signalUser.identityStore = NewInMemoryIdentityKey(signalUser.identityKeyPair, signalUser.registrationID) 73 | signalUser.senderKeyStore = NewInMemorySenderKey() 74 | 75 | // Put all our pre keys in our local stores. 76 | for i := range signalUser.preKeys { 77 | signalUser.preKeyStore.StorePreKey( 78 | signalUser.preKeys[i].ID().Value, 79 | record.NewPreKey(signalUser.preKeys[i].ID().Value, signalUser.preKeys[i].KeyPair(), serializer.PreKeyRecord), 80 | ) 81 | } 82 | 83 | // Store our's own signed prekey 84 | signalUser.signedPreKeyStore.StoreSignedPreKey( 85 | signalUser.signedPreKey.ID(), 86 | record.NewSignedPreKey( 87 | signalUser.signedPreKey.ID(), 88 | signalUser.signedPreKey.Timestamp(), 89 | signalUser.signedPreKey.KeyPair(), 90 | signalUser.signedPreKey.Signature(), 91 | serializer.SignedPreKeyRecord, 92 | ), 93 | ) 94 | 95 | // Create a remote address that we'll be building our session with. 96 | signalUser.name = name 97 | signalUser.deviceID = deviceID 98 | signalUser.address = protocol.NewSignalAddress(name, deviceID) 99 | 100 | // Create a group session builder 101 | signalUser.buildGroupSession(serializer) 102 | 103 | return signalUser 104 | } 105 | -------------------------------------------------------------------------------- /util/bytehelper/ByteHelper.go: -------------------------------------------------------------------------------- 1 | package bytehelper 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // SliceToArray will convert byte slice to a 32 byte array 8 | func SliceToArray(bytes []byte) [32]byte { 9 | var byteArray [32]byte 10 | copy(byteArray[:], bytes) 11 | return byteArray 12 | } 13 | 14 | // SliceToArray64 will convert byte slice to a 64 byte array 15 | func SliceToArray64(bytes []byte) [64]byte { 16 | var byteArray [64]byte 17 | copy(byteArray[:], bytes) 18 | return byteArray 19 | } 20 | 21 | // ArrayToSlice will convert a 32 byte array to byte slice 22 | func ArrayToSlice(bytes [32]byte) []byte { 23 | return bytes[:] 24 | } 25 | 26 | // ArrayToSlice64 will convert a 64 byte array to byte slice 27 | func ArrayToSlice64(bytes [64]byte) []byte { 28 | return bytes[:] 29 | } 30 | 31 | // Split will take the given byte array and split it into half, 32 | // with the first half being "firstLength" in size and the second 33 | // half "secondLength" in size. 34 | func Split(input []byte, firstLength, secondLength int) [][]byte { 35 | parts := make([][]byte, 2) 36 | 37 | parts[0] = make([]byte, firstLength) 38 | copy(parts[0], input[:firstLength]) 39 | 40 | parts[1] = make([]byte, secondLength) 41 | copy(parts[1], input[firstLength:]) 42 | 43 | return parts 44 | } 45 | 46 | // SplitThree will take the given byte array and split it into thirds, 47 | // with the first third being "firstLength" in size, the second third 48 | // being "secondLength" in size, and the last third being "thirdLength" 49 | // in size. 50 | func SplitThree(input []byte, firstLength, secondLength, thirdLength int) ([][]byte, error) { 51 | if input == nil || firstLength < 0 || secondLength < 0 || thirdLength < 0 || 52 | len(input) < firstLength+secondLength+thirdLength { 53 | 54 | return nil, errors.New("Input too small: " + string(input)) 55 | } 56 | 57 | parts := make([][]byte, 3) 58 | 59 | parts[0] = make([]byte, firstLength) 60 | copy(parts[0], input[:firstLength]) 61 | 62 | parts[1] = make([]byte, secondLength) 63 | copy(parts[1], input[firstLength:][:secondLength]) 64 | 65 | parts[2] = make([]byte, thirdLength) 66 | copy(parts[2], input[firstLength+secondLength:]) 67 | 68 | return parts, nil 69 | } 70 | 71 | // Trim will trim the given byte array to the given length. 72 | func Trim(input []byte, length int) []byte { 73 | result := make([]byte, length) 74 | copy(result, input[:length]) 75 | 76 | return result 77 | } 78 | 79 | // Bytes5ToInt64 will convert the given byte array and offset to an int64. 80 | func Bytes5ToInt64(bytes []byte, offset int) int64 { 81 | 82 | value := (int64(bytes[offset]&0xff) << 32) | 83 | (int64(bytes[offset+1]&0xff) << 24) | 84 | (int64(bytes[offset+2]&0xff) << 16) | 85 | (int64(bytes[offset+3]&0xff) << 8) | 86 | int64(bytes[offset+4]&0xff) 87 | 88 | return value 89 | } 90 | 91 | // CopySlice returns a copy of the given bytes. 92 | func CopySlice(bytes []byte) []byte { 93 | cp := make([]byte, len(bytes)) 94 | copy(cp, bytes) 95 | 96 | return cp 97 | } 98 | -------------------------------------------------------------------------------- /util/errorhelper/ErrorHelper.go: -------------------------------------------------------------------------------- 1 | package errorhelper 2 | 3 | // NewMultiError returns a new MultiError object. 4 | func NewMultiError() *MultiError { 5 | return &MultiError{ 6 | errors: []error{}, 7 | } 8 | } 9 | 10 | // MultiError is a structure for holding multiple errors so they 11 | // can be checked at a later point. 12 | type MultiError struct { 13 | errors []error 14 | } 15 | 16 | // Add will add the given error if it is not nil. 17 | func (m *MultiError) Add(err error) { 18 | if err != nil { 19 | m.errors = append(m.errors, err) 20 | } 21 | } 22 | 23 | // HasErrors will return true if any non-nil errors have been 24 | // added. 25 | func (m *MultiError) HasErrors() bool { 26 | if len(m.errors) > 0 { 27 | return true 28 | } 29 | 30 | return false 31 | } 32 | 33 | // Error will print the first error is encountered. 34 | func (m *MultiError) Error() string { 35 | if !m.HasErrors() { 36 | return "" 37 | } 38 | 39 | return m.errors[0].Error() 40 | } 41 | -------------------------------------------------------------------------------- /util/keyhelper/KeyHelper.go: -------------------------------------------------------------------------------- 1 | // Package keyhelper is based on: https://github.com/WhisperSystems/libsignal-protocol-java/blob/master/java/src/main/java/org/whispersystems/libsignal/util/KeyHelper.java 2 | package keyhelper 3 | 4 | import ( 5 | "crypto/rand" 6 | "encoding/binary" 7 | "github.com/RadicalApp/complete" 8 | "github.com/RadicalApp/libsignal-protocol-go/ecc" 9 | "github.com/RadicalApp/libsignal-protocol-go/keys/identity" 10 | "github.com/RadicalApp/libsignal-protocol-go/state/record" 11 | "time" 12 | ) 13 | 14 | // GenerateIdentityKeyPair generates an identity keypair used for 15 | // signing. Clients should only do this once at install time. 16 | func GenerateIdentityKeyPair() (*identity.KeyPair, error) { 17 | keyPair, err := ecc.GenerateKeyPair() 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | publicKey := identity.NewKey(keyPair.PublicKey()) 23 | return identity.NewKeyPair(publicKey, keyPair.PrivateKey()), nil 24 | } 25 | 26 | // GenerateIdentityKeyPairAsync generates an identity keypair asyncronously. 27 | func GenerateIdentityKeyPairAsync(completion complete.Completionable) { 28 | go func() { 29 | r, err := GenerateIdentityKeyPair() 30 | if err != nil { 31 | completion.OnFailure(err.Error()) 32 | return 33 | } 34 | result := complete.NewResult(r) 35 | completion.OnSuccess(&result) 36 | }() 37 | } 38 | 39 | // GeneratePreKeys generates a list of PreKeys. Client shsould do this at 40 | // install time, and subsequently any time the list of PreKeys stored on 41 | // the server runs low. 42 | // 43 | // PreKeys IDs are shorts, so they will eventually be repeated. Clients 44 | // should store PreKeys in a circular buffer, so that they are repeated 45 | // as infrequently as possible. 46 | func GeneratePreKeys(start int, count int, serializer record.PreKeySerializer) ([]*record.PreKey, error) { 47 | var preKeys []*record.PreKey 48 | 49 | start-- 50 | 51 | for i := 0; i < count; i++ { 52 | key, err := ecc.GenerateKeyPair() 53 | if err != nil { 54 | return nil, err 55 | } 56 | preKeys = append(preKeys, record.NewPreKey(uint32(i), key, serializer)) 57 | } 58 | 59 | return preKeys, nil 60 | } 61 | 62 | // GenerateLastResortKey will generate the last resort PreKey. Clients should 63 | // do this only once, at install time, and durably store it for the length 64 | // of the install. 65 | func GenerateLastResortKey(serializer record.PreKeySerializer) (*record.PreKey, error) { 66 | keyPair, err := ecc.GenerateKeyPair() 67 | if err != nil { 68 | return nil, err 69 | } 70 | return record.NewPreKey(0, keyPair, serializer), nil 71 | } 72 | 73 | // GenerateSignedPreKey generates a signed PreKey. 74 | func GenerateSignedPreKey(identityKeyPair *identity.KeyPair, signedPreKeyID uint32, serializer record.SignedPreKeySerializer) (*record.SignedPreKey, error) { 75 | keyPair, err := ecc.GenerateKeyPair() 76 | if err != nil { 77 | return nil, err 78 | } 79 | signature := ecc.CalculateSignature(identityKeyPair.PrivateKey(), keyPair.PublicKey().Serialize()) 80 | timestamp := time.Now().Unix() 81 | 82 | return record.NewSignedPreKey(signedPreKeyID, timestamp, keyPair, signature, serializer), nil 83 | } 84 | 85 | // GenerateRegistrationID generates a registration ID. Clients should only do 86 | // this once, at install time. 87 | func GenerateRegistrationID() uint32 { 88 | var n uint32 89 | binary.Read(rand.Reader, binary.LittleEndian, &n) 90 | 91 | return n 92 | } 93 | 94 | //---------- Group Stuff ---------------- 95 | 96 | func GenerateSenderSigningKey() (*ecc.ECKeyPair, error) { 97 | return ecc.GenerateKeyPair() 98 | } 99 | 100 | func GenerateSenderKey() []byte { 101 | randBytes := make([]byte, 32) 102 | rand.Read(randBytes) 103 | return randBytes 104 | } 105 | 106 | func GenerateSenderKeyID() uint32 { 107 | return GenerateRegistrationID() 108 | } 109 | 110 | //---------- End Group Stuff -------------- 111 | -------------------------------------------------------------------------------- /util/medium/Medium.go: -------------------------------------------------------------------------------- 1 | package medium 2 | 3 | // MaxValue is the maximum possible integer value. 4 | const MaxValue uint32 = 0xFFFFFF 5 | -------------------------------------------------------------------------------- /util/optional/Integer.go: -------------------------------------------------------------------------------- 1 | package optional 2 | 3 | // NewOptionalUint32 returns an optional Uint32 structure. 4 | func NewOptionalUint32(value uint32) *Uint32 { 5 | return &Uint32{Value: value, IsEmpty: false} 6 | } 7 | 8 | func NewEmptyUint32() *Uint32{ 9 | return &Uint32{IsEmpty: true} 10 | } 11 | 12 | // Uint32 is a simple structure for Uint32 values that can 13 | // optionally be nil. 14 | type Uint32 struct { 15 | Value uint32 16 | IsEmpty bool 17 | } 18 | --------------------------------------------------------------------------------