Encryption
Skiff provides both symmetric and asymmetric encryption functions built on industry-standard cryptographic libraries. This guide covers the encryption APIs, implementation details, and best practices.Symmetric Encryption
Symmetric encryption uses ChaCha20Poly1305, implemented through theTaggedSecretBox class. This provides authenticated encryption with additional data (AEAD).
Basic Usage
libs/skiff-crypto/README.md:58-66
Symmetric Encryption Functions
encryptSymmetric
Encrypts content using secret-key authenticated encryption and returns a base64-encoded string.content: The object being serialized and encryptedsymmetricKey: Base64-encoded symmetric key (32 bytes)datagram: The mechanism to convert instances of T to a Datagram
libs/skiff-crypto/src/symmetricEncryption.ts:31
rawEncryptSymmetric
Encrypts content and returns rawUint8Array without base64 encoding.
Uint8Array
Reference: libs/skiff-crypto/src/symmetricEncryption.ts:16
decryptSymmetric
Decrypts a base64-encoded encrypted payload.message: Base64-encoded encrypted payloadsymmetricKey: Base64-encoded key used for decryptionDatagramType: The type of object being decrypted
libs/skiff-crypto/src/symmetricEncryption.ts:61
TaggedSecretBox Implementation
TheTaggedSecretBox class wraps ChaCha20Poly1305 and adds version/type metadata:
libs/skiff-crypto/src/aead/secretbox.ts:12-54
Datagram Format
The encrypted data includes a header with version and type information:AA: Metadata format version (varint-prefixed)BB: Object version (varint-prefixed)CC: Type name (varint-prefixed)DD: Nonce (varint-prefixed)NN: Total length of header (varint-prefixed)
libs/skiff-crypto/src/aead/common.ts:79-113
This format ensures:
- Type safety: Prevents decrypting data as the wrong type
- Version compatibility: Validates version constraints
- Authenticated metadata: AAD is verified during decryption
Asymmetric Encryption
Asymmetric encryption uses TweetNaCl’sbox construction (Curve25519 + XSalsa20 + Poly1305).
Basic Usage
libs/skiff-crypto/README.md:48-55
Asymmetric Encryption Functions
stringEncryptAsymmetric
Encrypts a string using public-key authenticated encryption.myPrivateKey: Your private encryption key (base64-encoded)theirPublicKey: Recipient’s public key objectplaintext: The text to encrypt
libs/skiff-crypto/src/asymmetricEncryption.ts:57-65
stringDecryptAsymmetric
Decrypts a string using public-key authenticated encryption. This function is memoized for performance.myPrivateKey: Your private encryption key (base64-encoded)theirPublicKey: Sender’s public key objectencryptedText: The encrypted data to decrypt
libs/skiff-crypto/src/asymmetricEncryption.ts:74-81
Low-Level Asymmetric Functions
encryptAsymmetric
Core encryption function using nacl.box:- Generates a random nonce using
nacl.randomBytes(nacl.box.nonceLength) - Converts the message to UTF-8 bytes
- Encrypts using
nacl.boxornacl.box.after(with precomputed shared key) - Prepends the nonce to the encrypted message
- Base64-encodes the result
libs/skiff-crypto/src/asymmetricEncryption.ts:16-29
decryptAsymmetric
Core decryption function:- Base64-decodes the message
- Extracts the nonce (first
nacl.box.nonceLengthbytes) - Extracts the ciphertext (remaining bytes)
- Decrypts using
nacl.box.openornacl.box.open.after - Converts the result from UTF-8 bytes to string
libs/skiff-crypto/src/asymmetricEncryption.ts:34-48
Nonce Generation
Nonces are critical for security:libs/skiff-crypto/src/asymmetricEncryption.ts:9-11
Important: Never reuse a nonce with the same key. The encryption functions automatically generate a fresh random nonce for each encryption operation.
Choosing Between Symmetric and Asymmetric
Use Symmetric Encryption When:
- Encrypting large amounts of data (documents, files, messages)
- Both parties can securely share a symmetric key
- Performance is critical
- You need to encrypt/decrypt repeatedly with the same key
Use Asymmetric Encryption When:
- Sharing keys between parties who haven’t communicated before
- Encrypting small amounts of data (typically symmetric keys)
- You need non-repudiation or digital signatures
- Key distribution is a primary concern
Hybrid Approach (Recommended)
For most applications, use both:- Generate a random symmetric key
- Encrypt your data with the symmetric key (fast)
- Encrypt the symmetric key with the recipient’s public key (secure)
- Send both the encrypted data and encrypted symmetric key
Error Handling
Both encryption systems include robust error handling:Security Best Practices
- Never reuse nonces: Each encryption generates a fresh random nonce
- Protect private keys: Never expose private keys in logs, error messages, or client-side code
- Use authenticated encryption: Both ChaCha20Poly1305 and NaCl provide authentication
- Validate before decrypting: Type and version checks prevent malformed data processing
- Use secure random sources: All random generation uses cryptographically secure sources
- Key rotation: Periodically rotate encryption keys for long-lived data
- Constant-time operations: The underlying libraries use constant-time algorithms to prevent timing attacks
Next Steps
Key Management
Learn about generating and managing cryptographic keys
Private Search
Implement encrypted search functionality