LVE SDK
    Preparing search index...

    LVE SDK

    LVE SDK

    LVE is a browser-native encrypted file format — WebAuthn PRF + AES-256-GCM + AES-KW. Files are passkey-locked: only a registered WebAuthn credential with PRF support can decrypt them. There is no password fallback by design.

    Browser Minimum version
    Chrome / Edge 118+
    Safari 17.5+

    Requires: Web Crypto API (SubtleCrypto) + WebAuthn PRF extension. Node.js 18+ is supported for crypto operations, but passkey APIs are browser-only.

    plaintext
    └─ AES-256-GCM (random DEK + 12-byte IV)
    └─ DEK wrapped with AES-KW per credential
    └─ KEK = HKDF-SHA-256(PRF output, wrapSalt, fileId)
    └─ PRF output = WebAuthn assertion on fileId

    Each authorized credential gets its own wrapped_dek entry in the file header. The ciphertext is encrypted once; only the wrapped DEK copies differ per recipient.

    import {
    checkPasskeyCapabilities,
    registerCredential,
    authenticateWithPrf,
    createLveFile,
    LvePrfNotSupportedError,
    } from "@lve/sdk";

    // 1. Check browser support
    const caps = await checkPasskeyCapabilities();
    if (!caps.prfSupported) {
    throw new LvePrfNotSupportedError("PRF not available — use Chrome 118+");
    }

    // 2. Register a passkey (skip if the user already has one)
    const cred = await registerCredential({
    rpId: window.location.hostname,
    rpName: "My App",
    userId: crypto.randomUUID().slice(0, 16),
    userName: "user@example.com",
    userDisplayName: "User",
    });

    // 3. Authenticate to get the PRF output bound to a specific fileId
    const fileId = crypto.randomUUID();
    const authResult = await authenticateWithPrf({
    rpId: window.location.hostname,
    fileId,
    });

    // 4. Encrypt
    const lveBytes = await createLveFile({
    plaintext: new TextEncoder().encode("secret content"),
    rpId: window.location.hostname,
    fileId,
    credentials: [{
    credentialId: authResult.credentialId,
    prfOutput: authResult.prfOutput,
    }],
    });
    import { exportMetadata, authenticateWithPrf, openLveFile } from "@lve/sdk";

    // 1. Read public metadata — no passkey needed
    const meta = exportMetadata(lveBytes);
    console.log(`${meta.file_id}${meta.recipient_count} authorized credential(s)`);

    // 2. Authenticate to get PRF output, bound to this file's ID
    const authResult = await authenticateWithPrf({
    rpId: window.location.hostname,
    fileId: meta.file_id,
    });

    // 3. Decrypt
    const { plaintext } = await openLveFile(lveBytes, {
    rpId: window.location.hostname,
    credentials: [{
    credentialId: authResult.credentialId,
    prfOutput: authResult.prfOutput,
    }],
    });

    console.log(new TextDecoder().decode(plaintext));
    import { addAuthorizedCredential } from "@lve/sdk";

    // Alice (already authorized) grants access to Bob
    const aliceAuth = await authenticateWithPrf({ rpId, fileId: meta.file_id });
    const bobReg = await registerCredential({ rpId, rpName: "My App", ... });

    const updatedLve = await addAuthorizedCredential(lveBytes, {
    existingCredentialId: aliceAuth.credentialId,
    existingPrfOutput: aliceAuth.prfOutput,
    newCredentialId: bobReg.credentialId,
    newPrfOutput: bobReg.prfOutput!,
    });
    // updatedLve is openable by both Alice and Bob

    All errors extend LveError.

    import {
    openLveFile, LveError,
    LvePrfNotSupportedError, LveWrongCredentialError,
    LveTamperedError, LveInvalidFormatError, LveWrongOriginError,
    } from "@lve/sdk";

    try {
    const { plaintext } = await openLveFile(lveBytes, { rpId, credentials });
    } catch (err) {
    if (err instanceof LvePrfNotSupportedError) {
    // Browser or authenticator does not support PRF — no fallback
    showError("Use Chrome 118+ or Safari 17.5+");
    } else if (err instanceof LveWrongCredentialError) {
    // This passkey is not authorized, or wrong PRF output
    showError("Wrong passkey");
    } else if (err instanceof LveTamperedError) {
    // AES-GCM auth tag mismatch — file was modified
    showError("File integrity check failed");
    } else if (err instanceof LveInvalidFormatError) {
    // Not a .lve file (wrong magic bytes, truncated, etc.)
    showError("Not a valid .lve file");
    } else if (err instanceof LveWrongOriginError) {
    // File was created for a different rp_id (different app/domain)
    showError("File belongs to a different app");
    } else if (err instanceof LveError) {
    showError(err.message);
    } else {
    throw err;
    }
    }
    Error class When thrown
    LveError Base — catch all LVE errors
    LvePrfNotSupportedError PRF unavailable; no password fallback
    LveWrongCredentialError Passkey not authorized or wrong PRF output
    LveTamperedError Ciphertext or AAD-covered header was modified
    LveUnsupportedVersionError Format version > 1 not supported by this SDK
    LveInvalidFormatError Not a valid .lve binary
    LveWrongOriginError File bound to a different rp_id