chore: add docs for encoding/decoding messages (#236)

This commit is contained in:
Richard Ramos 2022-05-05 11:08:34 -04:00 committed by GitHub
parent 386d59747a
commit 19f13b80fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 204 additions and 33 deletions

View File

@ -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!

197
docs/encoding.md Normal file
View File

@ -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 Bobs 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.