Encryption

Encrypting and decrypting data using the WalletClient

Read as Markdown

This page shows how the WalletClient lets you encrypt and decrypt data using your identityKeys and how you can send encrypted messages to another party.


Why Encryption?

  • Keeps app data (messages, invoices, configuration files, etc.) private whether it lives on-chain or off-chain.

  • Achieve secure data flows by having the wallet encrypt/decrypt locally; private keys never leave the device.

  • Work with identity keys on both sides, so every operation lines up with the key concepts you learned in the previous guide.


Encrypting to Yourself

1const secret = new TextEncoder().encode('hello, future me');
2
3const { ciphertext } =  await wallet.encrypt({
4  plaintext:  Array.from(secret),
5  protocolID: [0, 'notes'], // specify the protocol to use
6  keyID:  'encrypt-1',      // specify the key that you want to use
7  counterparty:  'self'     // using your wallet's identity key
8})
9
10console.log('Cipher:', ciphertext);
Copied!

The wallet derives a shared secret from your identity key and returns an encrypted byte array you can store anywhere.


Decrypting Later

Decryption must use the exact same protocolID, keyID, and corresponding counterparty that were used to encrypt.

1const { plaintext } = await wallet.decrypt({
2  ciphertext,
3  protocolID: [0, 'notes'],
4  keyID: 'encrypt-1',
5  counterparty: 'self'
6});
7
8console.log(new TextDecoder().decode(Uint8Array.from(plaintext))); // → hello, future me
Copied!

Encrypting for a Friend

If Alice wants to send their friend Bob an encrypted message including a file, they must first know each other's identity keys. Here I'm starting with Bob's side:

1// Bob runs this once and sends Alice the result
2const { publicKey: bobsIDKey } = await wallet.getPublicKey({ identityKey: true });
3console.log('Bob’s Identity Key:', bobsIDKey);
Copied!

Alice → Bob: encrypt and send

1// Alice’s side
2const fileBytes = Array.from(await fileForBob.arrayBuffer());
3
4const { ciphertext } = await wallet.encrypt({
5  plaintext: fileBytes,
6  protocolID: [1, 'files'],   // must match on decrypt
7  keyID: 'encrypt-1',        // must match on decrypt
8  counterparty: bobsIDKey,   // Bob’s identity key
9});
10
11const { publicKey: alicesIDKey } = await wallet.getPublicKey({ identityKey: true })
12console.log('Alice’s Identity Key:', alicesIDKey);
13// Send ciphertext and alicesIDKey to Bob
Copied!

Bob ← Alice: decrypt

1// Bob receives the ciphertext and Alice’s identity key:
2const { plaintext } = await wallet.decrypt({
3  ciphertext,
4  protocolID: [1, 'files'],
5  keyID: 'encrypt-1',
6  counterparty: alicesIDKey,   // Alice’s identity key
7});
8
9// `plaintext` now holds the original file bytes
Copied!

Both sides must supply the same protocolID and keyID, and each uses the other party’s identity key in the counterparty field. If any of those values differ, decryption fails.


Summary

  • wallet.encrypt() secures any byte array to an identity key with a defined protocol ID, key ID, and counterparty.

  • wallet.decrypt() works only when you supply the matching protocolID, keyID, counterparty, and securityLevel.

  • Keys always come from identity-level getPublicKey() calls, keeping the flow consistent across your app.

Next up: Signing—learn how WalletClient attaches provable signatures to data and transactions.


Was this page helpful?