bVault-js is a type-safe, lightweight, zero-dependency cryptographic library for secure encryption and decryption in browser environments. It implements AES-GCM encryption with PBKDF2 key derivation, providing a simple API for data protection.
- 🔒 AES-GCM 256-bit encryption
- 🔑 Password-based key derivation (PBKDF2 with 100 thousand iterations)
- 🧂 Automatic salt and IV generation
- 🛡️ Built-in error handling for cryptographic operations
- 💻 Works in browsers (using Web Crypto API)
- 📦 Secure Local Storage Wrapper – store/retrieve data in
localStoragesecurely with automatic encryption/decryption - 📦 Secure Session Storage Wrapper – store/retrieve data in
sessionStoragesecurely with automatic encryption/decryption
npm install bvault-jsimport { encrypt, decrypt } from 'bvault-js';
const password = 'supersecretpassword';
const sensitiveData = 'My confidential information';
// Encrypt data
const { encryptedData, iv, salt } = await encrypt(sensitiveData, password);
console.log('Encrypted:', encryptedData);
console.log('IV:', iv);
console.log('Salt:', salt);
// Decrypt data
const decrypted = await decrypt(encryptedData, password, iv, salt);
console.log('Decrypted:', decrypted); // 'My confidential information'bVault-js provides a wrapper around localStorage so you can safely persist sensitive data in the browser.
import { initializeSecureStorage } from 'bvault-js';
async function bootstrap() {
await initializeSecureStorage('my-strong-password');
// Continue with app startup...
}
bootstrap();import { secureLocalStorage } from 'bvault-js';
// Store data securely
await secureLocalStorage.setItem('userProfile', {
username: 'alice',
email: '[email protected]',
});
// Retrieve data securely
const stored = await secureLocalStorage.getItem('userProfile');
const profile = stored ? JSON.parse(stored) : null;
console.log(profile);
// Remove a specific key
secureLocalStorage.removeItem('userProfile');
// Clear everything
secureLocalStorage.clear();bVault-js provides a wrapper around sessionStorage so you can securely store sensitive data that should only persist
for the duration of the browser session.
import { initializeSecureStorage } from 'bvault-js';
async function bootstrap() {
await initializeSecureStorage('my-strong-password');
// Continue with app startup...
}
bootstrap();import { secureSessionStorage } from 'bvault-js';
// Store data securely (persists only for this session)
await secureSessionStorage.setItem('authToken', 'abc123');
// Retrieve data securely
const stored = await secureSessionStorage.getItem('authToken');
console.log(stored); // "abc123"
// Remove a specific key
secureSessionStorage.removeItem('authToken');
// Clear everything for this session
secureSessionStorage.clear();- React (entry point initialization)
// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { initializeSecureStorage } from 'bvault-js';
async function bootstrap() {
await initializeSecureStorage('react-password');
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
}
bootstrap();or
// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { initializeSecureStorage } from 'bvault-js';
(async () => {
await initializeSecureStorage('react-password');
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
})();then
// App.tsx
import { useEffect, useState } from 'react';
import { secureLocalStorage, secureSessionStorage } from 'bvault-js';
export default function App() {
const [profile, setProfile] = useState<any>(null);
useEffect(() => {
(async () => {
await secureLocalStorage.setItem('profile', { username: 'carol' });
const data = await secureLocalStorage.getItem('profile');
if (data) profile = JSON.parse(data);
await secureSessionStorage.setItem('role', 'admin');
const roleData = await secureSession.getItem('role');
if (roleData) role = JSON.parse(roleData);
})();
}, []);
return <p>{profile ? `Hello ${profile.username}` : 'Loading...'}</p>;
}- Vue 3
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { initializeSecureStorage } from 'bvault-js';
async function bootstrap() {
await initializeSecureStorage('vue-password');
createApp(App).mount('#app');
}
bootstrap();or
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { initializeSecureStorage } from 'bvault-js';
(async () => {
await initializeSecureStorage('vue-password');
createApp(App).mount('#app');
})();then
<!-- App.vue -->
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { secureLocalStorage, secureSessionStorage } from 'bvault-js';
const profile = ref<any>(null);
onMounted(async () => {
await secureLocalStorage.setItem('profile', { username: 'bob' });
const data = await secureLocalStorage.getItem('profile');
if (data) profile = JSON.parse(data);
await secureSessionStorage.setItem('role', 'admin');
const roleData = await secureSessionStorage.getItem('role');
if (roleData) role = JSON.parse(roleData);
});
</script>
<template>
<p v-if="profile">Hello {{ profile.username }}</p>
<p v-else>Loading...</p>
<p v-if="role">Role: {{ role }}</p>
<p v-else>Loading...</p>
</template>- Svelte
// main.ts
import App from './App.svelte';
import { initializeSecureStorage } from 'bvault-js';
async function bootstrap() {
await initializeSecureStorage('svelte-password');
new App({ target: document.getElementById('app')! });
}
bootstrap();or
// main.ts
import App from './App.svelte';
import { initializeSecureStorage } from 'bvault-js';
(async () => {
await initializeSecureStorage('svelte-password');
new App({ target: document.getElementById('app')! });
})();then
<!-- App.svelte -->
<script lang="ts">
import { onMount } from 'svelte';
import { secureLocalStorage, secureSessionStorage } from 'bvault-js';
let profile: any = null;
onMount(async () => {
await secureLocalStorage.setItem('profile', { username: 'carol' });
const data = await secureLocalStorage.getItem('profile');
if (data) profile = JSON.parse(data);
await secureSessionStorage.setItem('role', 'admin');
const roleData = await secureSessionStorage.getItem('role');
if (roleData) role = JSON.parse(roleData);
});
</script>
<p>{#if profile}Hello {profile.username}{:else}Loading...{/if}</p>
<p>{#if role}Role: {role}{:else}Loading...{/if}</p>import { encrypt } from 'bvault-js';
async function encryptFile(file, password) {
const reader = new FileReader();
return new Promise((resolve, reject) => {
reader.onload = async () => {
try {
const encrypted = await encrypt(reader.result, password);
resolve(encrypted);
} catch (error) {
reject(error);
}
};
reader.readAsText(file);
});
}import { encrypt, decrypt } from 'bvault-js';
async function saveConfig(config, password) {
const encrypted = await encrypt(JSON.stringify(config), password);
return {
config: encrypted.encryptedData,
iv: encrypted.iv,
salt: encrypted.salt,
};
}
async function loadConfig(storedConfig, password) {
try {
const decrypted = await decrypt(
storedConfig.config,
password,
storedConfig.iv,
storedConfig.salt,
);
return JSON.parse(decrypted);
} catch (error) {
return null;
}
}Encrypts data using a password
Parameters:
data: String to encryptpassword: Encryption password
Returns: Promise resolving to:
{
encryptedData: string,
iv: string,
salt: string
}Decrypts data using the original password and stored parameters
Secure wrapper around localStorage with async encryption/decryption.
await secureLocalStorage.setItem(key: string, value: unknown)await secureLocalStorage.getItem(key: string): Promise<string | null>secureLocalStorage.removeItem(key: string)secureLocalStorage.clear()
Secure wrapper around sessionStorage with async encryption/decryption.
await secureSessionStorage.setItem(key: string, value: unknown)await secureSessionStorage.getItem(key: string): Promise<string | null>secureSessionStorage.removeItem(key: string)secureSessionStorage.clear()
Initializes secure storage. Must be called once (e.g., at app startup).
Checks if secure storage has been initialized.
The library throws specific error types for cryptographic operations:
EncryptionErrorDecryptionError
try {
const decrypted = await secureLocalStorage.getItem('someKey');
} catch (error) {
if (error instanceof DecryptionError) {
console.error('Decryption failed - check your password');
}
}- Password Strength: Always use strong, unique passwords for encryption
- Secure Storage: Safely store IVs and salts with encrypted data
- Never Hardcode: Never embed passwords in source code
- Key Management: Consider rotating encryption keys periodically
- Transport Security: Use HTTPS when transmitting encrypted data
While bVault-js provides robust encryption capabilities, it has some intentional limitations in its current version:
- No Key Rotation: Changing passwords requires re-encrypting all data
- No Key Export: Derived keys cannot be exported/backed up independently
- Fixed Iterations: PBKDF2 fixed at 100,000 iterations (secure but computationally expensive)
- Large Data: Not optimized for encrypting files >1GB due to memory constraints
- Fixed Algorithms: Only supports AES-GCM with 256-bit keys
- No Algorithm Agility: Cannot switch to other encryption algorithms
- String-Only Input: Only encrypts/decrypts UTF-8 strings (not binary data)
- No Stream Support: Requires complete data in memory
- No Key Stretching: Requires full PBKDF2 derivation on each operation
- No Session Caching: Keys aren't cached between operations
- Web Crypto Dependency: Requires modern browsers or Node.js v15+
- No Fallback: No alternative implementations for non-Web Crypto environments
- No Authentication: Doesn't verify data integrity before decryption
- No Key Separation: Same derivation parameters for encryption/decryption
We're actively working to enhance bVault-js with these planned features:
- Binary Data Support: Encrypt/decrypt ArrayBuffer and Blob types
- Configurable Algorithms: Allow choosing between AES-GCM and ChaCha20-Poly1305
- Key Management: Add key rotation and export capabilities
- Stream Processing: Support for large file encryption through stream processing
- Web Worker Support: Offload crypto operations to background threads
- Enhanced Security:
- Add authenticated data support (AAD) for AES-GCM
- Implement configurable iteration counts
- Add key derivation memory hardening (Argon2 support)
- Extended Environments:
- React Native compatibility
- Service worker support
- Developer Experience:
- Additional error diagnostics
- Password strength meter integration
- TypeScript type enhancements
Consider other solutions if you need:
- Binary data encryption/decryption today
- Encryption of files larger than 1GB
- Algorithm agility (e.g., ChaCha20-Poly1305 support)
- Hardware Security Module (HSM) integration
- Post-quantum cryptography algorithms
Contributions are welcome! Please read the Contribution Guidelines before submitting pull requests. We especially welcome help with items from our roadmap.
MIT © Aaron Will Djaba