mirror of https://github.com/status-im/go-waku.git
chore: add docs for encoding/decoding messages (#236)
This commit is contained in:
parent
386d59747a
commit
19f13b80fa
40
README.md
40
README.md
|
@ -52,46 +52,20 @@ make dynamic-library
|
|||
## Tutorials and documentation
|
||||
- [Receive and send messages using Waku Relay](docs/relay.md)
|
||||
- [Send messages using Waku Lightpush](docs/lightpush.md)
|
||||
- [Encoding and decoding Waku Messages](docs/encoding.md)
|
||||
- [C Bindings](library/README.md)
|
||||
|
||||
## Examples
|
||||
Examples of usage of go-waku as a library can be found in the `examples/` folder:
|
||||
|
||||
- [**basic2**](../examples/basic2) - demonstrates how to send and receive messages
|
||||
- [**chat2**](../examples/chat2) - simple chat client using waku relay / lightpush + filter / store protocol to send/receive messages and retrieve message history
|
||||
- [**filter2**](../examples/filter2) - demonstrates how to use filter protocol
|
||||
- [**c-bindings**](../examples/c-bindings) - simple program to demonstrate how to consume the go-waku library via C FFI
|
||||
- [**waku-csharp**](../examples/csharp) - C# console application that uses the go-waku library via FFI
|
||||
- [**android-kotlin**](../examples/android-kotlin) - android app that uses a .jar generated by gomobile using kotlin
|
||||
- [**basic2**](tree/master/examples/basic2) - demonstrates how to send and receive messages
|
||||
- [**chat2**](tree/master/examples/chat2) - simple chat client using waku relay / lightpush + filter / store protocol to send/receive messages and retrieve message history
|
||||
- [**filter2**](tree/master/examples/filter2) - demonstrates how to use filter protocol
|
||||
- [**c-bindings**](tree/master/examples/c-bindings) - simple program to demonstrate how to consume the go-waku library via C FFI
|
||||
- [**waku-csharp**](tree/master/examples/csharp) - C# console application that uses the go-waku library via FFI
|
||||
- [**android-kotlin**](tree/master/examples/android-kotlin) - android app that uses a .jar generated by gomobile using kotlin
|
||||
|
||||
|
||||
|
||||
## Waku Protocol Support
|
||||
|
||||
- ✔: Supported
|
||||
- 🚧: Implementation in progress
|
||||
- ⛔: Support is not planned
|
||||
|
||||
| Spec | Implementation Status |
|
||||
| ---- | -------------- |
|
||||
|[7/WAKU-DATA](https://rfc.vac.dev/spec/7)|✔|
|
||||
|[10/WAKU2](https://rfc.vac.dev/spec/10)|🚧|
|
||||
|[11/WAKU2-RELAY](https://rfc.vac.dev/spec/11)|✔|
|
||||
|[12/WAKU2-FILTER](https://rfc.vac.dev/spec/12)|✔|
|
||||
|[13/WAKU2-STORE](https://rfc.vac.dev/spec/13)|✔|
|
||||
|[14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14)|✔|
|
||||
|[15/WAKU2-BRIDGE](https://rfc.vac.dev/spec/15)|⛔|
|
||||
|[16/WAKU2-RPC](https://rfc.vac.dev/spec/16)|✔|
|
||||
|[17/WAKU2-RLNRELAY](https://rfc.vac.dev/spec/17)||
|
||||
|[18/WAKU2-SWAP](https://rfc.vac.dev/spec/18)|🚧|
|
||||
|[21/WAKU2-FTSTORE](https://rfc.vac.dev/spec/21)|✔|
|
||||
|[22/TOY-CHAT](https://rfc.vac.dev/spec/22)|✔|
|
||||
|[23/TOPICS](https://rfc.vac.dev/spec/22)|✔|
|
||||
|[25/LIBP2P-DNS-DISCOVERY](https://rfc.vac.dev/spec/25)|🚧|
|
||||
|[26/WAKU2-PAYLOAD](https://rfc.vac.dev/spec/26)|✔|
|
||||
|[27/WAKU2-PEERS](https://rfc.vac.dev/spec/27)|✔|
|
||||
|[29/WAKU2-CONFIG](https://rfc.vac.dev/spec/29)|🚧|
|
||||
|
||||
## Contribution
|
||||
Thank you for considering to help out with the source code! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes!
|
||||
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
Encoding and decoding Waku Messages
|
||||
===
|
||||
|
||||
The Waku Message format provides an easy way to encrypt messages using symmetric or asymmetric encryption. The encryption comes with several handy design requirements: confidentiality, authenticity and integrity. You can find more details about Waku Message Payload Encryption in 26/WAKU-PAYLOAD.
|
||||
|
||||
## What data is encrypted
|
||||
With Waku Message Version 1, the entire payload is encrypted.
|
||||
|
||||
Which means that the only discriminating data available in clear text is the content topic and timestamp (if present). Hence, if Alice expects to receive messages under a given content topic, she needs to try to decrypt all messages received on said content topic.
|
||||
|
||||
This needs to be kept in mind for scalability and forward secrecy concerns:
|
||||
|
||||
- If there is high traffic on a given content topic then all clients need to process and attempt decryption of all messages with said content topic;
|
||||
- If a content topic is only used by a given (group of) user(s) then it is possible to deduce some information about said user(s) communications such as sent time and frequency of messages.
|
||||
|
||||
## Key management
|
||||
By using Waku Message Version 1, you will need to provide a way to your users to generate and store keys in a secure manner. Storing, backing up and recovering key is out of the scope of this guide.
|
||||
|
||||
## Which encryption method should I use?
|
||||
Whether you should use symmetric or asymmetric encryption depends on your use case.
|
||||
|
||||
Symmetric encryption is done using a single key to encrypt and decrypt.
|
||||
|
||||
Which means that if Alice knows the symmetric key `K` and uses it to encrypt a message, she can also use `K` to decrypt any message encrypted with `K`, even if she is not the sender.
|
||||
|
||||
Group chats is a possible use case for symmetric encryption: All participants can use an out-of-band method to agree on a `K`. Participants can then use `K` to encrypt and decrypt messages within the group chat. Participants MUST keep `K` secret to ensure that no external party can decrypt the group chat messages.
|
||||
|
||||
Asymmetric encryption is done using a key pair: the public key is used to encrypt messages, the matching private key is used to decrypt messages.
|
||||
|
||||
For Alice to encrypt a message for Bob, she needs to know Bob’s Public Key `K`. Bob can then use his private key `k` to decrypt the message. As long as Bob keep his private key `k` secret, then he, and only he, can decrypt messages encrypted with `K`.
|
||||
|
||||
Private 1:1 messaging is a possible use case for asymmetric encryption: When Alice sends an encrypted message for Bob, only Bob can decrypt it.
|
||||
|
||||
## Symmetric Encryption
|
||||
|
||||
### Encrypt a Message
|
||||
To encrypt a message, assign the 32 byte symmetric key to a `KeyInfo`, and set its `Kind` to `node.Symmetric`. `node.EncodeWakuMessage` can then be used to encrypt the payload of a WakuMessage (that uses version `1`).
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/status-im/go-waku/waku/v2/utils"
|
||||
"github.com/status-im/go-waku/waku/v2/node"
|
||||
"github.com/status-im/go-waku/waku/v2/protocol/pb"
|
||||
)
|
||||
|
||||
func main(){
|
||||
symKey := []byte{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32}
|
||||
|
||||
keyInfo := &node.KeyInfo{
|
||||
Kind: node.Symmetric,
|
||||
SymKey: symKey,
|
||||
// PrivKey: Set a privkey if the message requires a signature
|
||||
}
|
||||
|
||||
msg := &pb.WakuMessage{
|
||||
Payload: []byte("Hello World"),
|
||||
Version: 1,
|
||||
ContentTopic: "/test/1/test/proto",
|
||||
Timestamp: utils.GetUnixEpoch(),
|
||||
}
|
||||
|
||||
if err := node.EncodeWakuMessage(msg, keyInfo); err != nil {
|
||||
fmt.Println("Error encrypting the message payload: ", err)
|
||||
}
|
||||
}
|
||||
```
|
||||
The `WakuMessage` payload will be encrypted, and can be later broadcasted via Relay or Lightpush. It's also possible to not have to rely on a `WakuMessage` by creating instead a `node.Payload`, setting the payload in the `Data` attribute and the key in `Key`, and then use `payload.Encode(1)` to encrypt your message, receiving a `byte[]` as a result.
|
||||
|
||||
The message can also be signed with a private key (`*ecdsa.PrivKey`) by setting it into the `PrivKey` attribute of the `KeyInfo` instance.
|
||||
|
||||
### Decrypting a Message
|
||||
To decrypt a message, regardless of the protocol on which it was received, assign the 32 byte symmetric key to a `KeyInfo`, and set its `Kind` to `node.Symmetric`.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/status-im/go-waku/waku/v2/utils"
|
||||
"github.com/status-im/go-waku/waku/v2/node"
|
||||
"github.com/status-im/go-waku/waku/v2/protocol/pb"
|
||||
)
|
||||
|
||||
func main(){
|
||||
symKey := []byte{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32}
|
||||
|
||||
keyInfo := &node.KeyInfo{
|
||||
Kind: node.Symmetric,
|
||||
SymKey: symKey,
|
||||
}
|
||||
|
||||
// This message could have arrived via any of these protocols: relay, filter, store
|
||||
msg := &pb.WakuMessage{
|
||||
Payload: ..., // Some encrypted payload
|
||||
Version: 1,
|
||||
...
|
||||
}
|
||||
|
||||
if err := node.DecodeWakuMessage(msg, keyInfo); err != nil {
|
||||
fmt.Println("Error decrypting the message payload: ", err)
|
||||
}
|
||||
|
||||
fmt.Println(msg.Payload)
|
||||
}
|
||||
```
|
||||
|
||||
The `WakuMessage` payload will be decrypted and available in plain text. Messages that can't be decrypted will return an `error`.
|
||||
|
||||
> To have access to the message author's public key and signature (if available) of the message, `DecodePayload(msg, keyInfo)` can be used instead. It will return a `DecodedPayload` instance containing `PubKey` and `Signature` attributes, and it's not a destructive operation, so the `WakuMessage` protobuffer will not be modified.
|
||||
|
||||
|
||||
|
||||
## Asymmetric Encryption
|
||||
|
||||
### Encrypt a Message
|
||||
To encrypt a message, assign an `*ecdsa.PublicKey` to a `KeyInfo`, and set its `Kind` to `node.Asymmetric`. `node.EncodeWakuMessage` can then be used to encrypt the payload of a WakuMessage (that uses version `1`).
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/status-im/go-waku/waku/v2/utils"
|
||||
"github.com/status-im/go-waku/waku/v2/node"
|
||||
"github.com/status-im/go-waku/waku/v2/protocol/pb"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
func main(){
|
||||
|
||||
|
||||
keyInfo := &node.KeyInfo{
|
||||
Kind: node.Asymmetric,
|
||||
PubKey: ..., // The public key to encrypt the messages with
|
||||
// PrivKey: Set a privkey if the message requires a signature
|
||||
}
|
||||
|
||||
msg := &pb.WakuMessage{
|
||||
Payload: []byte("Hello World"),
|
||||
Version: 1,
|
||||
ContentTopic: "/test/1/test/proto",
|
||||
Timestamp: utils.GetUnixEpoch(),
|
||||
}
|
||||
|
||||
if err := node.EncodeWakuMessage(msg, keyInfo); err != nil {
|
||||
fmt.Println("Error encrypting the message payload: ", err)
|
||||
}
|
||||
}
|
||||
```
|
||||
The `WakuMessage` payload will be encrypted, and can be later broadcasted via Relay or Lightpush. It's also possible to not have to rely on a `WakuMessage` by creating instead a `node.Payload`, setting the payload in the `Data` attribute and the key in `Key`, and then use `payload.Encode(1)` to encrypt your message, receiving a `byte[]` as a result.
|
||||
|
||||
The message can also be signed with a private key (`*ecdsa.PrivKey`) by setting it into the `PrivKey` attribute of the `KeyInfo` instance.
|
||||
|
||||
### Decrypting a Message
|
||||
To decrypt a message that was encrypted with your public key, regardless of the protocol on which it was received, assign the `*ecdsa.PrivateKey` to `KeyInfo`, and set its `Kind` to `node.Asymmetric`.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/status-im/go-waku/waku/v2/utils"
|
||||
"github.com/status-im/go-waku/waku/v2/node"
|
||||
"github.com/status-im/go-waku/waku/v2/protocol/pb"
|
||||
)
|
||||
|
||||
func main(){
|
||||
keyInfo := &node.KeyInfo{
|
||||
Kind: node.Symmetric,
|
||||
PrivKey: ..., // Your private key
|
||||
}
|
||||
|
||||
// This message could have arrived via any of these protocols: relay, filter, store
|
||||
msg := &pb.WakuMessage{
|
||||
Payload: ..., // Some encrypted payload
|
||||
Version: 1,
|
||||
...
|
||||
}
|
||||
|
||||
if err := node.DecodeWakuMessage(msg, keyInfo); err != nil {
|
||||
fmt.Println("Error decrypting the message payload: ", err)
|
||||
}
|
||||
|
||||
fmt.Println(msg.Payload)
|
||||
}
|
||||
```
|
||||
|
||||
The `WakuMessage` payload will be decrypted and available in plain text. Messages that can't be decrypted will return an `error`.
|
||||
|
||||
> To have access to the message author's public key and signature (if available) of the message, `DecodePayload(msg, keyInfo)` can be used instead. It will return a `DecodedPayload` instance containing `PubKey` and `Signature` attributes, and it's not a destructive operation, so the `WakuMessage` protobuffer will not be modified.
|
Loading…
Reference in New Issue