skiff-crypto
skiff-crypto is a versatile, open-source JavaScript cryptography library specifically designed to provide strong and efficient cryptographic functions for use in NodeJS or in the browser. This package powers cryptography inside Skiff’s end-to-end encrypted, privacy-first product suite, including Mail, Pages, Drive, and Calendar applications.
Features
- Symmetric Key Cryptography: ChaCha20Poly1305-based symmetric encryption functions
- Asymmetric Key Cryptography: TweetNaCl-based asymmetric encryption
- Datagram Library: Manage object versions and metadata in an efficient way
- Integrity: Support for checksum and data integrity verification
- Utilities: Collection of useful utilities for working with cryptographic data
Installation
npm install @skiff-org/skiff-crypto
Quick Start
const skiffCrypto = require('@skiff-org/skiff-crypto');
// or
import * as skiffCrypto from '@skiff-org/skiff-crypto';
// Asymmetric encryption example
const plaintext = "Hello, skiff-crypto!";
const keypair = skiffCrypto.generatePublicPrivateKeyPair();
const encrypted = skiffCrypto.stringEncryptAsymmetric(
keypair.privateKey,
{ key: keypair.publicKey },
plaintext
);
const decrypted = skiffCrypto.stringDecryptAsymmetric(
keypair.privateKey,
{ key: keypair.publicKey },
encrypted
);
console.log('Plaintext:', plaintext);
console.log('Ciphertext:', encrypted);
console.log('Expected to be true:', plaintext === decrypted);
Key Management
generateSymmetricKey
Generate a symmetric key for encryption.
function generateSymmetricKey(): string
Returns: Base64-encoded symmetric key
Example:
const symmetricKey = skiffCrypto.generateSymmetricKey();
console.log('Symmetric key:', symmetricKey);
Source: libs/skiff-crypto/src/keys.ts:14
generatePublicPrivateKeyPair
Generate public and private key pairs for signing and encryption.
function generatePublicPrivateKeyPair(): SigningAndEncryptionKeypairs
Returns:
Base64-encoded public encryption key
Base64-encoded private encryption key
Base64-encoded public signing key
Base64-encoded private signing key
Example:
const keypair = skiffCrypto.generatePublicPrivateKeyPair();
console.log('Public key:', keypair.publicKey);
console.log('Private key:', keypair.privateKey);
console.log('Signing public key:', keypair.signingPublicKey);
console.log('Signing private key:', keypair.signingPrivateKey);
Source: libs/skiff-crypto/src/keys.ts:82
createKeyFromSecret
Deterministically generate a key from a secret value and salt using Argon2id.
async function createKeyFromSecret(
secret: string,
argonSalt: string
): Promise<string>
Secret value to derive key from
Returns: Base64-encoded derived key
Source: libs/skiff-crypto/src/keys.ts:27
createSRPKey
Generate a key for SRP authentication from master secret using HKDF.
function createSRPKey(masterSecret: string, salt: string): string
Master secret used for HKDF
Returns: SRP private key in hexadecimal format
Source: libs/skiff-crypto/src/keys.ts:59
createPasswordDerivedSecret
Generate the password-derived secret (a symmetric key that encrypts user’s private keys).
function createPasswordDerivedSecret(
masterSecret: string,
salt: string
): string
User’s master secret for HKDF input
Returns: Base64-encoded password derived secret
Source: libs/skiff-crypto/src/keys.ts:102
generateVerificationPhraseFromSigningKey
Generate verification mnemonic using BIP39-like methodology.
function generateVerificationPhraseFromSigningKey(
publicSigningKey: string
): string
Public signing key of user to be verified
Returns: Mnemonic sentence for verification
Source: libs/skiff-crypto/src/keys.ts:120
Asymmetric Encryption
stringEncryptAsymmetric
Encrypt a string using asymmetric encryption (NaCl box).
function stringEncryptAsymmetric(
myPrivateKey: string,
theirPublicKey: { key: string },
plaintext: string
): string
User’s private encryption key
Recipient’s public key object
Returns: Base64-encoded encrypted ciphertext
Example:
const keypair = skiffCrypto.generatePublicPrivateKeyPair();
const encrypted = skiffCrypto.stringEncryptAsymmetric(
keypair.privateKey,
{ key: keypair.publicKey },
"Hello, World!"
);
Source: libs/skiff-crypto/src/asymmetricEncryption.ts:57
stringDecryptAsymmetric
Decrypt a string using asymmetric encryption (NaCl box).
function stringDecryptAsymmetric(
myPrivateKey: string,
theirPublicKey: { key: string },
encryptedText: string
): string
User’s private encryption key
Recipient’s public key object
Encrypted data to decrypt
Returns: Decrypted plaintext string
This function is memoized for performance optimization.
Source: libs/skiff-crypto/src/asymmetricEncryption.ts:74
Symmetric Encryption
encryptSymmetric
Symmetric encryption using NaCl secretbox (secret-key authenticated encryption).
function encryptSymmetric<T>(
content: T,
symmetricKey: string,
datagram: Datagram<T>
): string
The object being serialized and encrypted
Base64-encoded symmetric key
Mechanism to convert instances of T to a Datagram
Returns: Base64-encoded encrypted payload
Example:
const symmetricKey = skiffCrypto.generateSymmetricKey();
const TestDatagram = skiffCrypto.createJSONWrapperDatagram('ddl://test');
const plainText = "Hello, skiff-crypto (symmetric encryption)!";
const encrypted = skiffCrypto.encryptSymmetric(
plainText,
symmetricKey,
TestDatagram
);
Source: libs/skiff-crypto/src/symmetricEncryption.ts:31
decryptSymmetric
Symmetric decryption using NaCl secretbox (secret-key authenticated encryption).
function decryptSymmetric<T>(
message: string,
symmetricKey: string,
DatagramType: Datagram<T>
): T
Base64-encoded encrypted payload
Base64-encoded key used for decryption
The type of object being decrypted
Returns: Decrypted message contents
Example:
const decrypted = skiffCrypto.decryptSymmetric(
encrypted,
symmetricKey,
TestDatagram
);
console.log('Decrypted:', decrypted);
Source: libs/skiff-crypto/src/symmetricEncryption.ts:61
rawEncryptSymmetric
Symmetric encryption returning raw data without base64 encoding.
function rawEncryptSymmetric<T>(
content: T,
symmetricKey: string,
datagram: Datagram<T>
): Uint8Array
The object being serialized
Base64-encoded symmetric key
Mechanism to convert instances of T to a Datagram
Returns: Uint8Array encrypted payload
Source: libs/skiff-crypto/src/symmetricEncryption.ts:16
rawDecryptSymmetric
Symmetric decryption without base64 encoding.
function rawDecryptSymmetric<T>(
message: Uint8Array,
symmetricKey: string,
DatagramType: Datagram<T>
): T
Encrypted payload as raw bytes
Base64-encoded key used for decryption
The type of object being decrypted
Returns: Decrypted message contents
Source: libs/skiff-crypto/src/symmetricEncryption.ts:45
Datagram System
Datagrams provide a versioned, typed way to serialize and deserialize encrypted data with metadata support.
createJSONWrapperDatagram
Create a datagram that encodes and decodes any JSON.stringify-able data in an object containing {version, type, data}.
function createJSONWrapperDatagram<T>(
type: string,
version?: string,
versionConstraint?: Range
): Datagram<T>
Datagram type identifier (e.g., ‘ddl://test’)
Datagram version constraint
Returns: Datagram instance for encrypting/decrypting typed data
Example:
const TestDatagram = skiffCrypto.createJSONWrapperDatagram('ddl://test');
const symmetricKey = skiffCrypto.generateSymmetricKey();
const data = { message: "Hello, World!" };
const encrypted = skiffCrypto.encryptSymmetric(data, symmetricKey, TestDatagram);
const decrypted = skiffCrypto.decryptSymmetric(encrypted, symmetricKey, TestDatagram);
Source: libs/skiff-crypto/src/datagramBuilders.ts:15
createRawJSONDatagram
Create a datagram that encodes and decodes any JSON.stringify-able data without wrapping in version/type metadata.
function createRawJSONDatagram<T>(
type: string,
version?: string,
versionConstraint?: Range
): Datagram<T>
Datagram version constraint
Returns: Datagram instance without metadata wrapper
This is recommended for new code as version and type info are already contained in the encryption header.
Source: libs/skiff-crypto/src/datagramBuilders.ts:44
createRawCompressedJSONDatagram
Create a datagram that encodes and decodes JSON data with gzip compression.
function createRawCompressedJSONDatagram<T>(
type: string,
version?: string,
versionConstraint?: Range
): Datagram<T>
Datagram version constraint
Returns: Datagram instance with compression support
Source: libs/skiff-crypto/src/datagramBuilders.ts:68
createUint8ArrayDatagram
Create a datagram that encodes and decodes raw Uint8Array objects for optimal size.
function createUint8ArrayDatagram(
type: string,
version?: string,
versionConstraint?: Range
): Datagram<Uint8Array>
Datagram version constraint
Returns: Datagram instance for raw binary data
Source: libs/skiff-crypto/src/datagramBuilders.ts:96
Hashing
generateHash
Generate a SHA-512 hash of the given value.
function generateHash(value: string): string
Returns: Base64-encoded SHA-512 hash
Example:
const hash = skiffCrypto.generateHash('Hello, skiff-crypto!');
console.log('SHA-512 hash:', hash);
Source: libs/skiff-crypto/src/hash.ts:10
Digital Signatures
createDetachedSignatureAsymmetric
Create a detached signature from a message with context.
function createDetachedSignatureAsymmetric(
message: string,
signingPrivateKey: string,
context: SignatureContext,
additionalContext?: AdditionalContext
): string
User’s signing private key
Signature context to prevent re-interpretation
Optional additional context
Returns: Base64-encoded signature
Source: libs/skiff-crypto/src/signature.ts:96
verifyDetachedSignatureAsymmetric
Verify a signature on provided message given context.
function verifyDetachedSignatureAsymmetric(
message: string,
signature: string,
signingPublicKey: string,
context: SignatureContext,
additionalContext?: AdditionalContext
): boolean
User’s signing public key
Optional additional context
Returns: Boolean indicating whether signature is valid
Source: libs/skiff-crypto/src/signature.ts:73
SignatureContext
Enumeration of signature contexts to prevent signature re-interpretation:
enum SignatureContext {
DeleteAccount = 'DELETE_ACCOUNT',
DeleteDoc = 'DELETE_DOC',
DeleteRecoveryData = 'DELETE_RECOVERY_DATA',
DisableMfa = 'DISABLE_MFA',
DocumentChunk = 'DOCUMENT_CHUNK',
DocumentData = 'DOCUMENT_DATA',
DocumentMetadata = 'DOCUMENT_METADATA',
DocumentParent = 'DOCUMENT_PARENT',
EnrollMfa = 'ENROLL_MFA',
LinksLinkKey = 'LINKS_LINK_KEY',
LinksSessionKey = 'LINKS_SESSION_KEY',
RecoveryData = 'RECOVERY_DATA',
RegenerateMfaBackupCodes = 'REGENERATE_MFA_BACKUP_CODES',
SessionKey = 'SESSION_KEY',
SrpSalt = 'SRP_SALT',
SrpVerifier = 'SRP_VERIFIER',
UnshareDoc = 'UNSHARE_DOC',
UpdateUserData = 'UPDATE_USER_DATA',
UserData = 'USER_DATA',
UserPublicKey = 'USER_PUBLIC_KEY',
EmailContent = 'EMAIL_CONTENT',
MobileLogin = 'MOBILE_LOGIN'
}
Source: libs/skiff-crypto/src/signature.ts:12
Complete Example
import * as skiffCrypto from '@skiff-org/skiff-crypto';
// Generate keys
const keypair = skiffCrypto.generatePublicPrivateKeyPair();
const symmetricKey = skiffCrypto.generateSymmetricKey();
// Asymmetric encryption
const plaintext = "Hello, skiff-crypto!";
const encrypted = skiffCrypto.stringEncryptAsymmetric(
keypair.privateKey,
{ key: keypair.publicKey },
plaintext
);
const decrypted = skiffCrypto.stringDecryptAsymmetric(
keypair.privateKey,
{ key: keypair.publicKey },
encrypted
);
console.log('Asymmetric encryption works:', plaintext === decrypted);
// Symmetric encryption with datagram
const TestDatagram = skiffCrypto.createJSONWrapperDatagram('ddl://test');
const symmetricPlainText = "Hello, skiff-crypto (symmetric encryption)!";
const symmetricEncrypted = skiffCrypto.encryptSymmetric(
symmetricPlainText,
symmetricKey,
TestDatagram
);
const symmetricDecrypted = skiffCrypto.decryptSymmetric(
symmetricEncrypted,
symmetricKey,
TestDatagram
);
console.log('Symmetric encryption works:', symmetricPlainText === symmetricDecrypted);
// Hash example
const hash = skiffCrypto.generateHash('Hello, skiff-crypto!');
console.log('SHA-512 hash:', hash);
Security
Cryptography is a sensitive domain. While skiff-crypto has been audited and built using widely-used, audited libraries (TweetNaCl, ChaCha20Poly1305, Argon2), we urge you to use this library responsibly. Please have a sound understanding of the underlying principles of cryptography before implementation.
Security issues or questions can be sent to [email protected].
License
skiff-crypto is MIT licensed. See the LICENSE file for details.