Encryption
Encrypting and decrypting data using the WalletClient
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);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 correspondingcounterpartythat 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 meEncrypting 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);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 BobBob ← 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 bytesBoth sides must supply the same
protocolIDandkeyID, and each uses the other party’s identity key in thecounterpartyfield. 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 matchingprotocolID,keyID,counterparty, andsecurityLevel. -
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.
