Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@lattestack/vault
Advanced tools
Vault is a wrapper around the Web Cryptography API available in modern browsers and NodeJS, it provides secure and easy-to-use cryptographic APIs for encrypting and decrypting data using AES-256-GCM and Elliptic-curve cryptography.
Vault is a wrapper around the Web Cryptography API available in modern browsers and NodeJS, it provides secure and easy-to-use cryptographic APIs for encrypting and decrypting data using AES-256-GCM and Elliptic-curve cryptography.
npm install --save @lattestack/vault
For Node.js versions 19 and below, include the following statement in the program's entry point:
globalThis.crypto ??= require('crypto').webcrypto
globalThis.Blob ??= require('buffer').Blob
globalThis.ReadableStream ??= require('stream/web').ReadableStream
globalThis.TransformStream ??= require('stream/web').TransformStream
import { Recipient, Encryption, Decryption } from '@lattestack/vault'
// Set your confidential data here
const plaintext = 'CONFIDENTIAL_DATA'
// Generate a Recipient representing Alice.
const alice = await Recipient.generate()
// Add Alice as a recipient,
// then encrypt the plaintext and outputs as text.
// Now only Alice can decrypt the ciphertext
const ciphertext = await new Encryption(plaintext)
.addRecipient(alice)
.text()
// Set Alice as the recipient,
// then decrypt the ciphertext and outputs as raw text.
const decryptedText = await new Decryption(ciphertext)
.setRecipient(alice)
.text()
// => true
console.log(decryptedText === plaintext)
The Encryption
interface is used to encrypt plaintext into ciphertext. The plaintext passed into Encryption will be encrypted using a hybrid encryption scheme combining AES-256-GCM and Elliptic-curve cryptography.
constructor(plaintext: string | ArrayBuffer | Blob)
plaintext
addRecipient(recipient: Recipient | string): this
Add a recipient. This method can be called multiple times to add multiple recipients. Only the recipients added here can decrypt the corresponding data.
recipient
text(): Promise<string>
Outputs ciphertext as String. Note that string here are encoded as Base64URL.
arrayBuffer(): Promise<ArrayBuffer>
Outputs ciphertext as ArrayBuffer.
stream(): ReadableStream<Uint8Array>
Outputs ciphertext as ReadableStream<Uint8Array>.
The Decryption
interface is used to decrypt ciphertext into plaintext.
constructor(ciphertext: string | ArrayBuffer | Blob)
ciphertext
setRecipient(recipient: Recipient): this
Set the recipient. Only the recipient added during encryption can decrypt the data.
recipient
text(): Promise<string>
Outputs plaintext as String. Note that string here are encoded as UTF-8.
arrayBuffer(): Promise<ArrayBuffer>
Outputs plaintext as ArrayBuffer.
stream(): ReadableStream<Uint8Array>
Outputs plaintext as ReadableStream<Uint8Array>.
The Recipient
interface is used to represent the owner of the data, which is usually used to represent a user.
When encrypting, you always need to add one or more recipients. Only the recipients that have been set during encryption can decrypt the corresponding data.
publicKey: string
The publicKey property, which does not contain any confidential information, can be openly shared. It can be passed as an argument to the Encryption.addRecipient function to encrypt data, but it cannot be used to decrypt data.
static generate(): Promise<Recipient>
Generete a new Recipient. You need to associate the recipient with a specific user on your own.
static export(recipient: Recipient, unlockKey: UnlockKey): Promise<string>
Export recipient as string. This allows you to persist the recipient to the storage.
recipient
unlockKey
static import(exportRecipient: string, unlockKey: UnlockKey): Promise<Recipient>
Import recipient from string. This allows you to instantiate the recipient from the storage.
exportRecipient
unlockKey
The UnlockKey
interface is used to protect the exported recipient from being stolen or misused. The unlockKey must be provided when importing or exporting the recipient.
static fromSecret(secret: string): Promise<UnlockKey>
Derive unlockKey from secret. It is not recommended to use this method to derive the unlockKey on the client-side because clients typically lack a secure way to store secrets.
secret
static fromPassword(password: string, salt: string, iterations: number): Promise<UnlockKey>
Derive unlockKey from password with PBKDF2-HMAC-SHA256.
password
The password to mix with the salt. You should set a password policy to prevent weak password.
salt
The salt to mix with the password. The salt should be a random value of at least 16 bytes to prevent the use of rainbow tables and other precomputed attacks. Salt does not need to be kept secret.
iterations
The number of times the hash function will be executed.
Generate recipients
import { Recipient } from '@lattestack/vault'
// Generate a recipient representing Alice.
const alice = await Recipient.generate()
// Generate a recipient representing Bob.
const bob = await Recipient.generate()
Export and persist recipient to storage
import { Recipient, UnlockKey } from '@lattestack/vault'
// Derive unlockKey from custom secret
const secret = process.env.CUSTOM_SECRET
const unlockKey = await UnlockKey.fromSecret(secret)
// Generate a recipient representing Alice.
const alice = await Recipient.generate()
// Export recipient(Alice) with unlockKey
const exportedAlice = Recipient.export(alice, unlockKey)
await storage.save('alice', exportedAlice)
Import and instantiate recipient from storage
import { Recipient, UnlockKey } from '@lattestack/vault'
// Derive unlockKey from custom secret
const secret = process.env.CUSTOM_SECRET
const unlockKey = await UnlockKey.fromSecret(secret)
// Retrieve exported recipient(Alice) from storage
const exportedAlice = await storage.get('alice')
// Import recipient(Alice) with unlockKey
const alice = await Recipient.import(exportedAlice, unlockKey)
Encrypt text data
import { Recipient, Encryption } from '@lattestack/vault'
const alice = await Recipient.import(/**/)
const ciphertext = await new Encryption('DATA')
.addRecipient(alice)
.text()
Encrypt binary data
import { Recipient, Encryption } from '@lattestack/vault'
const alice = await Recipient.import(/**/)
const buffer = new TextEncoder().encode('DATA')
const ciphertext = await new Encryption(buffer)
.addRecipient(alice)
.arrayBuffer()
Encrypt file by streaming
This allows you to encrypt large files with less memory.
import { Recipient, Encryption } from '@lattestack/vault'
const alice = await Recipient.import(/**/)
const fileStream = new Blob([/**/]).stream()
const encryptionStream = new Encryption(fileStream)
.addRecipient(alice)
.stream()
Public-key encryption
Public-key encryption lets you add multiple recipients to the data without sharing the secrets of each recipient.
const registry = new Map()
// Alice share her publicKey with the public registry.
const alice = await Recipient.import(/**/)
registry.set('alice', alice.publicKey)
// Bob share his publicKey with the public registry.
const bob = await Recipient.import(/**/)
registry.set('bob', bob.publicKey)
// Carol share his publicKey with the public registry.
const carol = await Recipient.import(/**/)
registry.set('carol', carol.publicKey)
// Encrypt the secrets by the three and add all three of them as recipients.
// We encrypt the data using publicKey(s) here.
const ciphertext = await new Encryption('SECRETS')
.addRecipient(registry.get('alice'))
.addRecipient(registry.get('bob'))
.addRecipient(registry.get('carol'))
.text()
// All three were then able to decrypt the data.
await new Decryption(ciphertext).setRecipient(alice).text()
await new Decryption(ciphertext).setRecipient(bob).text()
await new Decryption(ciphertext).setRecipient(carol).text()
Each Recipient holds the following information:
ECDH
(Elliptic Curve Diffie-Hellman) keyPair.ECDSA
(Elliptic Curve Digital Signature Algorithm) keyPair.All encrypted output is essentially binary data in the following format:
| headerSize: UInt32 | header: String | ...chunks: Bytes |
CPri
and CPub
CPub
in header
CEK
RPub
be the recipient's public keyRPubT = thumbprint(RPub)
KEK = deriveKey(CPri, RPub)
WCEK = wrapKey(CEK, KEK)
RPubT
, WCEK
as key-value in header
.p
be the blockn
be the block ordinala = sha256(header + n)
iv
c = aes_encrypt(CEK, p, iv, a)
iv
and c
in the chunk
header
from encrypted outputCPub
from header
RPub
be the recipient's public keyRPubT = thumbprint(RPub)
WCEK
by RPubT
from header
RPri
be the recipient's private keyKEK = deriveKey(RPri, CPub)
CEK = unwrapKey(WCEK, KEK)
chunk
be the blockn
be the block ordinala = sha256(header + n)
iv
from chunk
c
from chunk
p = aes_decrypt(CEK, c, iv, a)
Distributed under the Dual License. See LICENSE
for more information.
FAQs
Vault is a wrapper around the Web Cryptography API available in modern browsers and NodeJS, it provides secure and easy-to-use cryptographic APIs for encrypting and decrypting data using AES-256-GCM and Elliptic-curve cryptography.
The npm package @lattestack/vault receives a total of 322 weekly downloads. As such, @lattestack/vault popularity was classified as not popular.
We found that @lattestack/vault demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.