diff --git a/CHANGELOG.md b/CHANGELOG.md index deeebe0ed6..76b8978efe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Examples (web-chat): New `/fleet` command to switch connection between Status prod and test fleets. - Export `generatePrivateKey` and `getPublicKey` directly from the root. +- Usage of the encryption and signature APIs to the readme. ### Changed - **Breaking**: Renamed `WakuRelay.(add|delete)PrivateDecryptionKey` to `WakuRelay.(add|delete)DecryptionKey` to make it clearer that it accepts both symmetric keys and asymmetric private keys. diff --git a/README.md b/README.md index 65dd66073b..9684c59903 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,134 @@ waku.store.queryHistory({ }); ``` +## Encryption & Signature + +With js-waku, you can: + +- Encrypt messages over the wire using public/private key pair (asymmetric encryption), +- Encrypt messages over the wire using a unique key to both encrypt and decrypt (symmetric encryption), +- Sign and verify your waku messages (must use encryption, compatible with both symmetric and asymmetric). + +### Cryptographic Libraries + +A quick note on the cryptographic libraries used as it is a not a straightforward affair: +- Asymmetric encryption: Uses [ecies-geth](https://github.com/cyrildever/ecies-geth/) which in turns uses [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) Web API (browser), [secp256k1](https://www.npmjs.com/package/secp256k1) (native binding for node) or [elliptic](https://www.npmjs.com/package/elliptic) (pure JS if none of the other libraries are available). +- Symmetric encryption: uses [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) Web API (browser) or [NodeJS' crypto](https://nodejs.org/api/crypto.html) module. Which means there is no fallback if [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) is not available, [elliptic](https://www.npmjs.com/package/elliptic) could be added if the need rises. + +### Create new keys + +Asymmetric private keys and symmetric keys are expected to be 32 bytes arrays. + +```ts +import { generatePrivateKey, getPublicKey } from 'js-waku'; + +// Asymmetric +const privateKey = generatePrivateKey(); +const publicKey = getPublicKey(privateKey); + +// Symmetric +const symKey = generatePrivateKey(); +``` + +### Encrypt Waku Messages + +To encrypt your waku messages, simply pass the encryption key when creating it: + +```ts +import { WakuMessage } from 'js-waku'; + +// Asymmetric +const message = await WakuMessage.fromBytes(payload, { + contentTopic: myAppContentTopic, + encPublicKey: publicKey, + }); + +// Symmetric +const message = await WakuMessage.fromBytes(payload, { + contentTopic: myAppContentTopic, + symKey: symKey, + }); +``` + +### Decrypt Waku Messages + +#### Waku Relay + +If you expect to receive encrypted messages then simply add private decryption key(s) to `WakuRelay`. +Waku Relay will attempt to decrypt incoming messages with each keys, both for symmetric and asymmetric encryption. +Messages that are successfully decrypted (or received in clear) will be passed to the observers, other messages will be ommitted. + +```ts +// Asymmetric +waku.relay.addDecryptionKey(privateKey); + +// Symmetric +waku.relay.addDecryptionKey(symKey); + +// Then add the observer +waku.relay.addObserver(callback, [contentTopic]); +``` + +Keys can be removed using `WakuMessage.deleteDecryptionKey`. + +#### Waku Store + +```ts +const messages = await waku.store.queryHistory({ + contentTopics: [], + decryptionKeys: [privateKey, symKey], +}); +``` + +Similarly to relay, only decrypted or clear messages will be returned. + +### Sign Waku Messages + +As per version 1`s [specs](https://rfc.vac.dev/spec/26/), signatures are only included in encrypted messages. +In the case where your app does not need encryption then you could use symmetric encryption with a trivial key, I intend to dig [more on the subject](https://github.com/status-im/js-waku/issues/74#issuecomment-880440186) and come back with recommendation and examples. + +Signature keys can be generated the same way asymmetric keys for encryption are: + +```ts +import { generatePrivateKey, getPublicKey, WakuMessage } from 'js-waku'; + +const signPrivateKey = generatePrivateKey(); + +// Asymmetric Encryption +const message = await WakuMessage.fromBytes(payload, { + contentTopic: myAppContentTopic, + encPublicKey: recipientPublicKey, + sigPrivKey: signPrivateKey + }); + +// Symmetric Encryption +const message = await WakuMessage.fromBytes(payload, { + contentTopic: myAppContentTopic, + encPublicKey: symKey, + sigPrivKey: signPrivateKey + }); +``` + +### Verify Waku Message signatures + +Two fields are available on `WakuMessage` regarding signatures: + +- `signaturePublicKey`: If the message is signed, it holds the public key of the signature, +- `signature`: If the message is signed, it holds the actual signature. + +Thus, if you expect messages to be signed by Alice, +you can simply compare `WakuMessage.signaturePublicKey` with Alice's public key. +As comparing hex string can lead to issues (is the `0x` prefix present?), +simply use helper function `equalByteArrays`. + +```ts +import { equalByteArrays } from 'js-waku/lib/utils'; + +const sigPubKey = wakuMessage.signaturePublicKey; + +const isSignedByAlice = sigPubKey && equalByteArrays(sigPubKey, alicePublicKey); +``` + ## More documentation Find more [examples](#examples) below