├── .github └── dependabot.yml ├── .gitignore ├── CREDITS.md ├── LICENSE ├── README.md ├── cipher ├── Cbc.go └── 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 ├── go.mod ├── go.sum ├── 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 ├── main.go ├── mixin_signal_protocol_store.go ├── mixin_store.go ├── protocol ├── CiphertextMessage.go ├── Doc.go ├── PreKeySignalMessage.go ├── SenderKeyDistributionMessage.go ├── SenderKeyMessage.go ├── SenderKeyName.go ├── SignalMessage.go └── SignalProtocolAddress.go ├── provision └── ProvisioningCipher.go ├── ratchet ├── Ratchet.go ├── ReceiverParameters.go ├── SenderParameters.go └── SymmetricParameters.go ├── serialize ├── FingerprintProtocol.pb.go ├── JSONSerializer.go ├── LocalStorageProtocol.pb.go ├── ProtoBufferSerializer.go ├── Serializer.go └── WhisperTextProtocol.pb.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 /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.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/crossle/goquery?status.png)](https://godoc.org/github.com/crossle/libsignal-protocol-go) 2 | [![Go Report Card](https://goreportcard.com/badge/github.com/crossle/libsignal-protocol-go)](https://goreportcard.com/report/github.com/crossle/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/crossle/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/crossle/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/crossle/libsignal-protocol-go/serialize" 40 | "github.com/crossle/libsignal-protocol-go/session" 41 | "github.com/crossle/libsignal-protocol-go/state/record" 42 | "github.com/crossle/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/crossle/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/Cbc.go: -------------------------------------------------------------------------------- 1 | /* 2 | CBC describes a block cipher mode. In cryptography, a block cipher mode of operation is an algorithm that uses a 3 | block cipher to provide an information service such as confidentiality or authenticity. A block cipher by itself 4 | is only suitable for the secure cryptographic transformation (encryption or decryption) of one fixed-length group of 5 | bits called a block. A mode of operation describes how to repeatedly apply a cipher's single-block operation to 6 | securely transform amounts of data larger than a block. 7 | 8 | This package simplifies the usage of AES-256-CBC. 9 | */ 10 | package cipher 11 | 12 | /* 13 | Some code is provided by the GitHub user locked (github.com/locked): 14 | https://gist.github.com/locked/b066aa1ddeb2b28e855e 15 | Thanks! 16 | */ 17 | import ( 18 | "bytes" 19 | "crypto/aes" 20 | "crypto/cipher" 21 | "crypto/rand" 22 | "fmt" 23 | "io" 24 | ) 25 | 26 | /* 27 | Decrypt is a function that decrypts a given cipher text with a provided key and initialization vector(iv). 28 | */ 29 | func DecryptCbc(iv, key, ciphertext []byte) ([]byte, error) { 30 | block, err := aes.NewCipher(key) 31 | 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | if len(ciphertext) < aes.BlockSize { 37 | return nil, fmt.Errorf("ciphertext is shorter then block size: %d / %d", len(ciphertext), aes.BlockSize) 38 | } 39 | 40 | if iv == nil { 41 | iv = ciphertext[:aes.BlockSize] 42 | ciphertext = ciphertext[aes.BlockSize:] 43 | } 44 | 45 | cbc := cipher.NewCBCDecrypter(block, iv) 46 | cbc.CryptBlocks(ciphertext, ciphertext) 47 | 48 | return unpad(ciphertext) 49 | } 50 | 51 | /* 52 | Encrypt is a function that encrypts plaintext with a given key and an optional initialization vector(iv). 53 | */ 54 | func EncryptCbc(iv, key, plaintext []byte) ([]byte, error) { 55 | plaintext = pad(plaintext, aes.BlockSize) 56 | 57 | if len(plaintext)%aes.BlockSize != 0 { 58 | return nil, fmt.Errorf("plaintext is not a multiple of the block size: %d / %d", len(plaintext), aes.BlockSize) 59 | } 60 | 61 | block, err := aes.NewCipher(key) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | var ciphertext []byte 67 | if iv == nil { 68 | ciphertext = make([]byte, aes.BlockSize+len(plaintext)) 69 | iv := ciphertext[:aes.BlockSize] 70 | if _, err := io.ReadFull(rand.Reader, iv); err != nil { 71 | return nil, err 72 | } 73 | 74 | cbc := cipher.NewCBCEncrypter(block, iv) 75 | cbc.CryptBlocks(ciphertext[aes.BlockSize:], plaintext) 76 | } else { 77 | ciphertext = make([]byte, len(plaintext)) 78 | 79 | cbc := cipher.NewCBCEncrypter(block, iv) 80 | cbc.CryptBlocks(ciphertext, plaintext) 81 | } 82 | 83 | return ciphertext, nil 84 | } 85 | 86 | func pad(ciphertext []byte, blockSize int) []byte { 87 | padding := blockSize - len(ciphertext)%blockSize 88 | padtext := bytes.Repeat([]byte{byte(padding)}, padding) 89 | return append(ciphertext, padtext...) 90 | } 91 | 92 | func unpad(src []byte) ([]byte, error) { 93 | length := len(src) 94 | padLen := int(src[length-1]) 95 | 96 | if padLen > length { 97 | return nil, fmt.Errorf("padding is greater then the length: %d / %d", padLen, length) 98 | } 99 | 100 | return src[:(length - padLen)], nil 101 | } 102 | -------------------------------------------------------------------------------- /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 | "fmt" 7 | "io" 8 | 9 | "github.com/crossle/libsignal-protocol-go/logger" 10 | "golang.org/x/crypto/curve25519" 11 | ) 12 | 13 | // DjbType is the Diffie-Hellman curve type (curve25519) created by D. J. Bernstein. 14 | const DjbType = 0x05 15 | 16 | var ErrBadKeyType = errors.New("bad key type") 17 | 18 | // DecodePoint will take the given bytes and offset and return an ECPublicKeyable object. 19 | // This is used to check the byte at the given offset in the byte array for a special 20 | // "type" byte that will determine the key type. Currently only DJB EC keys are supported. 21 | func DecodePoint(bytes []byte, offset int) (ECPublicKeyable, error) { 22 | keyType := bytes[offset] & 0xFF 23 | 24 | switch keyType { 25 | case DjbType: 26 | keyBytes := [32]byte{} 27 | copy(keyBytes[:], bytes[offset+1:]) 28 | return NewDjbECPublicKey(keyBytes), nil 29 | default: 30 | return nil, fmt.Errorf("%w %d", ErrBadKeyType, keyType) 31 | } 32 | } 33 | 34 | func CreateKeyPair(privateKey []byte) *ECKeyPair { 35 | var private, public [32]byte 36 | copy(private[:], privateKey) 37 | 38 | private[0] &= 248 39 | private[31] &= 127 40 | private[31] |= 64 41 | 42 | curve25519.ScalarBaseMult(&public, &private) 43 | 44 | // Put data into our keypair struct 45 | djbECPub := NewDjbECPublicKey(public) 46 | djbECPriv := NewDjbECPrivateKey(private) 47 | keypair := NewECKeyPair(djbECPub, djbECPriv) 48 | 49 | logger.Debug("Returning keypair: ", keypair) 50 | return keypair 51 | } 52 | 53 | // GenerateKeyPair returns an EC Key Pair. 54 | func GenerateKeyPair() (*ECKeyPair, error) { 55 | // logger.Debug("Generating EC Key Pair...") 56 | // Get cryptographically secure random numbers. 57 | random := rand.Reader 58 | 59 | // Create a byte array for our public and private keys. 60 | var private, public [32]byte 61 | 62 | // Generate some random data 63 | _, err := io.ReadFull(random, private[:]) 64 | if err != nil { 65 | return nil, err 66 | } 67 | 68 | // Documented at: http://cr.yp.to/ecdh.html 69 | private[0] &= 248 70 | private[31] &= 127 71 | private[31] |= 64 72 | 73 | curve25519.ScalarBaseMult(&public, &private) 74 | 75 | // Put data into our keypair struct 76 | djbECPub := NewDjbECPublicKey(public) 77 | djbECPriv := NewDjbECPrivateKey(private) 78 | keypair := NewECKeyPair(djbECPub, djbECPriv) 79 | 80 | // logger.Debug("Returning keypair: ", keypair) 81 | 82 | return keypair, nil 83 | } 84 | 85 | // VerifySignature verifies that the message was signed with the given key. 86 | func VerifySignature(signingKey ECPublicKeyable, message []byte, signature [64]byte) bool { 87 | logger.Debug("Verifying signature of bytes: ", message) 88 | publicKey := signingKey.PublicKey() 89 | valid := verify(publicKey, message, &signature) 90 | logger.Debug("Signature valid: ", valid) 91 | return valid 92 | } 93 | 94 | // CalculateSignature signs a message with the given private key. 95 | func CalculateSignature(signingKey ECPrivateKeyable, message []byte) [64]byte { 96 | logger.Debug("Signing bytes with signing key") 97 | // Get cryptographically secure random numbers. 98 | var random [64]byte 99 | r := rand.Reader 100 | io.ReadFull(r, random[:]) 101 | 102 | // Get the private key. 103 | privateKey := signingKey.Serialize() 104 | 105 | // Sign the message. 106 | signature := sign(&privateKey, message, random) 107 | return *signature 108 | } 109 | -------------------------------------------------------------------------------- /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/ed25519" 8 | "crypto/sha512" 9 | 10 | "filippo.io/edwards25519" 11 | "filippo.io/edwards25519/field" 12 | ) 13 | 14 | // sign signs the message with privateKey and returns a signature as a byte slice. 15 | func sign(privateKey *[32]byte, message []byte, random [64]byte) *[64]byte { 16 | 17 | // Calculate Ed25519 public key from Curve25519 private key 18 | var A edwards25519.Point 19 | privateKeyScalar, _ := edwards25519.NewScalar().SetBytesWithClamping(privateKey[:]) 20 | A.ScalarBaseMult(privateKeyScalar) 21 | publicKey := *(*[32]byte)(A.Bytes()) 22 | 23 | // Calculate r 24 | diversifier := [32]byte{ 25 | 0xFE, 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 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} 29 | 30 | var r [64]byte 31 | hash := sha512.New() 32 | hash.Write(diversifier[:]) 33 | hash.Write(privateKey[:]) 34 | hash.Write(message) 35 | hash.Write(random[:]) 36 | hash.Sum(r[:0]) 37 | 38 | // Calculate R 39 | var rReduced *edwards25519.Scalar 40 | rReduced, _ = edwards25519.NewScalar().SetUniformBytes(r[:]) 41 | var R edwards25519.Point 42 | R.ScalarBaseMult(rReduced) 43 | 44 | var encodedR [32]byte 45 | encodedR = *(*[32]byte)(R.Bytes()) 46 | 47 | // Calculate S = r + SHA2-512(R || A_ed || msg) * a (mod L) 48 | var hramDigest [64]byte 49 | hash.Reset() 50 | hash.Write(encodedR[:]) 51 | hash.Write(publicKey[:]) 52 | hash.Write(message) 53 | hash.Sum(hramDigest[:0]) 54 | hramDigestReduced, _ := edwards25519.NewScalar().SetUniformBytes(hramDigest[:]) 55 | 56 | sScalar := edwards25519.NewScalar().MultiplyAdd(hramDigestReduced, privateKeyScalar, rReduced) 57 | s := *(*[32]byte)(sScalar.Bytes()) 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 | ed_y = (mont_x - 1) / (mont_x + 1) 76 | NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp 77 | Then move the sign bit into the pubkey from the signature. 78 | */ 79 | 80 | var edY, one, montX, montXMinusOne, montXPlusOne field.Element 81 | _, _ = montX.SetBytes(publicKey[:]) 82 | _ = one.One() 83 | montXMinusOne.Subtract(&montX, &one) 84 | montXPlusOne.Add(&montX, &one) 85 | montXPlusOne.Invert(&montXPlusOne) 86 | edY.Multiply(&montXMinusOne, &montXPlusOne) 87 | 88 | A_ed := *(*[32]byte)(edY.Bytes()) 89 | 90 | A_ed[31] |= signature[63] & 0x80 91 | signature[63] &= 0x7F 92 | 93 | return ed25519.Verify(A_ed[:], message, signature[:]) 94 | } 95 | -------------------------------------------------------------------------------- /fingerprint/DisplayFingerprint.go: -------------------------------------------------------------------------------- 1 | package fingerprint 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/crossle/libsignal-protocol-go/util/bytehelper" 7 | ) 8 | 9 | // NewDisplay will return a new displayable fingerprint. 10 | func NewDisplay(localFingerprint, remoteFingerprint []byte) *Display { 11 | return &Display{ 12 | localFingerprintNumbers: displayStringFor(localFingerprint), 13 | remoteFingerprintNumbers: displayStringFor(remoteFingerprint), 14 | } 15 | } 16 | 17 | // Display is a structure for displayable fingerprints. 18 | type Display struct { 19 | localFingerprintNumbers string 20 | remoteFingerprintNumbers string 21 | } 22 | 23 | // DisplayText will return a string of the fingerprint numbers. 24 | func (d *Display) DisplayText() string { 25 | if d.localFingerprintNumbers < d.remoteFingerprintNumbers { 26 | return d.localFingerprintNumbers + d.remoteFingerprintNumbers 27 | } 28 | return d.remoteFingerprintNumbers + d.localFingerprintNumbers 29 | } 30 | 31 | // displayStringFor will return a displayable string representation 32 | // of the given fingerprint. 33 | func displayStringFor(fingerprint []byte) string { 34 | return encodedChunk(fingerprint, 0) + 35 | encodedChunk(fingerprint, 5) + 36 | encodedChunk(fingerprint, 10) + 37 | encodedChunk(fingerprint, 15) + 38 | encodedChunk(fingerprint, 20) + 39 | encodedChunk(fingerprint, 25) 40 | } 41 | 42 | // encodedChunk will return an encoded string of the given hash. 43 | func encodedChunk(hash []byte, offset int) string { 44 | chunk := bytehelper.Bytes5ToInt64(hash, offset) % 100000 45 | return fmt.Sprintf("%05d", chunk) 46 | } 47 | -------------------------------------------------------------------------------- /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/crossle/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 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/crossle/libsignal-protocol-go 2 | 3 | go 1.17 4 | 5 | require ( 6 | filippo.io/edwards25519 v1.1.0 7 | github.com/golang/protobuf v1.5.4 8 | github.com/kr/pretty v0.3.1 9 | golang.org/x/crypto v0.22.0 10 | ) 11 | 12 | require ( 13 | github.com/kr/text v0.2.0 // indirect 14 | github.com/rogpeppe/go-internal v1.9.0 // indirect 15 | google.golang.org/protobuf v1.33.0 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= 2 | filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 3 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 4 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 5 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 6 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 7 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 8 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 9 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 10 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 11 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 12 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 13 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 14 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 15 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 16 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 17 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 18 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 19 | golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= 20 | golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= 21 | golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= 22 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 23 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 24 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 25 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 26 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 27 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 28 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 29 | golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 30 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 31 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 32 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 33 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 34 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 35 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 36 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 37 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 38 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 39 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 40 | golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 41 | golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 42 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 43 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 44 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 45 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 46 | golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= 47 | golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= 48 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 49 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 50 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 51 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 52 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 53 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 54 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 55 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 56 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 57 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 58 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 59 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 60 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 61 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 62 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 63 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 64 | -------------------------------------------------------------------------------- /groups/GroupCipher.go: -------------------------------------------------------------------------------- 1 | package groups 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | 7 | "github.com/crossle/libsignal-protocol-go/cipher" 8 | "github.com/crossle/libsignal-protocol-go/ecc" 9 | "github.com/crossle/libsignal-protocol-go/groups/ratchet" 10 | "github.com/crossle/libsignal-protocol-go/groups/state/record" 11 | "github.com/crossle/libsignal-protocol-go/groups/state/store" 12 | "github.com/crossle/libsignal-protocol-go/protocol" 13 | ) 14 | 15 | // NewGroupCipher will return a new group message cipher that can be used for 16 | // encrypt/decrypt operations. 17 | func NewGroupCipher(builder *SessionBuilder, senderKeyID *protocol.SenderKeyName, 18 | senderKeyStore store.SenderKey) *GroupCipher { 19 | 20 | return &GroupCipher{ 21 | senderKeyID: senderKeyID, 22 | senderKeyStore: senderKeyStore, 23 | sessionBuilder: builder, 24 | } 25 | } 26 | 27 | // GroupCipher is the main entry point for group encrypt/decrypt operations. 28 | // Once a session has been established, this can be used for 29 | // all encrypt/decrypt operations within that session. 30 | type GroupCipher struct { 31 | senderKeyID *protocol.SenderKeyName 32 | senderKeyStore store.SenderKey 33 | sessionBuilder *SessionBuilder 34 | } 35 | 36 | // Encrypt will take the given message in bytes and return encrypted bytes. 37 | func (c *GroupCipher) Encrypt(plaintext []byte) (protocol.CiphertextMessage, error) { 38 | // Load the sender key based on id from our store. 39 | keyRecord := c.senderKeyStore.LoadSenderKey(c.senderKeyID) 40 | senderKeyState, err := keyRecord.SenderKeyState() 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | // Get the message key from the senderkey state. 46 | senderKey, err := senderKeyState.SenderChainKey().SenderMessageKey() 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | // Encrypt the plaintext. 52 | ciphertext, err := cipher.EncryptCbc(senderKey.Iv(), senderKey.CipherKey(), plaintext) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | senderKeyMessage := protocol.NewSenderKeyMessage( 58 | senderKeyState.KeyID(), 59 | senderKey.Iteration(), 60 | ciphertext, 61 | senderKeyState.SigningKey().PrivateKey(), 62 | c.sessionBuilder.serializer.SenderKeyMessage, 63 | ) 64 | 65 | senderKeyState.SetSenderChainKey(senderKeyState.SenderChainKey().Next()) 66 | c.senderKeyStore.StoreSenderKey(c.senderKeyID, keyRecord) 67 | 68 | return senderKeyMessage, nil 69 | } 70 | 71 | // Decrypt decrypts the given message using an existing session that 72 | // is stored in the senderKey store. 73 | func (c *GroupCipher) Decrypt(senderKeyMessage *protocol.SenderKeyMessage) ([]byte, error) { 74 | keyRecord := c.senderKeyStore.LoadSenderKey(c.senderKeyID) 75 | 76 | if keyRecord.IsEmpty() { 77 | return nil, errors.New("No sender key for: " + c.senderKeyID.GroupID() + c.senderKeyID.Sender().String()) 78 | } 79 | 80 | // Get the senderkey state by id. 81 | senderKeyState, err := keyRecord.GetSenderKeyStateByID(senderKeyMessage.KeyID()) 82 | if err != nil { 83 | return nil, err 84 | } 85 | 86 | // Verify the signature of the senderkey message. 87 | verified := c.verifySignature(senderKeyState.SigningKey().PublicKey(), senderKeyMessage) 88 | if !verified { 89 | return nil, errors.New("Sender Key State failed verification with given pub key!") 90 | } 91 | 92 | senderKey, err := c.getSenderKey(senderKeyState, senderKeyMessage.Iteration()) 93 | if err != nil { 94 | return nil, err 95 | } 96 | 97 | // Decrypt the message ciphertext. 98 | plaintext, err := cipher.DecryptCbc(senderKey.Iv(), senderKey.CipherKey(), senderKeyMessage.Ciphertext()) 99 | if err != nil { 100 | return nil, err 101 | } 102 | 103 | // Store the sender key by id. 104 | c.senderKeyStore.StoreSenderKey(c.senderKeyID, keyRecord) 105 | 106 | return plaintext, nil 107 | } 108 | 109 | // verifySignature will verify the signature of the senderkey message with 110 | // the given public key. 111 | func (c *GroupCipher) verifySignature(signingPubKey ecc.ECPublicKeyable, 112 | senderKeyMessage *protocol.SenderKeyMessage) bool { 113 | 114 | return ecc.VerifySignature(signingPubKey, senderKeyMessage.Serialize(), senderKeyMessage.Signature()) 115 | } 116 | 117 | func (c *GroupCipher) getSenderKey(senderKeyState *record.SenderKeyState, iteration uint32) (*ratchet.SenderMessageKey, error) { 118 | senderChainKey := senderKeyState.SenderChainKey() 119 | if senderChainKey.Iteration() > iteration { 120 | if senderKeyState.HasSenderMessageKey(iteration) { 121 | return senderKeyState.RemoveSenderMessageKey(iteration), nil 122 | } 123 | i1 := strconv.Itoa(int(senderChainKey.Iteration())) 124 | i2 := strconv.Itoa(int(iteration)) 125 | return nil, errors.New("Received message with old counter: " + i1 + ", " + i2) 126 | } 127 | 128 | if iteration-senderChainKey.Iteration() > 2000 { 129 | return nil, errors.New("Over 2000 messages into the future!") 130 | } 131 | 132 | for senderChainKey.Iteration() < iteration { 133 | senderMessageKey, err := senderChainKey.SenderMessageKey() 134 | if err != nil { 135 | return nil, err 136 | } 137 | senderKeyState.AddSenderMessageKey(senderMessageKey) 138 | senderChainKey = senderChainKey.Next() 139 | } 140 | 141 | senderKeyState.SetSenderChainKey(senderChainKey.Next()) 142 | return senderChainKey.SenderMessageKey() 143 | } 144 | -------------------------------------------------------------------------------- /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/crossle/libsignal-protocol-go/groups/state/record" 13 | "github.com/crossle/libsignal-protocol-go/groups/state/store" 14 | "github.com/crossle/libsignal-protocol-go/protocol" 15 | "github.com/crossle/libsignal-protocol-go/serialize" 16 | "github.com/crossle/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/crossle/libsignal-protocol-go/kdf" 5 | "github.com/crossle/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 | "fmt" 6 | 7 | "github.com/crossle/libsignal-protocol-go/ecc" 8 | ) 9 | 10 | const maxStates = 5 11 | 12 | // SenderKeySerializer is an interface for serializing and deserializing 13 | // SenderKey objects into bytes. An implementation of this interface should be 14 | // used to encode/decode the object into JSON, Protobuffers, etc. 15 | type SenderKeySerializer interface { 16 | Serialize(preKey *SenderKeyStructure) []byte 17 | Deserialize(serialized []byte) (*SenderKeyStructure, error) 18 | } 19 | 20 | // NewSenderKeyFromBytes will return a prekey record from the given bytes using the given serializer. 21 | func NewSenderKeyFromBytes(serialized []byte, serializer SenderKeySerializer, 22 | stateSerializer SenderKeyStateSerializer) (*SenderKey, error) { 23 | 24 | // Use the given serializer to decode the senderkey record 25 | senderKeyStructure, err := serializer.Deserialize(serialized) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | return NewSenderKeyFromStruct(senderKeyStructure, serializer, stateSerializer) 31 | } 32 | 33 | // NewSenderKeyFromStruct returns a SenderKey record using the given serializable structure. 34 | func NewSenderKeyFromStruct(structure *SenderKeyStructure, serializer SenderKeySerializer, 35 | stateSerializer SenderKeyStateSerializer) (*SenderKey, error) { 36 | 37 | // Build our sender key states from structure. 38 | senderKeyStates := make([]*SenderKeyState, len(structure.SenderKeyStates)) 39 | for i := range structure.SenderKeyStates { 40 | var err error 41 | senderKeyStates[i], err = NewSenderKeyStateFromStructure(structure.SenderKeyStates[i], stateSerializer) 42 | if err != nil { 43 | return nil, err 44 | } 45 | } 46 | 47 | // Build and return our session. 48 | senderKey := &SenderKey{ 49 | senderKeyStates: senderKeyStates, 50 | serializer: serializer, 51 | } 52 | 53 | return senderKey, nil 54 | 55 | } 56 | 57 | // NewSenderKey record returns a new sender key record that can 58 | // be stored in a SenderKeyStore. 59 | func NewSenderKey(serializer SenderKeySerializer, 60 | stateSerializer SenderKeyStateSerializer) *SenderKey { 61 | 62 | return &SenderKey{ 63 | senderKeyStates: []*SenderKeyState{}, 64 | serializer: serializer, 65 | stateSerializer: stateSerializer, 66 | } 67 | } 68 | 69 | // SenderKeyStructure is a structure for serializing SenderKey records. 70 | type SenderKeyStructure struct { 71 | SenderKeyStates []*SenderKeyStateStructure 72 | } 73 | 74 | // SenderKey record is a structure for storing pre keys inside 75 | // a SenderKeyStore. 76 | type SenderKey struct { 77 | senderKeyStates []*SenderKeyState 78 | serializer SenderKeySerializer 79 | stateSerializer SenderKeyStateSerializer 80 | } 81 | 82 | // SenderKeyState will return the first sender key state in the record's 83 | // list of sender key states. 84 | func (k *SenderKey) SenderKeyState() (*SenderKeyState, error) { 85 | if len(k.senderKeyStates) > 0 { 86 | return k.senderKeyStates[0], nil 87 | } 88 | return nil, errors.New("No Sender Keys State in Record") 89 | } 90 | 91 | // GetSenderKeyStateByID will return the sender key state with the given 92 | // key id. 93 | func (k *SenderKey) GetSenderKeyStateByID(keyID uint32) (*SenderKeyState, error) { 94 | for i := 0; i < len(k.senderKeyStates); i++ { 95 | if k.senderKeyStates[i].KeyID() == keyID { 96 | return k.senderKeyStates[i], nil 97 | } 98 | } 99 | 100 | return nil, fmt.Errorf("No sender key for for ID: %d", keyID) 101 | } 102 | 103 | // IsEmpty will return false if there is more than one state in this 104 | // senderkey record. 105 | func (k *SenderKey) IsEmpty() bool { 106 | return len(k.senderKeyStates) == 0 107 | } 108 | 109 | // AddSenderKeyState will add a new state to this senderkey record with the given 110 | // id, iteration, chainkey, and signature key. 111 | func (k *SenderKey) AddSenderKeyState(id uint32, iteration uint32, 112 | chainKey []byte, signatureKey ecc.ECPublicKeyable) { 113 | 114 | newState := NewSenderKeyStateFromPublicKey(id, iteration, chainKey, signatureKey, k.stateSerializer) 115 | k.senderKeyStates = append([]*SenderKeyState{newState}, k.senderKeyStates...) 116 | 117 | if len(k.senderKeyStates) > maxStates { 118 | k.senderKeyStates = k.senderKeyStates[:len(k.senderKeyStates)-1] 119 | } 120 | } 121 | 122 | // SetSenderKeyState will replace the current senderkey states with the given 123 | // senderkey state. 124 | func (k *SenderKey) SetSenderKeyState(id uint32, iteration uint32, 125 | chainKey []byte, signatureKey *ecc.ECKeyPair) { 126 | 127 | newState := NewSenderKeyState(id, iteration, chainKey, signatureKey, k.stateSerializer) 128 | k.senderKeyStates = make([]*SenderKeyState, 0, maxStates/2) 129 | k.senderKeyStates = append(k.senderKeyStates, newState) 130 | } 131 | 132 | // Serialize will return the record as serialized bytes so it can be 133 | // persistently stored. 134 | func (k *SenderKey) Serialize() []byte { 135 | return k.serializer.Serialize(k.structure()) 136 | } 137 | 138 | // structure will return a simple serializable record structure. 139 | // This is used for serialization to persistently 140 | // store a session record. 141 | func (k *SenderKey) structure() *SenderKeyStructure { 142 | senderKeyStates := make([]*SenderKeyStateStructure, len(k.senderKeyStates)) 143 | for i := range k.senderKeyStates { 144 | senderKeyStates[i] = k.senderKeyStates[i].structure() 145 | } 146 | return &SenderKeyStructure{ 147 | SenderKeyStates: senderKeyStates, 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /groups/state/record/SenderKeyState.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/crossle/libsignal-protocol-go/ecc" 5 | "github.com/crossle/libsignal-protocol-go/groups/ratchet" 6 | "github.com/crossle/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 | s := &SenderKeyStateStructure{ 177 | Keys: keys, 178 | KeyID: k.keyID, 179 | SenderChainKey: ratchet.NewStructFromSenderChainKey(k.senderChainKey), 180 | SigningKeyPublic: k.signingKeyPair.PublicKey().Serialize(), 181 | } 182 | if k.signingKeyPair.PrivateKey() != nil { 183 | s.SigningKeyPrivate = bytehelper.ArrayToSlice(k.signingKeyPair.PrivateKey().Serialize()) 184 | } 185 | return s 186 | } 187 | -------------------------------------------------------------------------------- /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/crossle/libsignal-protocol-go/groups/state/record" 5 | "github.com/crossle/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 | "io" 8 | 9 | "golang.org/x/crypto/curve25519" 10 | "golang.org/x/crypto/hkdf" 11 | ) 12 | 13 | // HKDF is a hashed key derivation function type that can be used to derive keys. 14 | type HKDF func(inputKeyMaterial, salt, info []byte, outputLength int) ([]byte, error) 15 | 16 | // DeriveSecrets derives the requested number of bytes using HKDF with the given 17 | // input, salt, and info. 18 | func DeriveSecrets(inputKeyMaterial, salt, info []byte, outputLength int) ([]byte, error) { 19 | kdf := hkdf.New(sha256.New, inputKeyMaterial, salt, info) 20 | 21 | secrets := make([]byte, outputLength) 22 | length, err := io.ReadFull(kdf, secrets) 23 | if err != nil { 24 | return nil, err 25 | } 26 | if length != outputLength { 27 | return nil, err 28 | } 29 | 30 | return secrets, nil 31 | } 32 | 33 | // CalculateSharedSecret uses DH Curve25519 to find a shared secret. The result of this function 34 | // should be used in `DeriveSecrets` to output the Root and Chain keys. 35 | func CalculateSharedSecret(theirKey, ourKey [32]byte) [32]byte { 36 | var sharedSecret [32]byte 37 | curve25519.ScalarMult(&sharedSecret, &ourKey, &theirKey) 38 | 39 | return sharedSecret 40 | } 41 | 42 | // KeyMaterial is a structure for representing a cipherkey, mac, and iv 43 | type KeyMaterial struct { 44 | CipherKey []byte 45 | MacKey []byte 46 | IV []byte 47 | } 48 | -------------------------------------------------------------------------------- /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 | 8 | "github.com/crossle/libsignal-protocol-go/kdf" 9 | "github.com/crossle/libsignal-protocol-go/keys/message" 10 | ) 11 | 12 | var messageKeySeed = []byte{0x01} 13 | var chainKeySeed = []byte{0x02} 14 | 15 | // NewKey returns a new chain key with the given kdf, key, and index 16 | func NewKey(kdf kdf.HKDF, key []byte, index uint32) *Key { 17 | chainKey := Key{ 18 | kdf: kdf, 19 | key: key, 20 | index: index, 21 | } 22 | 23 | return &chainKey 24 | } 25 | 26 | // NewKeyFromStruct will return a chain key built from the given structure. 27 | func NewKeyFromStruct(structure *KeyStructure, kdf kdf.HKDF) *Key { 28 | return NewKey( 29 | kdf, 30 | structure.Key, 31 | structure.Index, 32 | ) 33 | } 34 | 35 | // NewStructFromKey will return a chain key structure for serialization. 36 | func NewStructFromKey(key *Key) *KeyStructure { 37 | return &KeyStructure{ 38 | Key: key.key, 39 | Index: key.index, 40 | } 41 | } 42 | 43 | // KeyStructure is a serializeable structure for chain keys. 44 | type KeyStructure struct { 45 | Key []byte 46 | Index uint32 47 | } 48 | 49 | // Key is used for generating message keys. This key "ratchets" every time a 50 | // message key is generated. Every time the chain key ratchets forward, its index 51 | // increases by one. 52 | type Key struct { 53 | kdf kdf.HKDF 54 | key []byte 55 | index uint32 // Index's maximum size: 4,294,967,295 56 | } 57 | 58 | // Current returns the current ChainKey struct. 59 | func (c *Key) Current() *Key { 60 | return c 61 | } 62 | 63 | // Key returns the ChainKey's key material. 64 | func (c *Key) Key() []byte { 65 | return c.key 66 | } 67 | 68 | // SetKey will set the ChainKey's key material. 69 | func (c *Key) SetKey(key []byte) { 70 | c.key = key 71 | } 72 | 73 | // Index returns how many times the ChainKey has been "ratcheted" forward. 74 | func (c *Key) Index() uint32 { 75 | return c.index 76 | } 77 | 78 | // SetIndex sets how many times the ChainKey has been "ratcheted" forward. 79 | func (c *Key) SetIndex(index uint32) { 80 | c.index = index 81 | } 82 | 83 | // NextKey uses the key derivation function to generate a new ChainKey. 84 | func (c *Key) NextKey() *Key { 85 | nextKey := c.BaseMaterial(chainKeySeed) 86 | return NewKey(c.kdf, nextKey, c.index+1) 87 | } 88 | 89 | // MessageKeys returns message keys, which includes the cipherkey, mac, iv, and index. 90 | func (c *Key) MessageKeys() *message.Keys { 91 | inputKeyMaterial := c.BaseMaterial(messageKeySeed) 92 | keyMaterialBytes, _ := c.kdf(inputKeyMaterial, nil, []byte(message.KdfSalt), message.DerivedSecretsSize) 93 | keyMaterial := newKeyMaterial(keyMaterialBytes) 94 | 95 | // Use the key material returned from the key derivation function for our cipherkey, mac, and iv. 96 | messageKeys := message.NewKeys( 97 | keyMaterial.CipherKey, // Use the first 32 bytes of the key material for the CipherKey 98 | keyMaterial.MacKey, // Use bytes 32-64 of the key material for the MacKey 99 | keyMaterial.IV, // Use the last 16 bytes for the IV. 100 | c.Index(), // Attach the chain key's index to the message keys. 101 | ) 102 | 103 | return messageKeys 104 | } 105 | 106 | // BaseMaterial uses hmac to derive the base material used in the key derivation function for a new key. 107 | func (c *Key) BaseMaterial(seed []byte) []byte { 108 | mac := hmac.New(sha256.New, c.key[:]) 109 | mac.Write(seed) 110 | 111 | return mac.Sum(nil) 112 | } 113 | 114 | // NewKeyMaterial takes an 80-byte slice derived from a key derivation function and splits 115 | // it into the cipherkey, mac, and iv. 116 | func newKeyMaterial(keyMaterialBytes []byte) *kdf.KeyMaterial { 117 | cipherKey := keyMaterialBytes[:32] // Use the first 32 bytes of the key material for the CipherKey 118 | macKey := keyMaterialBytes[32:64] // Use bytes 32-64 of the key material for the MacKey 119 | iv := keyMaterialBytes[64:80] // Use the last 16 bytes for the IV. 120 | 121 | keyMaterial := kdf.KeyMaterial{ 122 | CipherKey: cipherKey, 123 | MacKey: macKey, 124 | IV: iv, 125 | } 126 | 127 | return &keyMaterial 128 | } 129 | -------------------------------------------------------------------------------- /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 | 8 | "github.com/crossle/libsignal-protocol-go/ecc" 9 | ) 10 | 11 | // NewKey generates a new IdentityKey from an ECPublicKey 12 | func NewKey(publicKey ecc.ECPublicKeyable) *Key { 13 | identityKey := Key{ 14 | publicKey: publicKey, 15 | } 16 | 17 | return &identityKey 18 | } 19 | 20 | // NewKeyFromBytes generates a new IdentityKey from public key bytes 21 | func NewKeyFromBytes(publicKey [32]byte, offset int) Key { 22 | identityKey := Key{ 23 | publicKey: ecc.NewDjbECPublicKey(publicKey), 24 | } 25 | 26 | return identityKey 27 | } 28 | 29 | // Key is a structure for representing an identity key. This same structure can 30 | // be used for verifying recipient's identity key or storing our own identity key. 31 | type Key struct { 32 | publicKey ecc.ECPublicKeyable 33 | } 34 | 35 | // Fingerprint gets the string fingerprint representation of the public key. 36 | func (k *Key) Fingerprint() string { 37 | return hex.EncodeToString(k.publicKey.Serialize()) 38 | } 39 | 40 | // PublicKey returns the EC Public key of the identity key 41 | func (k *Key) PublicKey() ecc.ECPublicKeyable { 42 | return k.publicKey 43 | } 44 | 45 | // Serialize returns the serialized version of the key 46 | func (k *Key) Serialize() []byte { 47 | return k.publicKey.Serialize() 48 | } 49 | -------------------------------------------------------------------------------- /keys/identity/IdentityKeyPair.go: -------------------------------------------------------------------------------- 1 | package identity 2 | 3 | import ( 4 | "github.com/crossle/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/crossle/libsignal-protocol-go/ecc" 7 | "github.com/crossle/libsignal-protocol-go/keys/identity" 8 | "github.com/crossle/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/crossle/libsignal-protocol-go/ecc" 7 | "github.com/crossle/libsignal-protocol-go/kdf" 8 | "github.com/crossle/libsignal-protocol-go/keys/chain" 9 | "github.com/crossle/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 | theirPublicKey := theirRatchetKey.PublicKey() 43 | ourPrivateKey := ourRatchetKey.PrivateKey().Serialize() 44 | 45 | // Use our key derivation function to calculate a shared secret. 46 | sharedSecret := kdf.CalculateSharedSecret(theirPublicKey, ourPrivateKey) 47 | derivedSecretBytes, err := kdf.DeriveSecrets(sharedSecret[:], k.key, []byte(KdfInfo), DerivedSecretsSize) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | // Split the derived secret bytes in half, using one half for the root key and the second for the chain key. 53 | derivedSecrets := session.NewDerivedSecrets(derivedSecretBytes) 54 | 55 | // Create new root and chain key structures from the derived secrets. 56 | rootKey := NewKey(k.kdf, derivedSecrets.RootKey()) 57 | chainKey := chain.NewKey(k.kdf, derivedSecrets.ChainKey(), 0) 58 | 59 | // Create a session keypair with the generated root and chain keys. 60 | keyPair := session.NewKeyPair( 61 | rootKey, 62 | chainKey, 63 | ) 64 | 65 | return keyPair, nil 66 | } 67 | -------------------------------------------------------------------------------- /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/crossle/libsignal-protocol-go/ecc" 7 | "github.com/crossle/libsignal-protocol-go/keys/chain" 8 | "github.com/crossle/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 | fmt.Println(msg) 21 | t := time.Now() 22 | fmt.Println( 23 | "["+level+"]", 24 | t.Format(time.RFC3339), 25 | caller, 26 | "▶ ", 27 | msg, 28 | ) 29 | } 30 | 31 | // shouldLog determines whether or not the given caller should 32 | // be allowed to log messages. 33 | func (d *defaultLogger) shouldLog(caller string) bool { 34 | shouldLog := false 35 | d.ensureNamespaces() 36 | for _, namespace := range d.namespaces { 37 | if namespace == "all" { 38 | shouldLog = true 39 | } 40 | if strings.Contains(caller, namespace) { 41 | shouldLog = true 42 | } 43 | } 44 | 45 | return shouldLog 46 | } 47 | 48 | // ensureNamespaces checks to see if our list of loggable namespaces 49 | // has been initialized or not. If not, it defaults to log all. 50 | func (d *defaultLogger) ensureNamespaces() { 51 | if d.namespaces == nil { 52 | d.namespaces = []string{"all"} 53 | } 54 | } 55 | 56 | // Debug is used to log debug messages. 57 | func (d *defaultLogger) Debug(caller, msg string) { 58 | // d.log("DEBUG", caller, msg) 59 | } 60 | 61 | // Info is used to log info messages. 62 | func (d *defaultLogger) Info(caller, msg string) { 63 | // d.log("INFO", caller, msg) 64 | } 65 | 66 | // Warning is used to log warning messages. 67 | func (d *defaultLogger) Warning(caller, msg string) { 68 | d.log("WARNING", caller, msg) 69 | } 70 | 71 | // Error is used to log error messages. 72 | func (d *defaultLogger) Error(caller, msg string) { 73 | d.log("ERROR", caller, msg) 74 | } 75 | 76 | // Configure takes a configuration string separated by commas 77 | // that contains all the callers that should be logged. This 78 | // allows granular logging of different go files. 79 | // 80 | // Example: 81 | // logger.Configure("RootKey.go,Curve.go") 82 | // logger.Configure("all") 83 | // 84 | func (d *defaultLogger) Configure(settings string) { 85 | d.namespaces = strings.Split(settings, ",") 86 | } 87 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /mixin_signal_protocol_store.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | groupRecord "github.com/crossle/libsignal-protocol-go/groups/state/record" 5 | "github.com/crossle/libsignal-protocol-go/keys/identity" 6 | "github.com/crossle/libsignal-protocol-go/protocol" 7 | "github.com/crossle/libsignal-protocol-go/serialize" 8 | "github.com/crossle/libsignal-protocol-go/state/record" 9 | ) 10 | 11 | func NewMixinSignalProtocolStore(serializer *serialize.Serializer) *MixinSignalProtocolStore { 12 | return &MixinSignalProtocolStore{ 13 | IdentityKeyStore: NewMixinIdentityKeyStore(), 14 | PreKeyStore: NewMixinPreKeyStore(serializer), 15 | SessionStore: NewMixinSessionStore(serializer), 16 | SignedPreKeyStore: NewMixinSignedPreKeyStore(serializer), 17 | SenderKeyStore: NewMixinSenderKeyStore(serializer), 18 | } 19 | } 20 | 21 | type MixinSignalProtocolStore struct { 22 | IdentityKeyStore *MixinIdentityKeyStore 23 | PreKeyStore *MixinPreKeyStore 24 | SessionStore *MixinSessionStore 25 | SignedPreKeyStore *MixinSignedPreKeyStore 26 | SenderKeyStore *MixinSenderKeyStore 27 | } 28 | 29 | func (i *MixinSignalProtocolStore) GetIdentityKeyPair() *identity.KeyPair { 30 | return i.IdentityKeyStore.GetIdentityKeyPair() 31 | } 32 | 33 | func (i *MixinSignalProtocolStore) GetLocalRegistrationId() uint32 { 34 | return i.IdentityKeyStore.GetLocalRegistrationId() 35 | } 36 | 37 | func (i *MixinSignalProtocolStore) SaveIdentity(address *protocol.SignalAddress, identityKey *identity.Key) { 38 | i.IdentityKeyStore.SaveIdentity(address, identityKey) 39 | } 40 | 41 | func (i *MixinSignalProtocolStore) IsTrustedIdentity(address *protocol.SignalAddress, identityKey *identity.Key) bool { 42 | return i.IdentityKeyStore.IsTrustedIdentity(address, identityKey) 43 | } 44 | 45 | func (i *MixinSignalProtocolStore) LoadPreKey(preKeyID uint32) *record.PreKey { 46 | return i.PreKeyStore.LoadPreKey(preKeyID) 47 | } 48 | 49 | func (i *MixinSignalProtocolStore) StorePreKey(preKeyID uint32, preKeyRecord *record.PreKey) { 50 | i.PreKeyStore.StorePreKey(preKeyID, preKeyRecord) 51 | } 52 | 53 | func (i *MixinSignalProtocolStore) ContainsPreKey(preKeyID uint32) bool { 54 | return i.PreKeyStore.ContainsPreKey(preKeyID) 55 | } 56 | 57 | func (i *MixinSignalProtocolStore) RemovePreKey(preKeyID uint32) { 58 | i.PreKeyStore.RemovePreKey(preKeyID) 59 | } 60 | 61 | func (i *MixinSignalProtocolStore) LoadSession(address *protocol.SignalAddress) *record.Session { 62 | return i.SessionStore.LoadSession(address) 63 | } 64 | 65 | func (i *MixinSignalProtocolStore) GetSubDeviceSessions(name string) []uint32 { 66 | return i.SessionStore.GetSubDeviceSessions(name) 67 | } 68 | 69 | func (i *MixinSignalProtocolStore) StoreSession(remoteAddress *protocol.SignalAddress, record *record.Session) { 70 | i.SessionStore.StoreSession(remoteAddress, record) 71 | } 72 | 73 | func (i *MixinSignalProtocolStore) ContainsSession(remoteAddress *protocol.SignalAddress) bool { 74 | return i.SessionStore.ContainsSession(remoteAddress) 75 | } 76 | 77 | func (i *MixinSignalProtocolStore) DeleteSession(remoteAddress *protocol.SignalAddress) { 78 | i.SessionStore.DeleteSession(remoteAddress) 79 | } 80 | 81 | func (i *MixinSignalProtocolStore) DeleteAllSessions() { 82 | // i.sessions = make(map[*protocol.SignalAddress]*record.Session) 83 | i.SessionStore.DeleteAllSessions() 84 | } 85 | 86 | func (i *MixinSignalProtocolStore) LoadSignedPreKey(signedPreKeyID uint32) *record.SignedPreKey { 87 | return i.SignedPreKeyStore.LoadSignedPreKey(signedPreKeyID) 88 | } 89 | 90 | func (i *MixinSignalProtocolStore) LoadSignedPreKeys() []*record.SignedPreKey { 91 | return i.SignedPreKeyStore.LoadSignedPreKeys() 92 | } 93 | 94 | func (i *MixinSignalProtocolStore) StoreSignedPreKey(signedPreKeyID uint32, record *record.SignedPreKey) { 95 | i.SignedPreKeyStore.StoreSignedPreKey(signedPreKeyID, record) 96 | } 97 | 98 | func (i *MixinSignalProtocolStore) ContainsSignedPreKey(signedPreKeyID uint32) bool { 99 | return i.SignedPreKeyStore.ContainsSignedPreKey(signedPreKeyID) 100 | } 101 | 102 | func (i *MixinSignalProtocolStore) RemoveSignedPreKey(signedPreKeyID uint32) { 103 | i.SignedPreKeyStore.RemoveSignedPreKey(signedPreKeyID) 104 | } 105 | 106 | func (i *MixinSignalProtocolStore) StoreSenderKey(senderKeyName *protocol.SenderKeyName, keyRecord *groupRecord.SenderKey) { 107 | i.SenderKeyStore.StoreSenderKey(senderKeyName, keyRecord) 108 | } 109 | 110 | func (i *MixinSignalProtocolStore) LoadSenderKey(senderKeyName *protocol.SenderKeyName) *groupRecord.SenderKey { 111 | return i.SenderKeyStore.LoadSenderKey(senderKeyName) 112 | } 113 | -------------------------------------------------------------------------------- /mixin_store.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/hex" 6 | "fmt" 7 | "syscall/js" 8 | 9 | "github.com/crossle/libsignal-protocol-go/ecc" 10 | groupRecord "github.com/crossle/libsignal-protocol-go/groups/state/record" 11 | "github.com/crossle/libsignal-protocol-go/keys/identity" 12 | "github.com/crossle/libsignal-protocol-go/logger" 13 | "github.com/crossle/libsignal-protocol-go/protocol" 14 | "github.com/crossle/libsignal-protocol-go/serialize" 15 | "github.com/crossle/libsignal-protocol-go/state/record" 16 | "github.com/crossle/libsignal-protocol-go/util/bytehelper" 17 | ) 18 | 19 | // IdentityKeyStore 20 | func NewMixinIdentityKeyStore() *MixinIdentityKeyStore { 21 | return &MixinIdentityKeyStore{} 22 | } 23 | 24 | type MixinIdentityKeyStore struct { 25 | } 26 | 27 | func (i *MixinIdentityKeyStore) GetIdentityKeyPair() *identity.KeyPair { 28 | result := js.Global().Get("signalDao").Call("getIdentityKeyPair") 29 | public, _ := base64.StdEncoding.DecodeString(result.Get("public_key").String()) 30 | private, _ := base64.StdEncoding.DecodeString(result.Get("private_key").String()) 31 | 32 | privateKey := ecc.NewDjbECPrivateKey(bytehelper.SliceToArray(private)) 33 | 34 | publicKeyable, _ := ecc.DecodePoint(public, 0) 35 | publicKey := identity.NewKey(publicKeyable) 36 | identityKeyPair := identity.NewKeyPair(publicKey, privateKey) 37 | return identityKeyPair 38 | } 39 | 40 | func (i *MixinIdentityKeyStore) GetLocalRegistrationId() uint32 { 41 | result := js.Global().Get("signalDao").Call("getIdentityKeyPair") 42 | return uint32(result.Get("registration_id").Int()) 43 | } 44 | 45 | func (i *MixinIdentityKeyStore) SaveIdentity(address *protocol.SignalAddress, identityKey *identity.Key) { 46 | pub := base64.StdEncoding.EncodeToString(identityKey.Serialize()) 47 | js.Global().Get("signalDao").Call("saveIdentityKey", address.Name(), pub) 48 | } 49 | 50 | func (i *MixinIdentityKeyStore) IsTrustedIdentity(address *protocol.SignalAddress, identityKey *identity.Key) bool { 51 | result := js.Global().Get("signalDao").Call("getIdentityKey", address.Name()) 52 | if result.IsUndefined() { 53 | return true 54 | } 55 | public, _ := base64.StdEncoding.DecodeString(result.Get("public_key").String()) 56 | if hex.EncodeToString(public) == identityKey.Fingerprint() { 57 | return true 58 | } 59 | // TODO 60 | return true 61 | } 62 | 63 | // PreKeyStore 64 | func NewMixinPreKeyStore(serializer *serialize.Serializer) *MixinPreKeyStore { 65 | return &MixinPreKeyStore{ 66 | serializer: serializer, 67 | } 68 | } 69 | 70 | type MixinPreKeyStore struct { 71 | serializer *serialize.Serializer 72 | } 73 | 74 | func (i *MixinPreKeyStore) LoadPreKey(preKeyID uint32) *record.PreKey { 75 | result := js.Global().Get("signalDao").Call("getPreKey", preKeyID) 76 | if result.IsUndefined() { 77 | return nil 78 | } 79 | recordBytes := []byte(result.Get("record").String()) 80 | preKey, err := record.NewPreKeyFromBytes(recordBytes, i.serializer.PreKeyRecord) 81 | if err != nil { 82 | return nil 83 | } 84 | return preKey 85 | } 86 | 87 | func (i *MixinPreKeyStore) StorePreKey(preKeyID uint32, preKeyRecord *record.PreKey) { 88 | record := hex.EncodeToString(preKeyRecord.Serialize()) 89 | js.Global().Get("signalDao").Call("savePreKey", preKeyID, record) 90 | } 91 | 92 | func (i *MixinPreKeyStore) ContainsPreKey(preKeyID uint32) bool { 93 | result := js.Global().Get("signalDao").Call("getPreKey", preKeyID) 94 | if result.IsUndefined() { 95 | return false 96 | } 97 | return true 98 | } 99 | 100 | func (i *MixinPreKeyStore) RemovePreKey(preKeyID uint32) { 101 | js.Global().Get("signalDao").Call("deletePreKey", preKeyID) 102 | } 103 | 104 | // SessionStore 105 | func NewMixinSessionStore(serializer *serialize.Serializer) *MixinSessionStore { 106 | return &MixinSessionStore{ 107 | serializer: serializer, 108 | } 109 | } 110 | 111 | type MixinSessionStore struct { 112 | serializer *serialize.Serializer 113 | } 114 | 115 | func (i *MixinSessionStore) LoadSession(address *protocol.SignalAddress) *record.Session { 116 | result := js.Global().Get("signalDao").Call("getSession", address.Name(), address.DeviceID()) 117 | if result.IsUndefined() { 118 | sessionRecord := record.NewSession(i.serializer.Session, i.serializer.State) 119 | return sessionRecord 120 | } 121 | recordResult := result.Get("record") 122 | serialized, err := hex.DecodeString(recordResult.String()) 123 | if err != nil { 124 | fmt.Println(err) 125 | } 126 | sessionRecord, err := record.NewSessionFromBytes(serialized, i.serializer.Session, i.serializer.State) 127 | if err != nil { 128 | fmt.Println(err) 129 | } 130 | return sessionRecord 131 | } 132 | 133 | func (i *MixinSessionStore) GetSubDeviceSessions(name string) []uint32 { 134 | var deviceIDs []uint32 135 | 136 | return deviceIDs 137 | } 138 | 139 | func (i *MixinSessionStore) StoreSession(remoteAddress *protocol.SignalAddress, record *record.Session) { 140 | rec := hex.EncodeToString(record.Serialize()) 141 | js.Global().Get("signalDao").Call("saveSession", remoteAddress.Name(), remoteAddress.DeviceID(), rec) 142 | } 143 | 144 | func (i *MixinSessionStore) ContainsSession(remoteAddress *protocol.SignalAddress) bool { 145 | result := js.Global().Get("signalDao").Call("getSession", remoteAddress.Name(), remoteAddress.DeviceID()) 146 | if result.IsUndefined() { 147 | return false 148 | } 149 | return true 150 | } 151 | 152 | func (i *MixinSessionStore) DeleteSession(remoteAddress *protocol.SignalAddress) { 153 | js.Global().Get("signalDao").Call("deleteSession", remoteAddress.Name(), remoteAddress.DeviceID()) 154 | } 155 | 156 | func (i *MixinSessionStore) DeleteAllSessions() { 157 | // i.sessions = make(map[*protocol.SignalAddress]*record.Session) 158 | } 159 | 160 | // SignedPreKeyStore 161 | func NewMixinSignedPreKeyStore(serializer *serialize.Serializer) *MixinSignedPreKeyStore { 162 | return &MixinSignedPreKeyStore{ 163 | serializer: serializer, 164 | } 165 | } 166 | 167 | type MixinSignedPreKeyStore struct { 168 | serializer *serialize.Serializer 169 | } 170 | 171 | func (i *MixinSignedPreKeyStore) LoadSignedPreKey(signedPreKeyID uint32) *record.SignedPreKey { 172 | result := js.Global().Get("signalDao").Call("getSignedPreKey", signedPreKeyID) 173 | logger.Debug("Load Signed PreKey result: ", result) 174 | if result.IsUndefined() { 175 | return nil 176 | } 177 | recordResult := result.Get("record") 178 | serialized := []byte(recordResult.String()) 179 | signedPreKey, err := record.NewSignedPreKeyFromBytes(serialized, i.serializer.SignedPreKeyRecord) 180 | if err != nil { 181 | return nil 182 | } 183 | return signedPreKey 184 | } 185 | 186 | func (i *MixinSignedPreKeyStore) LoadSignedPreKeys() []*record.SignedPreKey { 187 | result := js.Global().Get("signalDao").Call("getAllSignedPreKeys") 188 | if result.IsUndefined() { 189 | return nil 190 | } 191 | 192 | var preKeys []*record.SignedPreKey 193 | 194 | // for _, record := range i.store { 195 | // preKeys = append(preKeys, record) 196 | // } 197 | 198 | return preKeys 199 | } 200 | 201 | func (i *MixinSignedPreKeyStore) StoreSignedPreKey(signedPreKeyID uint32, record *record.SignedPreKey) { 202 | recordStr := hex.EncodeToString(record.Serialize()) 203 | js.Global().Get("signalDao").Call("saveSignedPreKey", signedPreKeyID, recordStr) 204 | } 205 | 206 | func (i *MixinSignedPreKeyStore) ContainsSignedPreKey(signedPreKeyID uint32) bool { 207 | result := js.Global().Get("signalDao").Call("getSignedPreKey", signedPreKeyID) 208 | if result.IsUndefined() { 209 | return false 210 | } 211 | return true 212 | } 213 | 214 | func (i *MixinSignedPreKeyStore) RemoveSignedPreKey(signedPreKeyID uint32) { 215 | js.Global().Get("signalDao").Call("deleteSignedPreKey", signedPreKeyID) 216 | } 217 | 218 | func NewMixinSenderKeyStore(serializer *serialize.Serializer) *MixinSenderKeyStore { 219 | return &MixinSenderKeyStore{ 220 | serializer: serializer.SenderKeyRecord, 221 | stateSerializer: serializer.SenderKeyState, 222 | } 223 | } 224 | 225 | type MixinSenderKeyStore struct { 226 | serializer groupRecord.SenderKeySerializer 227 | stateSerializer groupRecord.SenderKeyStateSerializer 228 | } 229 | 230 | func (i *MixinSenderKeyStore) StoreSenderKey(senderKeyName *protocol.SenderKeyName, keyRecord *groupRecord.SenderKey) { 231 | recordStr := hex.EncodeToString(keyRecord.Serialize()) 232 | js.Global().Get("signalDao").Call("saveSenderKey", senderKeyName.GroupID(), senderKeyName.Sender().String(), recordStr) 233 | } 234 | 235 | func (i *MixinSenderKeyStore) LoadSenderKey(senderKeyName *protocol.SenderKeyName) *groupRecord.SenderKey { 236 | result := js.Global().Get("signalDao").Call("getSenderKey", senderKeyName.GroupID(), senderKeyName.Sender().String()) 237 | if result.IsUndefined() { 238 | return groupRecord.NewSenderKey(i.serializer, i.stateSerializer) 239 | } 240 | recordResult := result.Get("record") 241 | serialized, err := hex.DecodeString(recordResult.String()) 242 | if err != nil { 243 | fmt.Println(err) 244 | return nil 245 | } 246 | senderKey, err := groupRecord.NewSenderKeyFromBytes(serialized, i.serializer, i.stateSerializer) 247 | if err != nil { 248 | fmt.Println(err) 249 | return nil 250 | } 251 | return senderKey 252 | } 253 | -------------------------------------------------------------------------------- /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 | "strconv" 6 | 7 | "github.com/crossle/libsignal-protocol-go/ecc" 8 | "github.com/crossle/libsignal-protocol-go/keys/identity" 9 | "github.com/crossle/libsignal-protocol-go/util/optional" 10 | ) 11 | 12 | // PreKeySignalMessageSerializer is an interface for serializing and deserializing 13 | // PreKeySignalMessages into bytes. An implementation of this interface should be 14 | // used to encode/decode the object into JSON, Protobuffers, etc. 15 | type PreKeySignalMessageSerializer interface { 16 | Serialize(signalMessage *PreKeySignalMessageStructure) []byte 17 | Deserialize(serialized []byte) (*PreKeySignalMessageStructure, error) 18 | } 19 | 20 | // NewPreKeySignalMessageFromBytes will return a Signal Ciphertext message from the given 21 | // bytes using the given serializer. 22 | func NewPreKeySignalMessageFromBytes(serialized []byte, serializer PreKeySignalMessageSerializer, 23 | msgSerializer SignalMessageSerializer) (*PreKeySignalMessage, error) { 24 | // Use the given serializer to decode the signal message. 25 | signalMessageStructure, err := serializer.Deserialize(serialized) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | return NewPreKeySignalMessageFromStruct(signalMessageStructure, serializer, msgSerializer) 31 | } 32 | 33 | // NewPreKeySignalMessageFromStruct will return a new PreKeySignalMessage from the given 34 | // PreKeySignalMessageStructure. 35 | func NewPreKeySignalMessageFromStruct(structure *PreKeySignalMessageStructure, 36 | serializer PreKeySignalMessageSerializer, msgSerializer SignalMessageSerializer) (*PreKeySignalMessage, error) { 37 | 38 | // Throw an error if the given message structure is an unsupported version. 39 | if structure.Version <= UnsupportedVersion { 40 | err := "Legacy message: " + strconv.Itoa(structure.Version) 41 | return nil, errors.New(err) 42 | } 43 | 44 | // Throw an error if the given message structure is a future version. 45 | if structure.Version > CurrentVersion { 46 | err := "Unknown version: " + strconv.Itoa(structure.Version) 47 | return nil, errors.New(err) 48 | } 49 | 50 | // Throw an error if the structure is missing critical fields. 51 | if structure.BaseKey == nil || structure.IdentityKey == nil || structure.Message == nil { 52 | err := "Incomplete message." 53 | return nil, errors.New(err) 54 | } 55 | 56 | // Create the signal message object from the structure. 57 | preKeyWhisperMessage := &PreKeySignalMessage{structure: *structure, serializer: serializer} 58 | 59 | // Generate the base ECC key from bytes. 60 | var err error 61 | preKeyWhisperMessage.baseKey, err = ecc.DecodePoint(structure.BaseKey, 0) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | // Generate the identity key from bytes 67 | var identityKey ecc.ECPublicKeyable 68 | identityKey, err = ecc.DecodePoint(structure.IdentityKey, 0) 69 | if err != nil { 70 | return nil, err 71 | } 72 | preKeyWhisperMessage.identityKey = identity.NewKey(identityKey) 73 | 74 | // Generate the SignalMessage object from bytes. 75 | preKeyWhisperMessage.message, err = NewSignalMessageFromBytes(structure.Message, msgSerializer) 76 | if err != nil { 77 | return nil, err 78 | } 79 | 80 | return preKeyWhisperMessage, nil 81 | } 82 | 83 | // NewPreKeySignalMessage will return a new PreKeySignalMessage object. 84 | func NewPreKeySignalMessage(version int, registrationID uint32, preKeyID *optional.Uint32, signedPreKeyID uint32, 85 | baseKey ecc.ECPublicKeyable, identityKey *identity.Key, message *SignalMessage, serializer PreKeySignalMessageSerializer, 86 | msgSerializer SignalMessageSerializer) (*PreKeySignalMessage, error) { 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 | "strconv" 6 | 7 | "github.com/crossle/libsignal-protocol-go/ecc" 8 | ) 9 | 10 | // SenderKeyDistributionMessageSerializer is an interface for serializing and deserializing 11 | // SenderKeyDistributionMessages into bytes. An implementation of this interface should be 12 | // used to encode/decode the object into JSON, Protobuffers, etc. 13 | type SenderKeyDistributionMessageSerializer interface { 14 | Serialize(signalMessage *SenderKeyDistributionMessageStructure) []byte 15 | Deserialize(serialized []byte) (*SenderKeyDistributionMessageStructure, error) 16 | } 17 | 18 | // NewSenderKeyDistributionMessageFromBytes will return a Signal Ciphertext message from the given 19 | // bytes using the given serializer. 20 | func NewSenderKeyDistributionMessageFromBytes(serialized []byte, 21 | serializer SenderKeyDistributionMessageSerializer) (*SenderKeyDistributionMessage, error) { 22 | 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 NewSenderKeyDistributionMessageFromStruct(signalMessageStructure, serializer) 30 | } 31 | 32 | // NewSenderKeyDistributionMessageFromStruct returns a Signal Ciphertext message from the 33 | // given serializable structure. 34 | func NewSenderKeyDistributionMessageFromStruct(structure *SenderKeyDistributionMessageStructure, 35 | serializer SenderKeyDistributionMessageSerializer) (*SenderKeyDistributionMessage, 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.SigningKey == nil || structure.ChainKey == nil { 51 | err := "Incomplete message." 52 | return nil, errors.New(err) 53 | } 54 | 55 | // Get the signing key object from bytes. 56 | signingKey, err := ecc.DecodePoint(structure.SigningKey, 0) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | // Create the signal message object from the structure. 62 | message := &SenderKeyDistributionMessage{ 63 | id: structure.ID, 64 | iteration: structure.Iteration, 65 | chainKey: structure.ChainKey, 66 | version: structure.Version, 67 | signatureKey: signingKey, 68 | serializer: serializer, 69 | } 70 | 71 | // Generate the ECC key from bytes. 72 | message.signatureKey, err = ecc.DecodePoint(structure.SigningKey, 0) 73 | if err != nil { 74 | return nil, err 75 | } 76 | 77 | return message, nil 78 | } 79 | 80 | // NewSenderKeyDistributionMessage returns a Signal Ciphertext message. 81 | func NewSenderKeyDistributionMessage(id uint32, iteration uint32, 82 | chainKey []byte, signatureKey ecc.ECPublicKeyable, 83 | serializer SenderKeyDistributionMessageSerializer) *SenderKeyDistributionMessage { 84 | 85 | return &SenderKeyDistributionMessage{ 86 | id: id, 87 | iteration: iteration, 88 | chainKey: chainKey, 89 | signatureKey: signatureKey, 90 | serializer: serializer, 91 | } 92 | } 93 | 94 | // SenderKeyDistributionMessageStructure is a serializeable structure for senderkey 95 | // distribution messages. 96 | type SenderKeyDistributionMessageStructure struct { 97 | ID uint32 98 | Iteration uint32 99 | ChainKey []byte 100 | SigningKey []byte 101 | Version uint32 102 | } 103 | 104 | // SenderKeyDistributionMessage is a structure for senderkey distribution messages. 105 | type SenderKeyDistributionMessage struct { 106 | id uint32 107 | iteration uint32 108 | chainKey []byte 109 | version uint32 110 | signatureKey ecc.ECPublicKeyable 111 | serializer SenderKeyDistributionMessageSerializer 112 | } 113 | 114 | // ID will return the message's id. 115 | func (p *SenderKeyDistributionMessage) ID() uint32 { 116 | return p.id 117 | } 118 | 119 | // Iteration will return the message's iteration. 120 | func (p *SenderKeyDistributionMessage) Iteration() uint32 { 121 | return p.iteration 122 | } 123 | 124 | // ChainKey will return the message's chain key in bytes. 125 | func (p *SenderKeyDistributionMessage) ChainKey() []byte { 126 | return p.chainKey 127 | } 128 | 129 | // SignatureKey will return the message's signature public key 130 | func (p *SenderKeyDistributionMessage) SignatureKey() ecc.ECPublicKeyable { 131 | return p.signatureKey 132 | } 133 | 134 | // Serialize will use the given serializer and return the message as 135 | // bytes. 136 | func (p *SenderKeyDistributionMessage) Serialize() []byte { 137 | structure := &SenderKeyDistributionMessageStructure{ 138 | ID: p.id, 139 | Iteration: p.iteration, 140 | ChainKey: p.chainKey, 141 | SigningKey: p.signatureKey.Serialize(), 142 | Version: CurrentVersion, 143 | } 144 | return p.serializer.Serialize(structure) 145 | } 146 | 147 | // Type will return the message's type. 148 | func (p *SenderKeyDistributionMessage) Type() uint32 { 149 | return SENDERKEY_DISTRIBUTION_TYPE 150 | } 151 | -------------------------------------------------------------------------------- /protocol/SenderKeyMessage.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | 7 | "github.com/crossle/libsignal-protocol-go/ecc" 8 | "github.com/crossle/libsignal-protocol-go/util/bytehelper" 9 | ) 10 | 11 | // SenderKeyMessageSerializer is an interface for serializing and deserializing 12 | // SenderKeyMessages into bytes. An implementation of this interface should be 13 | // used to encode/decode the object into JSON, Protobuffers, etc. 14 | type SenderKeyMessageSerializer interface { 15 | Serialize(signalMessage *SenderKeyMessageStructure) []byte 16 | Deserialize(serialized []byte) (*SenderKeyMessageStructure, error) 17 | } 18 | 19 | // NewSenderKeyMessageFromBytes will return a Signal Ciphertext message from the given 20 | // bytes using the given serializer. 21 | func NewSenderKeyMessageFromBytes(serialized []byte, 22 | serializer SenderKeyMessageSerializer) (*SenderKeyMessage, error) { 23 | 24 | // Use the given serializer to decode the signal message. 25 | senderKeyMessageStructure, err := serializer.Deserialize(serialized) 26 | if err != nil { 27 | return nil, err 28 | } 29 | 30 | return NewSenderKeyMessageFromStruct(senderKeyMessageStructure, serializer) 31 | } 32 | 33 | // NewSenderKeyMessageFromStruct returns a Signal Ciphertext message from the 34 | // given serializable structure. 35 | func NewSenderKeyMessageFromStruct(structure *SenderKeyMessageStructure, 36 | serializer SenderKeyMessageSerializer) (*SenderKeyMessage, error) { 37 | 38 | // Throw an error if the given message structure is an unsupported version. 39 | if structure.Version <= UnsupportedVersion { 40 | err := "Legacy message: " + strconv.Itoa(int(structure.Version)) 41 | return nil, errors.New(err) 42 | } 43 | 44 | // Throw an error if the given message structure is a future version. 45 | if structure.Version > CurrentVersion { 46 | err := "Unknown version: " + strconv.Itoa(int(structure.Version)) 47 | return nil, errors.New(err) 48 | } 49 | 50 | // Throw an error if the structure is missing critical fields. 51 | if structure.CipherText == nil { 52 | err := "Incomplete message." 53 | return nil, errors.New(err) 54 | } 55 | 56 | // Create the signal message object from the structure. 57 | whisperMessage := &SenderKeyMessage{ 58 | keyID: structure.ID, 59 | version: structure.Version, 60 | iteration: structure.Iteration, 61 | ciphertext: structure.CipherText, 62 | signature: structure.Signature, 63 | serializer: serializer, 64 | } 65 | 66 | return whisperMessage, nil 67 | } 68 | 69 | // NewSenderKeyMessage returns a SenderKeyMessage. 70 | func NewSenderKeyMessage(keyID uint32, iteration uint32, ciphertext []byte, 71 | signatureKey ecc.ECPrivateKeyable, serializer SenderKeyMessageSerializer) *SenderKeyMessage { 72 | 73 | // Ensure we have a valid signature key 74 | if signatureKey == nil { 75 | panic("Signature is nil. Unable to sign new senderkey message.") 76 | } 77 | 78 | // Build our SenderKeyMessage. 79 | senderKeyMessage := &SenderKeyMessage{ 80 | keyID: keyID, 81 | iteration: iteration, 82 | ciphertext: ciphertext, 83 | version: CurrentVersion, 84 | serializer: serializer, 85 | } 86 | 87 | // Sign the serialized message and include it in the message. This will be included 88 | // in the signed serialized version of the message. 89 | signature := ecc.CalculateSignature(signatureKey, senderKeyMessage.Serialize()) 90 | senderKeyMessage.signature = bytehelper.ArrayToSlice64(signature) 91 | 92 | return senderKeyMessage 93 | } 94 | 95 | // SenderKeyMessageStructure is a serializeable structure for SenderKey messages. 96 | type SenderKeyMessageStructure struct { 97 | ID uint32 98 | Iteration uint32 99 | CipherText []byte 100 | Version uint32 101 | Signature []byte 102 | } 103 | 104 | // SenderKeyMessage is a structure for messages using senderkey groups. 105 | type SenderKeyMessage struct { 106 | version uint32 107 | keyID uint32 108 | iteration uint32 109 | ciphertext []byte 110 | signature []byte 111 | serializer SenderKeyMessageSerializer 112 | } 113 | 114 | // KeyID returns the SenderKeyMessage key ID. 115 | func (p *SenderKeyMessage) KeyID() uint32 { 116 | return p.keyID 117 | } 118 | 119 | // Iteration returns the SenderKeyMessage iteration. 120 | func (p *SenderKeyMessage) Iteration() uint32 { 121 | return p.iteration 122 | } 123 | 124 | // Ciphertext returns the SenderKeyMessage encrypted ciphertext. 125 | func (p *SenderKeyMessage) Ciphertext() []byte { 126 | return p.ciphertext 127 | } 128 | 129 | // Version returns the Signal message version of the message. 130 | func (p *SenderKeyMessage) Version() uint32 { 131 | return p.version 132 | } 133 | 134 | // Serialize will use the given serializer to return the message as bytes 135 | // excluding the signature. This should be used for signing and verifying 136 | // message signatures. 137 | func (p *SenderKeyMessage) Serialize() []byte { 138 | structure := &SenderKeyMessageStructure{ 139 | ID: p.keyID, 140 | Iteration: p.iteration, 141 | CipherText: p.ciphertext, 142 | Version: p.version, 143 | } 144 | 145 | return p.serializer.Serialize(structure) 146 | } 147 | 148 | // SignedSerialize will use the given serializer to return the message as 149 | // bytes with the message signature included. This should be used when 150 | // sending the message over the network. 151 | func (p *SenderKeyMessage) SignedSerialize() []byte { 152 | structure := &SenderKeyMessageStructure{ 153 | ID: p.keyID, 154 | Iteration: p.iteration, 155 | CipherText: p.ciphertext, 156 | Version: p.version, 157 | Signature: p.signature, 158 | } 159 | 160 | return p.serializer.Serialize(structure) 161 | } 162 | 163 | // Signature returns the SenderKeyMessage signature 164 | func (p *SenderKeyMessage) Signature() [64]byte { 165 | return bytehelper.SliceToArray64(p.signature) 166 | } 167 | 168 | // Type returns the sender key type. 169 | func (p *SenderKeyMessage) Type() uint32 { 170 | return SENDERKEY_TYPE 171 | } 172 | -------------------------------------------------------------------------------- /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 | "strconv" 8 | 9 | "github.com/crossle/libsignal-protocol-go/ecc" 10 | "github.com/crossle/libsignal-protocol-go/keys/identity" 11 | "github.com/crossle/libsignal-protocol-go/logger" 12 | "github.com/crossle/libsignal-protocol-go/util/bytehelper" 13 | ) 14 | 15 | const MacLength int = 8 16 | 17 | // SignalMessageSerializer is an interface for serializing and deserializing 18 | // SignalMessages into bytes. An implementation of this interface should be 19 | // used to encode/decode the object into JSON, Protobuffers, etc. 20 | type SignalMessageSerializer interface { 21 | Serialize(signalMessage *SignalMessageStructure) []byte 22 | Deserialize(serialized []byte) (*SignalMessageStructure, error) 23 | } 24 | 25 | // NewSignalMessageFromBytes will return a Signal Ciphertext message from the given 26 | // bytes using the given serializer. 27 | func NewSignalMessageFromBytes(serialized []byte, serializer SignalMessageSerializer) (*SignalMessage, error) { 28 | // Use the given serializer to decode the signal message. 29 | signalMessageStructure, err := serializer.Deserialize(serialized) 30 | if err != nil { 31 | return nil, err 32 | } 33 | 34 | return NewSignalMessageFromStruct(signalMessageStructure, serializer) 35 | } 36 | 37 | // NewSignalMessageFromStruct returns a Signal Ciphertext message from the 38 | // given serializable structure. 39 | func NewSignalMessageFromStruct(structure *SignalMessageStructure, serializer SignalMessageSerializer) (*SignalMessage, error) { 40 | // Throw an error if the given message structure is an unsupported version. 41 | if structure.Version <= UnsupportedVersion { 42 | err := "Legacy message: " + strconv.Itoa(structure.Version) 43 | return nil, errors.New(err) 44 | } 45 | 46 | // Throw an error if the given message structure is a future version. 47 | if structure.Version > CurrentVersion { 48 | err := "Unknown version: " + strconv.Itoa(structure.Version) 49 | return nil, errors.New(err) 50 | } 51 | 52 | // Throw an error if the structure is missing critical fields. 53 | if structure.CipherText == nil || structure.RatchetKey == nil { 54 | err := "Incomplete message." 55 | return nil, errors.New(err) 56 | } 57 | 58 | // Create the signal message object from the structure. 59 | whisperMessage := &SignalMessage{structure: *structure, serializer: serializer} 60 | 61 | // Generate the ECC key from bytes. 62 | var err error 63 | whisperMessage.senderRatchetKey, err = ecc.DecodePoint(structure.RatchetKey, 0) 64 | if err != nil { 65 | return nil, err 66 | } 67 | 68 | return whisperMessage, nil 69 | } 70 | 71 | // NewSignalMessage returns a Signal Ciphertext message. 72 | func NewSignalMessage(messageVersion int, counter, previousCounter uint32, macKey []byte, 73 | senderRatchetKey ecc.ECPublicKeyable, ciphertext []byte, senderIdentityKey, 74 | receiverIdentityKey *identity.Key, serializer SignalMessageSerializer) (*SignalMessage, error) { 75 | 76 | version := []byte(strconv.Itoa(messageVersion)) 77 | // Build the signal message structure with the given data. 78 | structure := &SignalMessageStructure{ 79 | Counter: counter, 80 | PreviousCounter: previousCounter, 81 | RatchetKey: senderRatchetKey.Serialize(), 82 | CipherText: ciphertext, 83 | } 84 | 85 | serialized := append(version, serializer.Serialize(structure)...) 86 | // Get the message authentication code from the serialized structure. 87 | mac, err := getMac( 88 | messageVersion, senderIdentityKey, receiverIdentityKey, 89 | macKey, serialized, 90 | ) 91 | if err != nil { 92 | return nil, err 93 | } 94 | structure.Mac = mac 95 | structure.Version = messageVersion 96 | 97 | // Generate a SignalMessage with the structure. 98 | whisperMessage, err := NewSignalMessageFromStruct(structure, serializer) 99 | if err != nil { 100 | return nil, err 101 | } 102 | 103 | return whisperMessage, nil 104 | } 105 | 106 | // SignalMessageStructure is a serializeable structure of a signal message 107 | // object. 108 | type SignalMessageStructure struct { 109 | RatchetKey []byte 110 | Counter uint32 111 | PreviousCounter uint32 112 | CipherText []byte 113 | Version int 114 | Mac []byte 115 | } 116 | 117 | // SignalMessage is a cipher message that contains a message encrypted 118 | // with the Signal protocol. 119 | type SignalMessage struct { 120 | structure SignalMessageStructure 121 | senderRatchetKey ecc.ECPublicKeyable 122 | serializer SignalMessageSerializer 123 | } 124 | 125 | // SenderRatchetKey returns the SignalMessage's sender ratchet key. This 126 | // key is used for ratcheting the chain forward to negotiate a new shared 127 | // secret that cannot be derived from previous chains. 128 | func (s *SignalMessage) SenderRatchetKey() ecc.ECPublicKeyable { 129 | return s.senderRatchetKey 130 | } 131 | 132 | // MessageVersion returns the message version this SignalMessage supports. 133 | func (s *SignalMessage) MessageVersion() int { 134 | return s.structure.Version 135 | } 136 | 137 | // Counter will return the SignalMessage counter. 138 | func (s *SignalMessage) Counter() uint32 { 139 | return s.structure.Counter 140 | } 141 | 142 | // Body will return the SignalMessage's ciphertext in bytes. 143 | func (s *SignalMessage) Body() []byte { 144 | return s.structure.CipherText 145 | } 146 | 147 | // VerifyMac will return an error if the message's message authentication code 148 | // is invalid. This should be used on SignalMessages that have been constructed 149 | // from a sent message. 150 | func (s *SignalMessage) VerifyMac(messageVersion int, senderIdentityKey, 151 | receiverIdentityKey *identity.Key, macKey []byte) error { 152 | 153 | // Create a copy of the message without the mac. We'll use this to calculate 154 | // the message authentication code. 155 | structure := s.structure 156 | signalMessage, err := NewSignalMessageFromStruct(&structure, s.serializer) 157 | if err != nil { 158 | return err 159 | } 160 | signalMessage.structure.Mac = nil 161 | signalMessage.structure.Version = 0 162 | version := []byte(strconv.Itoa(s.MessageVersion())) 163 | serialized := append(version, signalMessage.Serialize()...) 164 | 165 | // Calculate the message authentication code from the serialized structure. 166 | ourMac, err := getMac( 167 | messageVersion, 168 | senderIdentityKey, 169 | receiverIdentityKey, 170 | macKey, 171 | serialized, 172 | ) 173 | if err != nil { 174 | logger.Error(err) 175 | return err 176 | } 177 | 178 | // Get the message authentication code that was sent to us as part of 179 | // the signal message structure. 180 | theirMac := s.structure.Mac 181 | 182 | logger.Debug("Verifying macs...") 183 | logger.Debug(" Our MAC: ", ourMac) 184 | logger.Debug(" Their MAC: ", theirMac) 185 | 186 | // Return an error if our calculated mac doesn't match the mac sent to us. 187 | if !hmac.Equal(ourMac, theirMac) { 188 | return errors.New("Bad Mac!") 189 | } 190 | 191 | return nil 192 | } 193 | 194 | // Serialize will return the Signal Message as bytes. 195 | func (s *SignalMessage) Serialize() []byte { 196 | return s.serializer.Serialize(&s.structure) 197 | } 198 | 199 | // Structure will return a serializeable structure of the Signal Message. 200 | func (s *SignalMessage) Structure() *SignalMessageStructure { 201 | structure := s.structure 202 | return &structure 203 | } 204 | 205 | // Type will return the type of Signal Message this is. 206 | func (s *SignalMessage) Type() uint32 { 207 | return WHISPER_TYPE 208 | } 209 | 210 | // getMac will calculate the mac using the given message version, identity 211 | // keys, macKey and SignalMessageStructure. The MAC key is a private key held 212 | // by both parties that is concatenated with the message and hashed. 213 | func getMac(messageVersion int, senderIdentityKey, receiverIdentityKey *identity.Key, 214 | macKey, serialized []byte) ([]byte, error) { 215 | 216 | mac := hmac.New(sha256.New, macKey[:]) 217 | 218 | if messageVersion >= 3 { 219 | mac.Write(senderIdentityKey.PublicKey().Serialize()) 220 | mac.Write(receiverIdentityKey.PublicKey().Serialize()) 221 | } 222 | 223 | mac.Write(serialized) 224 | 225 | fullMac := mac.Sum(nil) 226 | 227 | return bytehelper.Trim(fullMac, MacLength), nil 228 | } 229 | -------------------------------------------------------------------------------- /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 fmt.Sprintf("%s%s%d", s.name, ADDRESS_SEPARATOR, s.deviceID) 38 | } 39 | -------------------------------------------------------------------------------- /provision/ProvisioningCipher.go: -------------------------------------------------------------------------------- 1 | package provision 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha256" 6 | "encoding/base64" 7 | "encoding/json" 8 | "fmt" 9 | 10 | "github.com/crossle/libsignal-protocol-go/cipher" 11 | "github.com/crossle/libsignal-protocol-go/ecc" 12 | 13 | "github.com/crossle/libsignal-protocol-go/kdf" 14 | "github.com/crossle/libsignal-protocol-go/keys/root" 15 | "github.com/crossle/libsignal-protocol-go/util/bytehelper" 16 | ) 17 | 18 | type ProvisionMessage struct { 19 | IdentityKeyPublic []byte `json:"identity_key_public"` 20 | IdentityKeyPrivate []byte `json:"identity_key_private"` 21 | UserId string `json:"user_id"` 22 | ProvisioningCode string `json:"provisioning_code"` 23 | ProfileKey []byte `json:"profile_key"` 24 | } 25 | 26 | type ProvisionEnvelope struct { 27 | PublicKey []byte `json:"public_key"` 28 | Body []byte `json:"body"` 29 | } 30 | 31 | func verifyMAC(key, input, mac []byte) bool { 32 | m := hmac.New(sha256.New, key) 33 | m.Write(input) 34 | return hmac.Equal(m.Sum(nil), mac) 35 | } 36 | 37 | func Decrypt(privateKey string, content string) (string, error) { 38 | ourPrivateKey, err := base64.StdEncoding.DecodeString(privateKey) 39 | if err != nil { 40 | return "", err 41 | } 42 | envelopeDecode, err := base64.StdEncoding.DecodeString(content) 43 | if err != nil { 44 | return "", err 45 | } 46 | 47 | var envelope ProvisionEnvelope 48 | if err := json.Unmarshal(envelopeDecode, &envelope); err != nil { 49 | return "", err 50 | } 51 | 52 | publicKeyable, _ := ecc.DecodePoint(envelope.PublicKey, 0) 53 | masterEphemeral := publicKeyable.PublicKey() 54 | message := envelope.Body 55 | if message[0] != 1 { 56 | return "", fmt.Errorf("Bad version number on ProvisioningMessage %s", err.Error()) 57 | } 58 | 59 | iv := message[1 : 16+1] 60 | mac := message[len(message)-32:] 61 | ivAndCiphertext := message[0 : len(message)-32] 62 | cipherText := message[16+1 : len(message)-32] 63 | 64 | sharedSecret := kdf.CalculateSharedSecret(masterEphemeral, bytehelper.SliceToArray(ourPrivateKey)) 65 | derivedSecretBytes, err := kdf.DeriveSecrets(sharedSecret[:], nil, []byte("Mixin Provisioning Message"), root.DerivedSecretsSize) 66 | if err != nil { 67 | fmt.Println(err) 68 | return "", err 69 | } 70 | aesKey := derivedSecretBytes[:32] 71 | macKey := derivedSecretBytes[32:] 72 | 73 | if !verifyMAC(macKey, ivAndCiphertext, mac) { 74 | return "", fmt.Errorf("Verify Mac failed") 75 | } 76 | plaintext, err := cipher.DecryptCbc(iv, aesKey, cipherText) 77 | if err != nil { 78 | return "", err 79 | } 80 | return string(plaintext), nil 81 | } 82 | -------------------------------------------------------------------------------- /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 | 9 | "github.com/crossle/libsignal-protocol-go/ecc" 10 | "github.com/crossle/libsignal-protocol-go/kdf" 11 | "github.com/crossle/libsignal-protocol-go/keys/chain" 12 | "github.com/crossle/libsignal-protocol-go/keys/root" 13 | "github.com/crossle/libsignal-protocol-go/keys/session" 14 | ) 15 | 16 | var b64 = base64.StdEncoding.EncodeToString 17 | 18 | func genDiscontinuity() [32]byte { 19 | var discontinuity [32]byte 20 | for i := range discontinuity { 21 | discontinuity[i] = 0xFF 22 | } 23 | return discontinuity 24 | } 25 | 26 | // CalculateSenderSession calculates the key agreement for a recipient. This 27 | // should be used when we are trying to send a message to someone for the 28 | // first time. 29 | func CalculateSenderSession(parameters *SenderParameters) (*session.KeyPair, error) { 30 | var secret [32]byte 31 | var publicKey [32]byte 32 | var privateKey [32]byte 33 | masterSecret := []byte{} // Create a master shared secret that is 5 different 32-byte values 34 | discontinuity := genDiscontinuity() 35 | masterSecret = append(masterSecret, discontinuity[:]...) 36 | 37 | // Calculate the agreement using their signed prekey and our identity key. 38 | publicKey = parameters.TheirSignedPreKey().PublicKey() 39 | privateKey = parameters.OurIdentityKey().PrivateKey().Serialize() 40 | secret = kdf.CalculateSharedSecret( 41 | publicKey, 42 | privateKey, 43 | ) 44 | masterSecret = append(masterSecret, secret[:]...) 45 | 46 | // Calculate the agreement using their identity key and our base key. 47 | publicKey = parameters.TheirIdentityKey().PublicKey().PublicKey() 48 | privateKey = parameters.OurBaseKey().PrivateKey().Serialize() 49 | secret = kdf.CalculateSharedSecret( 50 | publicKey, 51 | privateKey, 52 | ) 53 | masterSecret = append(masterSecret, secret[:]...) 54 | 55 | // Calculate the agreement using their signed prekey and our base key. 56 | publicKey = parameters.TheirSignedPreKey().PublicKey() 57 | privateKey = parameters.OurBaseKey().PrivateKey().Serialize() 58 | secret = kdf.CalculateSharedSecret( 59 | publicKey, 60 | privateKey, 61 | ) 62 | masterSecret = append(masterSecret, secret[:]...) 63 | 64 | // If they have a one-time prekey, use it to calculate the shared secret with their 65 | // one time key and our base key. 66 | if parameters.TheirOneTimePreKey() != nil { 67 | publicKey = parameters.TheirOneTimePreKey().PublicKey() 68 | privateKey = parameters.OurBaseKey().PrivateKey().Serialize() 69 | secret = kdf.CalculateSharedSecret( 70 | publicKey, 71 | privateKey, 72 | ) 73 | masterSecret = append(masterSecret, secret[:]...) 74 | 75 | } 76 | 77 | // Derive the root and chain keys based on the master secret. 78 | derivedKeysBytes, err := kdf.DeriveSecrets(masterSecret, nil, []byte("WhisperText"), root.DerivedSecretsSize) 79 | if err != nil { 80 | return nil, err 81 | } 82 | derivedKeys := session.NewDerivedSecrets(derivedKeysBytes) 83 | chainKey := chain.NewKey(kdf.DeriveSecrets, derivedKeys.ChainKey(), 0) 84 | rootKey := root.NewKey(kdf.DeriveSecrets, derivedKeys.RootKey()) 85 | 86 | // Add the root and chain keys to a structure that will hold both keys. 87 | sessionKeys := session.NewKeyPair(rootKey, chainKey) 88 | 89 | return sessionKeys, nil 90 | } 91 | 92 | // CalculateReceiverSession calculates the key agreement for a sender. This should 93 | // be used when we are receiving a message from someone for the first time. 94 | func CalculateReceiverSession(parameters *ReceiverParameters) (*session.KeyPair, error) { 95 | var secret [32]byte 96 | var publicKey [32]byte 97 | var privateKey [32]byte 98 | masterSecret := []byte{} // Create a master shared secret that is 5 different 32-byte values 99 | 100 | discontinuity := genDiscontinuity() 101 | masterSecret = append(masterSecret, discontinuity[:]...) 102 | 103 | // Calculate the agreement using their identity key and our signed pre key. 104 | publicKey = parameters.TheirIdentityKey().PublicKey().PublicKey() 105 | privateKey = parameters.OurSignedPreKey().PrivateKey().Serialize() 106 | secret = kdf.CalculateSharedSecret( 107 | publicKey, 108 | privateKey, 109 | ) 110 | masterSecret = append(masterSecret, secret[:]...) 111 | 112 | // Calculate the agreement using their base key and our identity key. 113 | publicKey = parameters.TheirBaseKey().PublicKey() 114 | privateKey = parameters.OurIdentityKeyPair().PrivateKey().Serialize() 115 | secret = kdf.CalculateSharedSecret( 116 | publicKey, 117 | privateKey, 118 | ) 119 | masterSecret = append(masterSecret, secret[:]...) 120 | 121 | // Calculate the agreement using their base key and our signed prekey. 122 | publicKey = parameters.TheirBaseKey().PublicKey() 123 | privateKey = parameters.OurSignedPreKey().PrivateKey().Serialize() 124 | secret = kdf.CalculateSharedSecret( 125 | publicKey, 126 | privateKey, 127 | ) 128 | masterSecret = append(masterSecret, secret[:]...) 129 | 130 | // If we had a one-time prekey, use it to calculate the shared secret with our 131 | // one time key and their base key. 132 | if parameters.OurOneTimePreKey() != nil { 133 | publicKey = parameters.TheirBaseKey().PublicKey() 134 | privateKey = parameters.OurOneTimePreKey().PrivateKey().Serialize() 135 | secret = kdf.CalculateSharedSecret( 136 | publicKey, 137 | privateKey, 138 | ) 139 | masterSecret = append(masterSecret, secret[:]...) 140 | 141 | } 142 | 143 | // Derive the root and chain keys based on the master secret. 144 | derivedKeysBytes, err := kdf.DeriveSecrets(masterSecret, nil, []byte("WhisperText"), root.DerivedSecretsSize) 145 | if err != nil { 146 | return nil, err 147 | } 148 | derivedKeys := session.NewDerivedSecrets(derivedKeysBytes) 149 | chainKey := chain.NewKey(kdf.DeriveSecrets, derivedKeys.ChainKey(), 0) 150 | rootKey := root.NewKey(kdf.DeriveSecrets, derivedKeys.RootKey()) 151 | 152 | // Add the root and chain keys to a structure that will hold both keys. 153 | sessionKeys := session.NewKeyPair(rootKey, chainKey) 154 | 155 | return sessionKeys, nil 156 | } 157 | 158 | // CalculateSymmetricSession calculates the key agreement between two users. This 159 | // works by both clients exchanging KeyExchange messages to first establish a session. 160 | // This is useful for establishing a session if both users are online. 161 | func CalculateSymmetricSession(parameters *SymmetricParameters) (*session.KeyPair, error) { 162 | // Compare the base public keys so we can deterministically know whether we should 163 | // be setting up a sender or receiver session. If our key converted to an integer is 164 | // less than the other user's, act as a sender. 165 | if isSender(parameters.OurBaseKey.PublicKey(), parameters.TheirBaseKey) { 166 | senderParameters := &SenderParameters{ 167 | ourBaseKey: parameters.OurBaseKey, 168 | ourIdentityKeyPair: parameters.OurIdentityKeyPair, 169 | theirRatchetKey: parameters.TheirRatchetKey, 170 | theirIdentityKey: parameters.TheirIdentityKey, 171 | theirSignedPreKey: parameters.TheirBaseKey, 172 | } 173 | 174 | return CalculateSenderSession(senderParameters) 175 | } 176 | 177 | // If our base public key was larger than the other user's, act as a receiver. 178 | receiverParameters := &ReceiverParameters{ 179 | ourIdentityKeyPair: parameters.OurIdentityKeyPair, 180 | ourRatchetKey: parameters.OurRatchetKey, 181 | ourSignedPreKey: parameters.OurBaseKey, 182 | theirBaseKey: parameters.TheirBaseKey, 183 | theirIdentityKey: parameters.TheirIdentityKey, 184 | } 185 | 186 | return CalculateReceiverSession(receiverParameters) 187 | } 188 | 189 | // isSender is a private method for determining if a symmetric session should 190 | // be calculated as the sender or receiver. It does so by converting the given 191 | // keys into integers and comparing the size of those integers. 192 | func isSender(ourKey, theirKey ecc.ECPublicKeyable) bool { 193 | ourKeyInt := binary.BigEndian.Uint32(ourKey.Serialize()) 194 | theirKeyInt := binary.BigEndian.Uint32(theirKey.Serialize()) 195 | 196 | return ourKeyInt < theirKeyInt 197 | } 198 | -------------------------------------------------------------------------------- /ratchet/ReceiverParameters.go: -------------------------------------------------------------------------------- 1 | package ratchet 2 | 3 | import ( 4 | "github.com/crossle/libsignal-protocol-go/ecc" 5 | "github.com/crossle/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/crossle/libsignal-protocol-go/ecc" 5 | "github.com/crossle/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/crossle/libsignal-protocol-go/ecc" 5 | "github.com/crossle/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/FingerprintProtocol.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: FingerprintProtocol.proto 3 | 4 | package serialize 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | math "math" 10 | ) 11 | 12 | // Reference imports to suppress errors if they are not otherwise used. 13 | var _ = proto.Marshal 14 | var _ = fmt.Errorf 15 | var _ = math.Inf 16 | 17 | // This is a compile-time assertion to ensure that this generated file 18 | // is compatible with the proto package it is being compiled against. 19 | // A compilation error at this line likely means your copy of the 20 | // proto package needs to be updated. 21 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 22 | 23 | type LogicalFingerprint struct { 24 | Content []byte `protobuf:"bytes,1,opt,name=content" json:"content,omitempty"` 25 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 26 | XXX_unrecognized []byte `json:"-"` 27 | XXX_sizecache int32 `json:"-"` 28 | } 29 | 30 | func (m *LogicalFingerprint) Reset() { *m = LogicalFingerprint{} } 31 | func (m *LogicalFingerprint) String() string { return proto.CompactTextString(m) } 32 | func (*LogicalFingerprint) ProtoMessage() {} 33 | func (*LogicalFingerprint) Descriptor() ([]byte, []int) { 34 | return fileDescriptor_98263e7002f8d799, []int{0} 35 | } 36 | 37 | func (m *LogicalFingerprint) XXX_Unmarshal(b []byte) error { 38 | return xxx_messageInfo_LogicalFingerprint.Unmarshal(m, b) 39 | } 40 | func (m *LogicalFingerprint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 41 | return xxx_messageInfo_LogicalFingerprint.Marshal(b, m, deterministic) 42 | } 43 | func (m *LogicalFingerprint) XXX_Merge(src proto.Message) { 44 | xxx_messageInfo_LogicalFingerprint.Merge(m, src) 45 | } 46 | func (m *LogicalFingerprint) XXX_Size() int { 47 | return xxx_messageInfo_LogicalFingerprint.Size(m) 48 | } 49 | func (m *LogicalFingerprint) XXX_DiscardUnknown() { 50 | xxx_messageInfo_LogicalFingerprint.DiscardUnknown(m) 51 | } 52 | 53 | var xxx_messageInfo_LogicalFingerprint proto.InternalMessageInfo 54 | 55 | func (m *LogicalFingerprint) GetContent() []byte { 56 | if m != nil { 57 | return m.Content 58 | } 59 | return nil 60 | } 61 | 62 | type CombinedFingerprints struct { 63 | Version *uint32 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"` 64 | LocalFingerprint *LogicalFingerprint `protobuf:"bytes,2,opt,name=localFingerprint" json:"localFingerprint,omitempty"` 65 | RemoteFingerprint *LogicalFingerprint `protobuf:"bytes,3,opt,name=remoteFingerprint" json:"remoteFingerprint,omitempty"` 66 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 67 | XXX_unrecognized []byte `json:"-"` 68 | XXX_sizecache int32 `json:"-"` 69 | } 70 | 71 | func (m *CombinedFingerprints) Reset() { *m = CombinedFingerprints{} } 72 | func (m *CombinedFingerprints) String() string { return proto.CompactTextString(m) } 73 | func (*CombinedFingerprints) ProtoMessage() {} 74 | func (*CombinedFingerprints) Descriptor() ([]byte, []int) { 75 | return fileDescriptor_98263e7002f8d799, []int{1} 76 | } 77 | 78 | func (m *CombinedFingerprints) XXX_Unmarshal(b []byte) error { 79 | return xxx_messageInfo_CombinedFingerprints.Unmarshal(m, b) 80 | } 81 | func (m *CombinedFingerprints) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 82 | return xxx_messageInfo_CombinedFingerprints.Marshal(b, m, deterministic) 83 | } 84 | func (m *CombinedFingerprints) XXX_Merge(src proto.Message) { 85 | xxx_messageInfo_CombinedFingerprints.Merge(m, src) 86 | } 87 | func (m *CombinedFingerprints) XXX_Size() int { 88 | return xxx_messageInfo_CombinedFingerprints.Size(m) 89 | } 90 | func (m *CombinedFingerprints) XXX_DiscardUnknown() { 91 | xxx_messageInfo_CombinedFingerprints.DiscardUnknown(m) 92 | } 93 | 94 | var xxx_messageInfo_CombinedFingerprints proto.InternalMessageInfo 95 | 96 | func (m *CombinedFingerprints) GetVersion() uint32 { 97 | if m != nil && m.Version != nil { 98 | return *m.Version 99 | } 100 | return 0 101 | } 102 | 103 | func (m *CombinedFingerprints) GetLocalFingerprint() *LogicalFingerprint { 104 | if m != nil { 105 | return m.LocalFingerprint 106 | } 107 | return nil 108 | } 109 | 110 | func (m *CombinedFingerprints) GetRemoteFingerprint() *LogicalFingerprint { 111 | if m != nil { 112 | return m.RemoteFingerprint 113 | } 114 | return nil 115 | } 116 | 117 | func init() { 118 | proto.RegisterType((*LogicalFingerprint)(nil), "serialize.LogicalFingerprint") 119 | proto.RegisterType((*CombinedFingerprints)(nil), "serialize.CombinedFingerprints") 120 | } 121 | 122 | func init() { proto.RegisterFile("FingerprintProtocol.proto", fileDescriptor_98263e7002f8d799) } 123 | 124 | var fileDescriptor_98263e7002f8d799 = []byte{ 125 | // 208 bytes of a gzipped FileDescriptorProto 126 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x74, 0xcb, 0xcc, 0x4b, 127 | 0x4f, 0x2d, 0x2a, 0x28, 0xca, 0xcc, 0x2b, 0x09, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0xce, 0xcf, 0xd1, 128 | 0x2b, 0x00, 0x31, 0x84, 0x38, 0x8b, 0x53, 0x8b, 0x32, 0x13, 0x73, 0x32, 0xab, 0x52, 0x95, 0xf4, 129 | 0xb8, 0x84, 0x7c, 0xf2, 0xd3, 0x33, 0x93, 0x13, 0x73, 0x90, 0x94, 0x0b, 0x49, 0x70, 0xb1, 0x27, 130 | 0xe7, 0xe7, 0x95, 0xa4, 0xe6, 0x95, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0xf0, 0x04, 0xc1, 0xb8, 0x4a, 131 | 0x27, 0x18, 0xb9, 0x44, 0x9c, 0xf3, 0x73, 0x93, 0x32, 0xf3, 0x52, 0x53, 0x90, 0x74, 0x14, 0x83, 132 | 0xb4, 0x94, 0xa5, 0x16, 0x15, 0x67, 0xe6, 0xe7, 0x81, 0xb5, 0xf0, 0x06, 0xc1, 0xb8, 0x42, 0x9e, 133 | 0x5c, 0x02, 0x39, 0xf9, 0xa8, 0x16, 0x48, 0x30, 0x29, 0x30, 0x6a, 0x70, 0x1b, 0xc9, 0xea, 0xc1, 134 | 0x1d, 0xa2, 0x87, 0xe9, 0x8a, 0x20, 0x0c, 0x6d, 0x42, 0xde, 0x5c, 0x82, 0x45, 0xa9, 0xb9, 0xf9, 135 | 0x25, 0xa9, 0xc8, 0x66, 0x31, 0x13, 0x63, 0x16, 0xa6, 0x3e, 0x27, 0x5b, 0x2e, 0x8d, 0xfc, 0xa2, 136 | 0x74, 0xbd, 0xf2, 0x8c, 0xcc, 0xe2, 0x82, 0xd4, 0xa2, 0xe2, 0xca, 0xe2, 0x92, 0xd4, 0xdc, 0x62, 137 | 0xbd, 0x9c, 0xcc, 0xa4, 0xe2, 0xcc, 0xf4, 0xbc, 0xc4, 0x1c, 0xbd, 0x34, 0x24, 0xb5, 0x82, 0xe8, 138 | 0x81, 0x59, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x98, 0x79, 0x86, 0x60, 0x01, 0x00, 0x00, 139 | } 140 | -------------------------------------------------------------------------------- /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/crossle/libsignal-protocol-go/groups/state/record" 7 | "github.com/crossle/libsignal-protocol-go/protocol" 8 | "github.com/crossle/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 | -------------------------------------------------------------------------------- /state/record/ChainState.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/crossle/libsignal-protocol-go/ecc" 5 | "github.com/crossle/libsignal-protocol-go/kdf" 6 | "github.com/crossle/libsignal-protocol-go/keys/chain" 7 | "github.com/crossle/libsignal-protocol-go/keys/message" 8 | "github.com/crossle/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/crossle/libsignal-protocol-go/ecc" 5 | "github.com/crossle/libsignal-protocol-go/keys/identity" 6 | "github.com/crossle/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/crossle/libsignal-protocol-go/ecc" 5 | "github.com/crossle/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 | if p != nil { 55 | return &PendingPreKeyStructure{ 56 | PreKeyID: p.preKeyID, 57 | SignedPreKeyID: p.signedPreKeyID, 58 | BaseKey: p.baseKey.Serialize(), 59 | } 60 | } 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /state/record/PreKeyRecord.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/crossle/libsignal-protocol-go/ecc" 5 | "github.com/crossle/libsignal-protocol-go/util/bytehelper" 6 | "github.com/crossle/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 && (bytes.Compare(senderBaseKey, r.sessionState.SenderBaseKey()) == 0) { 134 | return true 135 | } 136 | 137 | // Loop through all of our previous states and see if this 138 | // exists in our state. 139 | for i := range r.previousStates { 140 | if r.previousStates[i].Version() == version && bytes.Compare(senderBaseKey, r.previousStates[i].SenderBaseKey()) == 0 { 141 | return true 142 | } 143 | } 144 | 145 | return false 146 | } 147 | 148 | // ArchiveCurrentState moves the current session state into the list 149 | // of "previous" session states, and replaces the current session state 150 | // with a fresh reset instance. 151 | func (r *Session) ArchiveCurrentState() { 152 | r.PromoteState(NewState(r.sessionState.serializer)) 153 | } 154 | 155 | // PromoteState takes the given session state and replaces it with the 156 | // current state, pushing the previous current state to "previousStates". 157 | func (r *Session) PromoteState(promotedState *State) { 158 | r.previousStates = r.prependStates(r.previousStates, r.sessionState) 159 | r.sessionState = promotedState 160 | 161 | // Remove the last state if it has reached our maximum length 162 | if len(r.previousStates) > archivedStatesMaxLength { 163 | r.previousStates = r.removeLastState(r.previousStates) 164 | } 165 | } 166 | 167 | // Serialize will return the session as serialized bytes so it can be 168 | // persistently stored. 169 | func (r *Session) Serialize() []byte { 170 | return r.serializer.Serialize(r.structure()) 171 | } 172 | 173 | // prependStates takes an array/slice of states and prepends it with 174 | // the given session state. 175 | func (r *Session) prependStates(states []*State, sessionState *State) []*State { 176 | return append([]*State{sessionState}, states...) 177 | } 178 | 179 | // removeLastState takes an array/slice of states and removes the 180 | // last element from it. 181 | func (r *Session) removeLastState(states []*State) []*State { 182 | return states[:len(states)-1] 183 | } 184 | 185 | // structure will return a simple serializable session structure 186 | // from the given structure. This is used for serialization to persistently 187 | // store a session record. 188 | func (r *Session) structure() *SessionStructure { 189 | previousStates := make([]*StateStructure, len(r.previousStates)) 190 | for i := range r.previousStates { 191 | previousStates[i] = r.previousStates[i].structure() 192 | } 193 | return &SessionStructure{ 194 | SessionState: r.sessionState.structure(), 195 | PreviousStates: previousStates, 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /state/record/SignedPreKeyRecord.go: -------------------------------------------------------------------------------- 1 | package record 2 | 3 | import ( 4 | "github.com/crossle/libsignal-protocol-go/ecc" 5 | "github.com/crossle/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/crossle/libsignal-protocol-go/ecc" 5 | "github.com/crossle/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/crossle/libsignal-protocol-go/keys/identity" 5 | "github.com/crossle/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/crossle/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/crossle/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/crossle/libsignal-protocol-go/protocol" 5 | "github.com/crossle/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/crossle/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/crossle/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 | "testing" 6 | 7 | "github.com/crossle/libsignal-protocol-go/fingerprint" 8 | ) 9 | 10 | // TestFingerprint will test printing key fingerprints. 11 | func TestFingerprint(t *testing.T) { 12 | 13 | // Create a serializer object that will be used to encode/decode data. 14 | serializer := newSerializer() 15 | 16 | // Create our users who will talk to each other. 17 | alice := newUser("Alice", 1, serializer) 18 | bob := newUser("Bob", 2, serializer) 19 | 20 | fp := fingerprint.NewDisplay( 21 | alice.identityKeyPair.PublicKey().Serialize(), 22 | bob.identityKeyPair.PublicKey().Serialize(), 23 | ) 24 | 25 | fmt.Println(fp.DisplayText()) 26 | 27 | } 28 | -------------------------------------------------------------------------------- /tests/identity_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/crossle/libsignal-protocol-go/ecc" 7 | "github.com/crossle/libsignal-protocol-go/logger" 8 | "github.com/crossle/libsignal-protocol-go/util/keyhelper" 9 | ) 10 | 11 | // TestIdentityKeys checks generating, signing, and verifying of identity keys. 12 | func TestIdentityKeys(t *testing.T) { 13 | logger.Info("Testing identity key generation...") 14 | 15 | // Generate an identity keypair 16 | identityKeyPair, err := keyhelper.GenerateIdentityKeyPair() 17 | if err != nil { 18 | t.Error("Error generating identity keys") 19 | } 20 | privateKey := identityKeyPair.PrivateKey() 21 | publicKey := identityKeyPair.PublicKey() 22 | logger.Info(" Identity KeyPair:", identityKeyPair) 23 | 24 | // Sign the text "Hello" with the identity key 25 | message := []byte("Hello") 26 | unsignedMessage := []byte("SHIT!") 27 | logger.Info("Signing bytes:", message) 28 | signature := ecc.CalculateSignature(privateKey, message) 29 | logger.Info(" Signature:", signature) 30 | 31 | // Validate the signature using the private key 32 | //valid := ecc.Verify(publicKey.PublicKey().PublicKey(), message, &signature) 33 | logger.Info("Verifying signature against bytes:", message) 34 | valid := ecc.VerifySignature(publicKey.PublicKey(), message, signature) 35 | logger.Info(" Valid signature:", valid) 36 | if !(valid) { 37 | t.Error("Signature verification failed.") 38 | } 39 | 40 | // Try checking the signature on text that is different 41 | logger.Info("Verifying signature against unsigned bytes:", unsignedMessage) 42 | valid = ecc.VerifySignature(publicKey.PublicKey(), unsignedMessage, signature) 43 | logger.Info(" Valid signature:", valid) 44 | if valid { 45 | t.Error("Signature verification should have failed here.") 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /tests/prekey_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/crossle/libsignal-protocol-go/logger" 7 | "github.com/crossle/libsignal-protocol-go/serialize" 8 | "github.com/crossle/libsignal-protocol-go/util/keyhelper" 9 | ) 10 | 11 | // TestPreKeys checks generating prekeys. 12 | func TestPreKeys(t *testing.T) { 13 | 14 | // Create a serializer object that will be used to encode/decode data. 15 | serializer := serialize.NewSerializer() 16 | serializer.SignalMessage = &serialize.ProtoBufSignalMessageSerializer{} 17 | serializer.PreKeySignalMessage = &serialize.ProtoBufPreKeySignalMessageSerializer{} 18 | serializer.SignedPreKeyRecord = &serialize.JSONSignedPreKeyRecordSerializer{} 19 | 20 | logger.Info("Testing prekey generation...") 21 | identityKeyPair, err := keyhelper.GenerateIdentityKeyPair() 22 | if err != nil { 23 | t.Error(err) 24 | } 25 | 26 | logger.Info("Generating prekeys") 27 | preKeys, _ := keyhelper.GeneratePreKeys(1, 100, serializer.PreKeyRecord) 28 | logger.Info("Generated PreKeys: ", preKeys) 29 | 30 | logger.Info("Generating Signed PreKey") 31 | signedPreKey, _ := keyhelper.GenerateSignedPreKey(identityKeyPair, 1, serializer.SignedPreKeyRecord) 32 | logger.Info("Signed PreKey: ", signedPreKey) 33 | } 34 | -------------------------------------------------------------------------------- /tests/registrationid_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/crossle/libsignal-protocol-go/util/keyhelper" 8 | ) 9 | 10 | func TestRegistrationID(t *testing.T) { 11 | regID := keyhelper.GenerateRegistrationID() 12 | fmt.Println(regID) 13 | } 14 | -------------------------------------------------------------------------------- /tests/saved_message_keys_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/crossle/libsignal-protocol-go/keys/message" 7 | "github.com/crossle/libsignal-protocol-go/keys/prekey" 8 | "github.com/crossle/libsignal-protocol-go/logger" 9 | "github.com/crossle/libsignal-protocol-go/protocol" 10 | "github.com/crossle/libsignal-protocol-go/session" 11 | ) 12 | 13 | // TestSavedMessageKeys tests the ability to save message keys for use in 14 | // decrypting messages in the future. 15 | func TestSavedMessageKeys(t *testing.T) { 16 | 17 | // Create a serializer object that will be used to encode/decode data. 18 | serializer := newSerializer() 19 | 20 | // Create our users who will talk to each other. 21 | alice := newUser("Alice", 1, serializer) 22 | bob := newUser("Bob", 2, serializer) 23 | 24 | // Create a session builder to create a session between Alice -> Bob. 25 | alice.buildSession(bob.address, serializer) 26 | bob.buildSession(alice.address, serializer) 27 | 28 | // Create a PreKeyBundle from Bob's prekey records and other 29 | // data. 30 | logger.Debug("Fetching Bob's prekey with ID: ", bob.preKeys[0].ID()) 31 | retrievedPreKey := prekey.NewBundle( 32 | bob.registrationID, 33 | bob.deviceID, 34 | bob.preKeys[0].ID(), 35 | bob.signedPreKey.ID(), 36 | bob.preKeys[0].KeyPair().PublicKey(), 37 | bob.signedPreKey.KeyPair().PublicKey(), 38 | bob.signedPreKey.Signature(), 39 | bob.identityKeyPair.PublicKey(), 40 | ) 41 | 42 | // Process Bob's retrieved prekey to establish a session. 43 | logger.Debug("Building sender's (Alice) session...") 44 | err := alice.sessionBuilder.ProcessBundle(retrievedPreKey) 45 | if err != nil { 46 | logger.Error("Unable to process retrieved prekey bundle") 47 | t.FailNow() 48 | } 49 | 50 | // Create a session cipher to encrypt messages to Bob. 51 | plaintextMessage := []byte("Hello!") 52 | logger.Info("Plaintext message: ", string(plaintextMessage)) 53 | sessionCipher := session.NewCipher(alice.sessionBuilder, bob.address) 54 | message, err := sessionCipher.Encrypt(plaintextMessage) 55 | if err != nil { 56 | logger.Error("Unable to encrypt message: ", err) 57 | t.FailNow() 58 | } 59 | 60 | logger.Info("Encrypted message: ", message) 61 | 62 | ///////////// RECEIVER SESSION CREATION /////////////// 63 | 64 | // Emulate receiving the message as JSON over the network. 65 | logger.Debug("Building message from bytes on Bob's end.") 66 | receivedMessage, err := protocol.NewPreKeySignalMessageFromBytes(message.Serialize(), serializer.PreKeySignalMessage, serializer.SignalMessage) 67 | if err != nil { 68 | logger.Error("Unable to emulate receiving message as JSON: ", err) 69 | t.FailNow() 70 | } 71 | 72 | // Try and decrypt the message and get the message key. 73 | bobSessionCipher := session.NewCipher(bob.sessionBuilder, alice.address) 74 | msg, key, err := bobSessionCipher.DecryptMessageReturnKey(receivedMessage) 75 | if err != nil { 76 | logger.Error("Unable to decrypt message: ", err) 77 | t.FailNow() 78 | } 79 | logger.Info("Decrypted message: ", string(msg)) 80 | if string(msg) != string(plaintextMessage) { 81 | logger.Error("Decrypted string does not match - Encrypted: ", string(plaintextMessage), " Decrypted: ", string(msg)) 82 | t.FailNow() 83 | } 84 | 85 | // Try using the message key to decrypt the message again. 86 | logger.Info("Testing using saved message key to decrypt again.") 87 | for i := 0; i < 10; i++ { 88 | testDecryptingWithKey(bobSessionCipher, receivedMessage.WhisperMessage(), key, plaintextMessage, t) 89 | } 90 | } 91 | 92 | func testDecryptingWithKey(cipher *session.Cipher, receivedMessage *protocol.SignalMessage, key *message.Keys, plaintextMessage []byte, t *testing.T) { 93 | msg, err := cipher.DecryptWithKey(receivedMessage, key) 94 | if err != nil { 95 | t.FailNow() 96 | } 97 | logger.Info("Decrypted message: ", string(msg)) 98 | if string(msg) != string(plaintextMessage) { 99 | logger.Error("Decrypted string does not match - Encrypted: ", string(plaintextMessage), " Decrypted: ", string(msg)) 100 | t.FailNow() 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /tests/serializer.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "github.com/crossle/libsignal-protocol-go/serialize" 5 | ) 6 | 7 | // newSerializer will return a JSON serializer for testing. 8 | func newSerializer() *serialize.Serializer { 9 | serializer := serialize.NewProtoBufSerializer() 10 | 11 | return serializer 12 | } 13 | -------------------------------------------------------------------------------- /tests/serializer_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/crossle/libsignal-protocol-go/keys/prekey" 8 | "github.com/crossle/libsignal-protocol-go/logger" 9 | "github.com/crossle/libsignal-protocol-go/session" 10 | "github.com/crossle/libsignal-protocol-go/state/record" 11 | "github.com/kr/pretty" 12 | ) 13 | 14 | // TestSerializing tests serialization and deserialization of Signal objects. 15 | func TestSerializing(t *testing.T) { 16 | 17 | // Create a serializer object that will be used to encode/decode data. 18 | serializer := newSerializer() 19 | 20 | // Create our users who will talk to each other. 21 | alice := newUser("Alice", 1, serializer) 22 | bob := newUser("Bob", 2, serializer) 23 | 24 | // Create a session builder to create a session between Alice -> Bob. 25 | alice.buildSession(bob.address, serializer) 26 | bob.buildSession(alice.address, serializer) 27 | 28 | // Create a PreKeyBundle from Bob's prekey records and other 29 | // data. 30 | retrivedPreKey := 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 | alice.sessionBuilder.ProcessBundle(retrivedPreKey) 43 | 44 | // Create a session cipher to encrypt messages to Bob. 45 | plaintextMessage := []byte("Hello!") 46 | sessionCipher := session.NewCipher(alice.sessionBuilder, bob.address) 47 | sessionCipher.Encrypt(plaintextMessage) 48 | 49 | // Serialize our session so it can be stored. 50 | loadedSession := alice.sessionStore.LoadSession(bob.address) 51 | serializedSession := loadedSession.Serialize() 52 | logger.Debug(string(serializedSession)) 53 | 54 | // Try deserializing our session back into an object. 55 | deserializedSession, err := record.NewSessionFromBytes(serializedSession, serializer.Session, serializer.State) 56 | if err != nil { 57 | logger.Error("Failed to deserialize session.") 58 | t.FailNow() 59 | } 60 | 61 | fmt.Printf("Original Session Record: %# v\n", pretty.Formatter(loadedSession)) 62 | fmt.Printf("Deserialized Session Record: %# v\n", pretty.Formatter(deserializedSession)) 63 | 64 | } 65 | -------------------------------------------------------------------------------- /tests/sharedsecret_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "encoding/base64" 5 | "testing" 6 | 7 | "github.com/crossle/libsignal-protocol-go/ecc" 8 | "github.com/crossle/libsignal-protocol-go/kdf" 9 | "github.com/crossle/libsignal-protocol-go/logger" 10 | ) 11 | 12 | // TestSharedSecret tests the key derivation function's ability to 13 | // calculate a shared secret given two pairs of ECDH keys. 14 | func TestSharedSecret(t *testing.T) { 15 | logger.Configure("sharedsecret_test.go") 16 | logger.Info("Testing identity key generation...") 17 | b64 := base64.StdEncoding.EncodeToString 18 | 19 | // Generate an keypair for Alice 20 | aliceKeyPair, err := ecc.GenerateKeyPair() 21 | if err != nil { 22 | t.Error("Error generating identity keys") 23 | } 24 | alicePrivateKey := aliceKeyPair.PrivateKey().Serialize() 25 | p := aliceKeyPair.PublicKey() 26 | alicePublicKey := p.PublicKey() 27 | logger.Info(" Alice PrivateKey: ", b64(alicePrivateKey[:])) 28 | logger.Info(" Alice PublicKey: ", b64(alicePublicKey[:])) 29 | 30 | // Generate an keypair for Bob 31 | bobKeyPair, err := ecc.GenerateKeyPair() 32 | if err != nil { 33 | t.Error("Error generating identity keys") 34 | } 35 | bobPrivateKey := bobKeyPair.PrivateKey().Serialize() 36 | p = bobKeyPair.PublicKey() 37 | bobPublicKey := p.PublicKey() 38 | logger.Info(" Bob PrivateKey: ", b64(bobPrivateKey[:])) 39 | logger.Info(" Bob PublicKey: ", b64(bobPublicKey[:])) 40 | 41 | // Calculate the shared secret as Alice. 42 | aliceSharedSecret := kdf.CalculateSharedSecret(bobPublicKey, alicePrivateKey) 43 | aliceHashedSecret, _ := kdf.DeriveSecrets(aliceSharedSecret[:], nil, []byte("Dust"), 64) 44 | logger.Info("Alice Shared Secret: ", b64(aliceSharedSecret[:])) 45 | logger.Info("Alice Hashed Secret: ", b64(aliceHashedSecret)) 46 | 47 | // Calculate the shared secret as Bob. 48 | bobSharedSecret := kdf.CalculateSharedSecret(alicePublicKey, bobPrivateKey) 49 | bobHashedSecret, _ := kdf.DeriveSecrets(bobSharedSecret[:], nil, []byte("Dust"), 64) 50 | logger.Info("Bob Shared Secret: ", b64(bobSharedSecret[:])) 51 | logger.Info("Bob Hashed Secret: ", b64(bobHashedSecret)) 52 | 53 | // Check to make sure Alice and Bob calculated the same shared secret. 54 | if b64(aliceSharedSecret[:]) != b64(bobSharedSecret[:]) { 55 | logger.Error("Computed secrets do not match: ", b64(aliceSharedSecret[:]), " != ", b64(bobSharedSecret[:])) 56 | t.Fail() 57 | } 58 | 59 | // Check to make sure that Alice and Bob also hashed the same secret the same way using KDF. 60 | if b64(aliceHashedSecret) != b64(bobHashedSecret) { 61 | logger.Error("Hashed secrets do not match: ", b64(aliceHashedSecret), " != ", b64(bobHashedSecret)) 62 | t.Fail() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/stores.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | groupRecord "github.com/crossle/libsignal-protocol-go/groups/state/record" 5 | "github.com/crossle/libsignal-protocol-go/keys/identity" 6 | "github.com/crossle/libsignal-protocol-go/protocol" 7 | "github.com/crossle/libsignal-protocol-go/serialize" 8 | "github.com/crossle/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/crossle/libsignal-protocol-go/groups" 5 | "github.com/crossle/libsignal-protocol-go/keys/identity" 6 | "github.com/crossle/libsignal-protocol-go/protocol" 7 | "github.com/crossle/libsignal-protocol-go/serialize" 8 | "github.com/crossle/libsignal-protocol-go/session" 9 | "github.com/crossle/libsignal-protocol-go/state/record" 10 | "github.com/crossle/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(1, 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 | "time" 8 | 9 | "github.com/crossle/libsignal-protocol-go/ecc" 10 | "github.com/crossle/libsignal-protocol-go/keys/identity" 11 | "github.com/crossle/libsignal-protocol-go/state/record" 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 | // GeneratePreKeys generates a list of PreKeys. Client shsould do this at 27 | // install time, and subsequently any time the list of PreKeys stored on 28 | // the server runs low. 29 | // 30 | // PreKeys IDs are shorts, so they will eventually be repeated. Clients 31 | // should store PreKeys in a circular buffer, so that they are repeated 32 | // as infrequently as possible. 33 | func GeneratePreKeys(start int, count int, serializer record.PreKeySerializer) ([]*record.PreKey, error) { 34 | var preKeys []*record.PreKey 35 | 36 | for i := start; i <= count; i++ { 37 | key, err := ecc.GenerateKeyPair() 38 | if err != nil { 39 | return nil, err 40 | } 41 | preKeys = append(preKeys, record.NewPreKey(uint32(i), key, serializer)) 42 | } 43 | 44 | return preKeys, nil 45 | } 46 | 47 | // GenerateLastResortKey will generate the last resort PreKey. Clients should 48 | // do this only once, at install time, and durably store it for the length 49 | // of the install. 50 | func GenerateLastResortKey(serializer record.PreKeySerializer) (*record.PreKey, error) { 51 | keyPair, err := ecc.GenerateKeyPair() 52 | if err != nil { 53 | return nil, err 54 | } 55 | return record.NewPreKey(0, keyPair, serializer), nil 56 | } 57 | 58 | // GenerateSignedPreKey generates a signed PreKey. 59 | func GenerateSignedPreKey(identityKeyPair *identity.KeyPair, signedPreKeyID uint32, serializer record.SignedPreKeySerializer) (*record.SignedPreKey, error) { 60 | keyPair, err := ecc.GenerateKeyPair() 61 | if err != nil { 62 | return nil, err 63 | } 64 | signature := ecc.CalculateSignature(identityKeyPair.PrivateKey(), keyPair.PublicKey().Serialize()) 65 | timestamp := time.Now().Unix() 66 | 67 | return record.NewSignedPreKey(signedPreKeyID, timestamp, keyPair, signature, serializer), nil 68 | } 69 | 70 | // GenerateRegistrationID generates a registration ID. Clients should only do 71 | // this once, at install time. 72 | func GenerateRegistrationID() uint32 { 73 | var n uint32 74 | binary.Read(rand.Reader, binary.LittleEndian, &n) 75 | 76 | return n 77 | } 78 | 79 | //---------- Group Stuff ---------------- 80 | 81 | func GenerateSenderSigningKey() (*ecc.ECKeyPair, error) { 82 | return ecc.GenerateKeyPair() 83 | } 84 | 85 | func GenerateSenderKey() []byte { 86 | randBytes := make([]byte, 32) 87 | rand.Read(randBytes) 88 | return randBytes 89 | } 90 | 91 | func GenerateSenderKeyID() uint32 { 92 | return GenerateRegistrationID() 93 | } 94 | 95 | //---------- End Group Stuff -------------- 96 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------