crypto stream
Streaming encryption for the browser, based on
Encrypted Content-Encoding for HTTP (RFC 8188)
install
npm i -S @bicycle-codes/crypto-stream
fork
This is a fork of SocketDev/wormhole-crypto, just adding types.
example
import { Keychain } from '@bicycle-codes/crypto-stream'
const keychain = new Keychain()
const stream = getStream()
const encryptedStream = await keychain.encryptStream(stream)
const plaintextStream = await keychain.decryptStream(encryptedStream)
example with blobs
See ./example for a version that uses blobs + a
local vite
server.
API
new Keychain([key, [salt]])
constructor (key?:string|Uint8Array, salt?:string|Uint8Array)
Type: Class
Returns: Keychain
Create a new keychain object. The keychain can be used to create encryption
streams, decryption streams, and to encrypt or decrypt a "metadata" buffer.
key
Type: Uint8Array | string | null
Default: null
The main key. This should be 16 bytes in length. If a string
is given,
then it should be a base64-encoded string. If the argument is null
, then a
key will be automatically generated.
salt
Type: Uint8Array | string | null
Default: null
The salt. This should be 16 bytes in length. If a string
is given,
then it should be a base64-encoded string. If this argument is null
, then a
salt will be automatically generated.
keychain.key
key:Uint8Array
The main key.
keychain.keyB64
keyB64:string
The main key as a base64url-encoded string.
keychain.salt
salt:Uint8Array
The salt.
Implementation note: The salt is used to derive the (internal) metadata key and
authentication token.
keychain.saltB64
saltB64:string
The salt as a base64-encoded string.
keychain.authToken()
authToken ():Promise<ArrayBuffer>
Returns the authentication token. By default, the authentication token is
automatically derived from the main key using HKDF SHA-256.
The authentication token can be used to communicate with the server and
prove that the client has permission to fetch some data. Without a valid
authentication token, the server can reject the request.
Since the authentication token is derived from the main key, the client would
present it to the server as a "reader token" to prove that it is in possession
of the main key without revealing the main key to the server.
For destructive operations, the client should instead
present a "writer token", which is not derived from the main key but is provided
by the server.
keychain.authTokenB64()
authTokenB64 ():Promise<string>
Returns the authentication token as a base64-encoded string.
authHeader ():Promise<string>
Returns a Promise
that resolves to the HTTP header value to be provided to the server, as a base64 string. It contains the authentication token.
keychain.setAuthToken(authToken)
setAuthToken (authToken:string|Uint8Array|null):void
Update the keychain authentication token to the given authToken
.
authToken
Type: Uint8Array | string | null
Default: null
The authentication token. This should be 16 bytes in length. If a string
is
given, then it should be a base64-encoded string. If this argument is null
,
then an authentication token will be automatically generated.
keychain.encryptStream(stream)
encryptStream (stream:ReadableStream):Promise<ReadableStream>
Type: Function
Returns: Promise[ReadableStream]
Returns a Promise
that resolves to a ReadableStream
encryption stream that
consumes the data in stream
and returns an encrypted version. Data is
encrypted with Encrypted Content-Encoding for HTTP (RFC 8188).
stream
Type: ReadableStream
A WHATWG readable stream used as a data source for the encrypted stream.
keychain.decryptStream(encryptedStream)
Type: Function
Returns: Promise[ReadableStream]
Returns a Promise
that resolves to a ReadableStream
decryption stream that
consumes the data in encryptedStream
and returns a plaintext version.
keychain.decryptStreamRange(offset, length, totalEncryptedLength)
function decryptStreamRange (
secretKey:CryptoKey,
offset:number,
length:number,
totalEncryptedLength:number,
rs:number = RECORD_SIZE
):{
ranges:{ offset:number, length:number }[],
decrypt:(streams:ReadableStream[])=>ReadableStream
}
Returns a Promise
that resolves to a object containing ranges
, which is
an array of objects containing offset
and length
integers specifying the
encrypted byte ranges that are needed to decrypt the client's specified range,
and a decrypt
function.
Once the client has gathered a stream for each byte range in ranges
,
the client should call decrypt(streams)
, where streams
is an array of
ReadableStream
objects, one for each of the requested ranges. decrypt
will then return a ReadableStream
containing the plaintext data for the
client's desired byte range.
encryptedStream
Type: ReadableStream
A WHATWG readable stream used as a data source for the plaintext stream.
keychain.encryptMeta(meta)
encryptMeta (meta:Uint8Array):Promise<Uint8Array>
Returns a Promise
that resolves to an encrypted version of meta
. The
metadata is encrypted with AES-GCM.
Implementation note: The metadata key is automatically derived from the main
key using HKDF SHA-256. The value is not user-controlled.
Implementation note: The initialization vector (IV) is automatically generated
and included in the encrypted output. No need to generate it or to manage it
separately from the encrypted output.
meta
Type: Uint8Array
The metadata buffer to encrypt.
keychain.decryptMeta(ivEncryptedMeta)
decryptMeta (ivEncryptedMeta:Uint8Array):Promise<Uint8Array>
Returns: Promise[Uint8Array]
Returns a Promise
that resolves to a decrypted version of encryptedMeta
.
ivEncryptedMeta
Type: Uint8Array
The encrypted metadata buffer to decrypt.
plaintextSize(encryptedSize)
function plaintextSize (encryptedSize:number, rs = RECORD_SIZE):number
Given an encrypted size, return the corresponding plaintext size.
encryptedSize(plaintextSize)
function encryptedSize (plaintextSize:number, rs = RECORD_SIZE):number
Given a plaintext size, return the corresponding encrypted size.
credits
Thank you Feross and SocketDev team for writing and publishing this.