npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@everabyte/evb-sdk-typescript

v1.0.4

Published

Everabyte SDK - Zero-Knowledge E2EE Cryptographic Library for TypeScript/JavaScript/Node.js

Downloads

309

Readme

@everabyte/evb-sdk-typescript

Zero-Knowledge End-to-End Encryption (E2EE) SDK for TypeScript and JavaScript

npm version License: MIT TypeScript

📋 Overview

EvbSDK TypeScript is a production-ready cryptographic library that provides secure file storage with zero-knowledge architecture. Your files are encrypted client-side before they ever reach the server, ensuring complete privacy and security.

🎯 Key Features

  • Zero-Knowledge E2EE - Server never sees plaintext or private keys
  • HPKE RFC 9180 - Hybrid Public Key Encryption (X25519-HKDF-SHA256)
  • AES-256-GCM - Industry-standard symmetric encryption with authentication
  • Chunked Encryption - Handle files of any size (1MB chunks for memory efficiency)
  • Progress Tracking - Built-in progress callbacks for long operations
  • Cross-Platform - Works in Browser, Node.js, React Native, and TypeScript
  • TypeScript Support - Full type definitions included
  • 100% Test Coverage - Production-ready with comprehensive tests

🌐 Platform Support

| Platform | Status | Notes | |----------|--------|-------| | Browser | ✅ Fully Supported | Chrome 90+, Firefox 88+, Safari 15+, Edge 90+ | | Node.js | ✅ Fully Supported | Node.js 16.0.0+ (uses crypto module) | | TypeScript | ✅ Fully Supported | TypeScript 5.0+ with full type definitions | | React Native | ⚠️ Planned | Web Crypto API polyfill required | | Electron | ✅ Fully Supported | Uses browser Web Crypto API |

⚠️ Important: This SDK automatically detects the environment and uses the appropriate crypto implementation:

  • Browser: Web Crypto API (native)
  • Node.js: crypto module (webcrypto)

📦 Prerequisites

Before installing the SDK, ensure you have:

  • Node.js 16.0.0 or higher
  • npm 7.0.0 or higher (or yarn 1.22+ / pnpm 6.0+)
  • A modern web browser with Web Crypto API support
  • TypeScript 5.0+ (if using TypeScript)

Development Environment

For development:

# Check Node.js version
node --version  # Should be v16.0.0 or higher

# Check npm version
npm --version  # Should be v7.0.0 or higher

🚀 Installation

Install from npm Public Registry

Install the package directly from npm:

npm install @everabyte/evb-sdk-typescript

Or with yarn:

yarn add @everabyte/evb-sdk-typescript

Or with pnpm:

pnpm add @everabyte/evb-sdk-typescript

Install from Local File (Development)

For local development:

npm install /path/to/evb-sdk/typescript

Verify Installation

npm list @everabyte/evb-sdk-typescript

📖 Usage

Platform-Specific Usage

Node.js Usage

The SDK works seamlessly in Node.js environments (16.0.0+). It automatically detects the environment and uses the Node.js crypto module.

import { E2EECore } from '@everabyte/evb-sdk-typescript/e2ee';
import { readFileSync, writeFileSync } from 'fs';
import { Buffer } from 'buffer';

async function encryptFileNodeJS(filePath: string) {
  const e2ee = new E2EECore();
  
  // Read file as Buffer
  const fileBuffer = readFileSync(filePath);
  
  // Encrypt file
  const result = await e2ee.prepareUpload({
    file: fileBuffer, // Pass Buffer directly
    chunkSize: 1024 * 1024,
    onProgress: (stage, progress) => {
      console.log(`[${stage}] ${progress}%`);
    },
  });
  
  if (result.success) {
    // Get encrypted data as Buffer
    const encryptedBuffer = Buffer.from(
      await result.encryptedFile.arrayBuffer()
    );
    
    // Save encrypted file
    writeFileSync('encrypted.bin', encryptedBuffer);
    console.log('File encrypted successfully!');
    console.log('AES Key (base64):', result.aesKeyBase64);
    return result.aesKeyBase64;
  }
}

async function decryptFileNodeJS(
  encryptedFilePath: string,
  aesKeyBase64: string
) {
  const e2ee = new E2EECore();
  
  // Read encrypted file
  const encryptedBuffer = readFileSync(encryptedFilePath);
  const encryptedBlob = new Blob([encryptedBuffer]);
  
  // Decrypt file
  const result = await e2ee.decryptDownload({
    encryptedData: await encryptedBlob.arrayBuffer(),
    aesKeyBase64: aesKeyBase64, // Direct AES key
    onProgress: (progress) => {
      console.log(`Decrypting: ${progress}%`);
    },
  });
  
  if (result.success) {
    // Get decrypted data as Buffer
    const decryptedBuffer = Buffer.from(
      await result.decryptedFile.arrayBuffer()
    );
    
    // Save decrypted file
    writeFileSync('decrypted.txt', decryptedBuffer);
    console.log('File decrypted successfully!');
  }
}

// Usage
encryptFileNodeJS('document.txt').catch(console.error);
decryptFileNodeJS('encrypted.bin', 'your-aes-key-base64').catch(console.error);

Frontend TypeScript Usage

The SDK is fully compatible with TypeScript frontends (React, Vue, Angular, etc.).

import { E2EECore } from '@everabyte/evb-sdk-typescript/e2ee';

interface UploadResult {
  success: boolean;
  fileId?: string;
  error?: string;
}

async function uploadFile(file: File): Promise<UploadResult> {
  const e2ee = new E2EECore();
  
  try {
    // Encrypt file with type safety
    const result = await e2ee.prepareUpload({
      file: file,
      chunkSize: 1024 * 1024,
      onProgress: (stage: string, progress: number) => {
        console.log(`[${stage}] ${progress}%`);
      },
    });
    
    if (!result.success) {
      return { success: false, error: result.error };
    }
    
    // Upload to server
    const formData = new FormData();
    formData.append('file', result.encryptedFile, file.name);
    formData.append('aesKeyBase64', result.aesKeyBase64);
    
    const response = await fetch('/api/files/upload', {
      method: 'POST',
      body: formData,
    });
    
    if (!response.ok) {
      throw new Error('Upload failed');
    }
    
    const data = await response.json();
    return { success: true, fileId: data.fileId };
  } catch (error) {
    return { 
      success: false, 
      error: error instanceof Error ? error.message : 'Unknown error' 
    };
  }
}

HTTP Client Integration

Using Fetch API

The SDK works perfectly with the native Fetch API available in modern browsers and Node.js 18+.

import { E2EECore } from '@everabyte/evb-sdk-typescript/e2ee';

// Upload with Fetch
async function uploadWithFetch(file: File) {
  const e2ee = new E2EECore();
  
  // Encrypt file
  const result = await e2ee.prepareUpload({
    file: file,
    chunkSize: 1024 * 1024,
    onProgress: (stage, progress) => {
      console.log(`${stage}: ${progress}%`);
    },
  });
  
  if (!result.success) {
    throw new Error(result.error);
  }
  
  // Upload with Fetch
  const formData = new FormData();
  formData.append('file', result.encryptedFile, file.name);
  formData.append('aesKeyBase64', result.aesKeyBase64);
  formData.append('originalSize', file.size.toString());
  formData.append('mimeType', file.type);
  
  const response = await fetch('/api/files/upload', {
    method: 'POST',
    body: formData,
    // Note: Don't set Content-Type header when using FormData
    // Fetch will set it automatically with the correct boundary
  });
  
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  
  const data = await response.json();
  return data.fileId;
}

// Download with Fetch
async function downloadWithFetch(fileId: string) {
  const e2ee = new E2EECore();
  
  // Download encrypted file
  const response = await fetch(`/api/files/download/${fileId}`);
  
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  
  const encryptedData = await response.arrayBuffer();
  
  // Get HPKE metadata from headers
  const encapsulatedKey = response.headers.get('X-HPKE-Encapsulated-Key') || '';
  const ciphertext = response.headers.get('X-HPKE-Ciphertext') || '';
  
  // Decrypt file
  const result = await e2ee.decryptDownload({
    encryptedData: encryptedData,
    encapsulatedKey: encapsulatedKey,
    ciphertext: ciphertext,
    onProgress: (progress) => {
      console.log(`Decrypting: ${progress}%`);
    },
  });
  
  if (!result.success) {
    throw new Error(result.error);
  }
  
  return result.decryptedFile;
}

// Usage in browser
const fileInput = document.querySelector('input[type="file"]');
fileInput?.addEventListener('change', async (e) => {
  const file = (e.target as HTMLInputElement).files?.[0];
  if (!file) return;
  
  try {
    const fileId = await uploadWithFetch(file);
    console.log('File uploaded:', fileId);
    
    const decryptedBlob = await downloadWithFetch(fileId);
    const url = URL.createObjectURL(decryptedBlob);
    const link = document.createElement('a');
    link.href = url;
    link.download = file.name;
    link.click();
    URL.revokeObjectURL(url);
  } catch (error) {
    console.error('Error:', error);
  }
});

Using Axios

For better error handling, request cancellation, and interceptors, you can use Axios.

import axios, { AxiosInstance, AxiosProgressEvent } from 'axios';
import { E2EECore } from '@everabyte/evb-sdk-typescript/e2ee';

// Create Axios instance with configuration
const apiClient: AxiosInstance = axios.create({
  baseURL: 'https://api.everabyte.io/api',
  timeout: 30000,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Upload with Axios
async function uploadWithAxios(
  file: File,
  onProgress?: (progress: number) => void
): Promise<string> {
  const e2ee = new E2EECore();
  
  // Encrypt file
  const result = await e2ee.prepareUpload({
    file: file,
    chunkSize: 1024 * 1024,
    onProgress: (stage, progress) => {
      console.log(`${stage}: ${progress}%`);
    },
  });
  
  if (!result.success) {
    throw new Error(result.error);
  }
  
  // Upload with Axios
  const formData = new FormData();
  formData.append('file', result.encryptedFile, file.name);
  formData.append('aesKeyBase64', result.aesKeyBase64);
  formData.append('originalSize', file.size.toString());
  formData.append('mimeType', file.type);
  
  const response = await apiClient.post('/files/upload', formData, {
    headers: {
      'Content-Type': 'multipart/form-data',
    },
    onUploadProgress: (progressEvent: AxiosProgressEvent) => {
      if (progressEvent.total && onProgress) {
        const percentCompleted = Math.round(
          (progressEvent.loaded * 100) / progressEvent.total
        );
        onProgress(percentCompleted);
      }
    },
  });
  
  return response.data.fileId;
}

// Download with Axios
async function downloadWithAxios(
  fileId: string,
  onProgress?: (progress: number) => void
): Promise<Blob> {
  const e2ee = new E2EECore();
  
  // Download encrypted file
  const response = await apiClient.get<ArrayBuffer>(`/files/download/${fileId}`, {
    responseType: 'arraybuffer',
    onDownloadProgress: (progressEvent: AxiosProgressEvent) => {
      if (progressEvent.total && onProgress) {
        const percentCompleted = Math.round(
          (progressEvent.loaded * 100) / progressEvent.total
        );
        onProgress(percentCompleted);
      }
    },
  });
  
  const encryptedData = response.data;
  
  // Get HPKE metadata from headers
  const encapsulatedKey = response.headers['x-hpke-encapsulated-key'] || '';
  const ciphertext = response.headers['x-hpke-ciphertext'] || '';
  
  // Decrypt file
  const result = await e2ee.decryptDownload({
    encryptedData: encryptedData,
    encapsulatedKey: encapsulatedKey,
    ciphertext: ciphertext,
    onProgress: (progress) => {
      console.log(`Decrypting: ${progress}%`);
    },
  });
  
  if (!result.success) {
    throw new Error(result.error);
  }
  
  return result.decryptedFile;
}

// Usage example with progress tracking
async function uploadExample() {
  const file = /* Get file from input */;
  
  try {
    console.log('Starting upload...');
    const fileId = await uploadWithAxios(file, (progress) => {
      console.log(`Upload progress: ${progress}%`);
    });
    console.log('Upload complete! File ID:', fileId);
  } catch (error) {
    console.error('Upload failed:', error);
  }
}

// Usage example with error handling
async function downloadExample(fileId: string) {
  try {
    console.log('Starting download...');
    const decryptedBlob = await downloadWithAxios(fileId, (progress) => {
      console.log(`Download progress: ${progress}%`);
    });
    console.log('Download complete!');
    
    // Save file
    const url = URL.createObjectURL(decryptedBlob);
    const link = document.createElement('a');
    link.href = url;
    link.download = `decrypted-${fileId}`;
    link.click();
    URL.revokeObjectURL(url);
  } catch (error) {
    if (axios.isAxiosError(error)) {
      console.error('Download failed:', error.response?.data || error.message);
    } else {
      console.error('Download failed:', error);
    }
  }
}

Advanced Axios Configuration

import axios, { AxiosInstance } from 'axios';

// Create Axios instance with interceptors
const createApiClient = (baseURL: string): AxiosInstance => {
  const client = axios.create({
    baseURL,
    timeout: 60000, // 60 seconds
  });
  
  // Request interceptor
  client.interceptors.request.use(
    (config) => {
      // Add auth token if available
      const token = localStorage.getItem('authToken');
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
      return config;
    },
    (error) => Promise.reject(error)
  );
  
  // Response interceptor
  client.interceptors.response.use(
    (response) => response,
    (error) => {
      // Handle common errors
      if (error.response?.status === 401) {
        // Redirect to login
        window.location.href = '/login';
      }
      return Promise.reject(error);
    }
  );
  
  return client;
};

// Usage
const api = createApiClient('https://api.everabyte.io/api');

async function uploadWithAuth(file: File) {
  const e2ee = new E2EECore();
  const result = await e2ee.prepareUpload({ file });
  
  if (!result.success) {
    throw new Error(result.error);
  }
  
  const formData = new FormData();
  formData.append('file', result.encryptedFile, file.name);
  formData.append('aesKeyBase64', result.aesKeyBase64);
  
  const response = await api.post('/files/upload', formData);
  return response.data.fileId;
}

Quick Start

Step 1: Import and Configure

import { configureSDK } from '@everabyte/evb-sdk-typescript/config';
import { E2EECore } from '@everabyte/evb-sdk-typescript/e2ee';

// Configure SDK (optional)
configureSDK({
  apiBaseUrl: 'https://api.everabyte.io/api',
  chunkSize: 1024 * 1024, // 1MB chunks
  debug: false,
});

Step 2: Encrypt and Upload a File

const e2ee = new E2EECore();

// Encrypt file client-side (zero-knowledge)
const result = await e2ee.prepareUpload({
  file: myFile,
  chunkSize: 1024 * 1024, // 1MB chunks
  onProgress: (stage, progress) => {
    console.log(`${stage}: ${progress}%`);
  },
});

if (result.success) {
  // Upload encrypted file to server
  const formData = new FormData();
  formData.append('file', result.encryptedFile, myFile.name);
  formData.append('aesKeyBase64', result.aesKeyBase64);
  
  const response = await fetch('/api/files/upload', {
    method: 'POST',
    body: formData,
  });
  
  console.log('File uploaded successfully!');
} else {
  console.error('Encryption failed:', result.error);
}

Step 3: Download and Decrypt a File

// Download encrypted file
const response = await fetch('/api/files/download/FILE_ID');
const encryptedData = await response.arrayBuffer();

// Get HPKE metadata from response headers
const encapsulatedKey = response.headers.get('X-HPKE-Encapsulated-Key') || '';
const ciphertext = response.headers.get('X-HPKE-Ciphertext') || '';

// Decrypt file
const result = await e2ee.decryptDownload({
  encryptedData,
  encapsulatedKey,
  ciphertext,
  onProgress: (progress) => {
    console.log(`Decrypting: ${progress}%`);
  },
});

if (result.success) {
  // Save decrypted file
  const blob = result.decryptedFile;
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = 'decrypted-file.txt';
  link.click();
  URL.revokeObjectURL(url);
}

Complete Usage Examples

File Upload with Progress Tracking (Browser)

import { E2EECore } from '@everabyte/evb-sdk-typescript/e2ee';

async function uploadFile(file: File) {
  const e2ee = new E2EECore();
  
  // Encrypt file client-side
  const result = await e2ee.prepareUpload({
    file: file,
    chunkSize: 1024 * 1024, // 1MB chunks
    onProgress: (stage, progress) => {
      console.log(`[${stage}] ${progress}%`);
      // Update UI progress bar
      updateProgressBar(stage, progress);
    },
  });
  
  if (!result.success) {
    throw new Error(result.error);
  }
  
  // Upload encrypted file to server
  const formData = new FormData();
  formData.append('file', result.encryptedFile, file.name);
  formData.append('aesKeyBase64', result.aesKeyBase64);
  formData.append('originalSize', file.size.toString());
  formData.append('mimeType', file.type);
  
  const response = await fetch('/api/files/upload', {
    method: 'POST',
    body: formData,
  });
  
  if (!response.ok) {
    throw new Error('Upload failed');
  }
  
  const data = await response.json();
  return data.fileId;
}

// Usage
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  try {
    const fileId = await uploadFile(file);
    console.log('File uploaded:', fileId);
  } catch (error) {
    console.error('Error:', error);
  }
});

File Download with Decryption

import { E2EECore } from '@everabyte/evb-sdk-typescript/e2ee';

async function downloadFile(fileId: string) {
  const e2ee = new E2EECore();
  
  // Download encrypted file
  const response = await fetch(`/api/files/download/${fileId}`);
  
  if (!response.ok) {
    throw new Error('Download failed');
  }
  
  const encryptedData = await response.arrayBuffer();
  
  // Get HPKE metadata from headers
  const encapsulatedKey = response.headers.get('X-HPKE-Encapsulated-Key') || '';
  const ciphertext = response.headers.get('X-HPKE-Ciphertext') || '';
  
  // Decrypt file
  const result = await e2ee.decryptDownload({
    encryptedData: encryptedData,
    encapsulatedKey: encapsulatedKey,
    ciphertext: ciphertext,
    onProgress: (progress) => {
      console.log(`Decrypting: ${progress}%`);
    },
  });
  
  if (!result.success) {
    throw new Error(result.error);
  }
  
  // Save file
  const blob = result.decryptedFile;
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = 'decrypted-file.txt';
  link.click();
  URL.revokeObjectURL(url);
}

// Usage
downloadFile('file-id-123').catch(console.error);

HPKE Key Management

import { HPKEKeyManager } from '@everabyte/evb-sdk-typescript/e2ee';

async function setupUserKeys(userId: string) {
  const keyManager = HPKEKeyManager.getInstance();
  
  // Check if user already has keys
  const existingPublicKey = keyManager.getPublicKey(userId);
  if (existingPublicKey) {
    console.log('User already has keys');
    return existingPublicKey;
  }
  
  // Generate new key pair
  const keyPair = await keyManager.generateKeyPair();
  
  // Store keys (in memory or secure storage)
  keyManager.storeKeyPair(userId, keyPair);
  
  // Upload public key to server
  await fetch('/api/users/keys', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      publicKey: keyPair.publicKey,
    }),
  });
  
  console.log('Keys generated and stored');
  return keyPair.publicKey;
}

// Usage
setupUserKeys('user-123').then(publicKey => {
  console.log('Public key:', publicKey);
});

Sharing Files with Other Users

import { E2EECore } from '@everabyte/evb-sdk-typescript/e2ee';

async function shareFile(file: File, recipientPublicKey: string) {
  const e2ee = new E2EECore();
  
  // Step 1: Encrypt file
  const encryptResult = await e2ee.prepareUpload({
    file: file,
    chunkSize: 1024 * 1024,
  });
  
  if (!encryptResult.success) {
    throw new Error(encryptResult.error);
  }
  
  // Step 2: Encapsulate AES key for recipient
  const hpkeResult = await e2ee.encapsulateAESKey(
    recipientPublicKey,
    encryptResult.aesKeyBase64
  );
  
  // Step 3: Upload with recipient-specific metadata
  const formData = new FormData();
  formData.append('file', encryptResult.encryptedFile, file.name);
  formData.append('encapsulatedKey', hpkeResult.encapsulatedKey);
  formData.append('ciphertext', hpkeResult.ciphertext);
  
  const response = await fetch('/api/files/share', {
    method: 'POST',
    body: formData,
  });
  
  return response.json();
}

// Usage
shareFile(myFile, 'recipient-public-key-base64')
  .then(result => console.log('File shared:', result));

React Integration Example

import React, { useState } from 'react';
import { E2EECore } from '@everabyte/evb-sdk-typescript/e2ee';

function FileUpload() {
  const [uploading, setUploading] = useState(false);
  const [progress, setProgress] = useState(0);
  const [status, setStatus] = useState('');

  const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    setUploading(true);
    setProgress(0);
    setStatus('Encrypting...');

    try {
      const e2ee = new E2EECore();
      
      // Encrypt file
      const result = await e2ee.prepareUpload({
        file,
        onProgress: (stage, currentProgress) => {
          setStatus(stage);
          setProgress(currentProgress);
        },
      });

      if (!result.success) {
        throw new Error(result.error);
      }

      setStatus('Uploading...');

      // Upload to server
      const formData = new FormData();
      formData.append('file', result.encryptedFile);
      formData.append('aesKeyBase64', result.aesKeyBase64);

      const response = await fetch('/api/files/upload', {
        method: 'POST',
        body: formData,
      });

      if (!response.ok) {
        throw new Error('Upload failed');
      }

      setStatus('Complete!');
      setProgress(100);
    } catch (error) {
      setStatus(`Error: ${error.message}`);
    } finally {
      setUploading(false);
    }
  };

  return (
    <div>
      <input
        type="file"
        onChange={handleFileUpload}
        disabled={uploading}
      />
      {uploading && (
        <div>
          <p>{status}</p>
          <progress value={progress} max={100} />
          <p>{progress}%</p>
        </div>
      )}
    </div>
  );
}

export default FileUpload;

Vue.js Integration Example

<template>
  <div>
    <input
      type="file"
      @change="handleFileUpload"
      :disabled="uploading"
    />
    <div v-if="uploading">
      <p>{{ status }}</p>
      <progress :value="progress" max="100"></progress>
      <p>{{ progress }}%</p>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { E2EECore } from '@everabyte/evb-sdk-typescript/e2ee';

const uploading = ref(false);
const progress = ref(0);
const status = ref('');

const handleFileUpload = async (e: Event) => {
  const target = e.target as HTMLInputElement;
  const file = target.files?.[0];
  if (!file) return;

  uploading.value = true;
  progress.value = 0;
  status.value = 'Encrypting...';

  try {
    const e2ee = new E2EECore();
    
    const result = await e2ee.prepareUpload({
      file,
      onProgress: (stage, currentProgress) => {
        status.value = stage;
        progress.value = currentProgress;
      },
    });

    if (!result.success) {
      throw new Error(result.error);
    }

    status.value = 'Uploading...';

    const formData = new FormData();
    formData.append('file', result.encryptedFile);
    formData.append('aesKeyBase64', result.aesKeyBase64);

    const response = await fetch('/api/files/upload', {
      method: 'POST',
      body: formData,
    });

    if (!response.ok) {
      throw new Error('Upload failed');
    }

    status.value = 'Complete!';
    progress.value = 100;
  } catch (error) {
    status.value = `Error: ${error.message}`;
  } finally {
    uploading.value = false;
  }
};
</script>

🔒 Security Architecture

Zero-Knowledge Flow

┌─────────────────────────────────────────────────────────────┐
│                         CLIENT                              │
│                        (Browser)                            │
│                                                             │
│  1. Generate AES-256 key                                    │
│  2. Encrypt file with AES-256-GCM (chunked)                │
│  3. Encapsulate AES key with HPKE (X25519)                 │
│  4. Send encrypted file + encapsulated key                  │
└────────────────────────┬────────────────────────────────────┘
                         │
                         │ Encrypted Data Only
                         │ (No plaintext, no private keys)
                         ▼
┌─────────────────────────────────────────────────────────────┐
│                         SERVER                              │
│                      (Ephemeral)                            │
│                                                             │
│  ✓ Receives encrypted file                                 │
│  ✓ Receives encapsulated AES key                           │
│  ✗ NEVER sees plaintext                                    │
│  ✗ NEVER sees private keys                                 │
│  ✗ CANNOT decrypt files                                    │
└────────────────────────┬────────────────────────────────────┘
                         │
                         │ Encrypted Data Only
                         ▼
┌─────────────────────────────────────────────────────────────┐
│                        STORAGE                              │
│                    (S3, Database, etc)                      │
│                                                             │
│  ✓ Stores encrypted files                                  │
│  ✓ Stores encapsulated keys                                │
│  ✗ NO plaintext data                                       │
└─────────────────────────────────────────────────────────────┘

Cryptographic Specifications

| Component | Algorithm | Key Size | Security Level | |-----------|-----------|----------|----------------| | HPKE KEM | X25519 (ECDH) | 256-bit | 128-bit security | | HPKE KDF | HKDF-SHA256 | 256-bit | 256-bit security | | HPKE AEAD | AES-256-GCM | 256-bit | 256-bit security | | File Encryption | AES-256-GCM | 256-bit | 256-bit security | | Nonce | Random | 96-bit | - |

Security Guarantees

Zero-Knowledge: Server never sees plaintext files or private keys
Forward Secrecy: Compromised keys don't reveal past communications
Authenticated Encryption: AES-GCM provides integrity and authenticity
Ephemeral Keys: Each file gets a unique AES-256 key
RFC 9180 Compliant: HPKE implementation follows IETF standard

🔧 API Reference

E2EECore

Main class for E2EE operations.

prepareUpload(options)

Encrypt a file for zero-knowledge upload.

Parameters:

{
  file: File;                    // File to encrypt
  chunkSize?: number;            // Chunk size in bytes (default: 1MB)
  onProgress?: (stage: 'encrypting' | 'uploading', progress: number) => void;
}

Returns:

{
  encryptedFile: Blob;           // Encrypted file data
  aesKeyBase64: string;          // AES-256 key (base64 encoded)
  success: boolean;              // Operation status
  error?: string;                // Error message if failed
}

decryptDownload(options)

Decrypt a downloaded file.

Parameters:

{
  encryptedData: ArrayBuffer | Blob;  // Encrypted file data
  encapsulatedKey?: string;           // HPKE encapsulated key (optional)
  ciphertext?: string;                // HPKE ciphertext (optional)
  aesKeyBase64?: string;              // Direct AES key (optional)
  onProgress?: (progress: number) => void;
}

Returns:

{
  decryptedFile: Blob;           // Decrypted file data
  success: boolean;              // Operation status
  error?: string;                // Error message if failed
}

encapsulateAESKey(recipientPublicKey, aesKeyBase64)

Encapsulate AES key for another user using HPKE.

Parameters:

  • recipientPublicKey (string): Recipient's HPKE public key
  • aesKeyBase64 (string): AES key to encapsulate

Returns:

{
  encapsulatedKey: string;       // HPKE encapsulated key
  ciphertext: string;            // HPKE ciphertext
}

HPKEKeyManager

Manage HPKE X25519 key pairs.

import { HPKEKeyManager } from '@everabyte/evb-sdk-typescript/e2ee';

const keyManager = HPKEKeyManager.getInstance();

// Generate key pair
const keyPair = await keyManager.generateKeyPair();

// Store key pair
keyManager.storeKeyPair(userId, keyPair);

// Get public key
const publicKey = keyManager.getPublicKey(userId);

// Get private key
const privateKey = keyManager.getPrivateKey(userId);

// Clear all keys
keyManager.clearAllKeys();

❓ FAQ

Q: Is this SDK suitable for production use?

A: Yes! This SDK has 100% test coverage and follows industry best practices for cryptographic implementations.

Q: Can I use this SDK in Node.js?

A: Yes! The SDK now supports Node.js 16.0.0+ out of the box. It automatically detects the environment and uses the appropriate crypto implementation (crypto module for Node.js, Web Crypto API for browsers).

Q: Can I use this SDK in TypeScript?

A: Absolutely! The SDK is written in TypeScript and includes full type definitions. It supports TypeScript 5.0+.

Q: Can I use this SDK in React/Vue/Angular?

A: Yes! The SDK works perfectly with all modern frontend frameworks that support TypeScript. See the React and Vue.js examples above.

Q: How secure is the encryption?

A: The SDK uses:

  • AES-256-GCM: Industry-standard symmetric encryption
  • HPKE (RFC 9180): IETF-standardized hybrid encryption
  • X25519: Modern elliptic curve cryptography

This provides 256-bit security for file encryption and 128-bit security for key exchange.

Q: What happens if I lose my private key?

A: You will permanently lose access to your encrypted files. The server cannot help you recover your data because it never has access to your private keys (zero-knowledge architecture).

Q: Can I share files with other users?

A: Yes! Use the encapsulateAESKey() method to encrypt the file's AES key for a specific recipient's public key.

Q: What's the maximum file size?

A: The SDK supports files of any size through chunked encryption. The default chunk size is 1MB, but you can adjust it based on your needs.

Q: Does the SDK work in React Native?

A: React Native support is planned. You'll need a Web Crypto API polyfill like react-native-webview-crypto or @peculiar/webcrypto to use it in React Native.

📄 License

MIT License - See LICENSE file for details.

🆘 Support


Made with ❤️ by Everabyte

WebsiteDocumentationBlog