This library provides wrappers on the put
and get
functions from the Cloudflare Workers runtime API for writing to and reading from Workers KV, encrypting values before put
and decrypting values after get
. Encryption is implemented using the Web Crypto API to derive AES-GCM keys from a password based key (PBKDF2).
By default all data stored in Cloudflare Workers KV is encrypted at rest:
All values are encrypted at rest with 256-bit AES-GCM, and only decrypted by the process executing your Worker scripts or responding to your API requests. (docs)
However, there are a variety of reasons you may want to add your own encryption to the values stored in Workers KV. For example, permissions to access Workers KV are scoped at the account level. For those working in shared team or organizational accounts, this means you cannot limit access to specific KV namespaces, as anyone in that account with access to Workers can read the stored data in all KV namespaces in that account.
Use npm to install this package while in the root directory of your Workers project:
npm i encrypt-workers-kv
- putEncryptedKV(namespace, key, data, password, options)
Wrapper on Workers KV put command that encrypts data prior to storage
- getDecryptedKV(namespace, key, password)
Wrapper on Workers KV get command that decrypts data after getting from storage
Wrapper on Workers KV put command that encrypts data prior to storage
Param | Type | Description |
---|---|---|
namespace | KVNamespace |
the binding to the namespace that script references |
key | string |
the key in the namespace used to reference the stored value |
data | string or ArrayBuffer |
the data to encrypt and store in KV |
password | string |
the password to be used to encrypt the data |
iterations | number |
optional number of iterations used by the PBKDF2 to derive the key. Default 10000 |
options | Object |
optional KV put fields (docs) |
Returns encrypted value as string - Promise<ArrayBuffer>
Sample implementation:
let data = await request.text()
try {
await putEncryptedKV(ENCRYPTED, 'data', data, password)
return new Response('Secret stored successfully')
} catch (e) {
return new Response(e.message, { status: e.status })
}
Wrapper on Workers KV get command that decrypts data after getting from storage
Param | Type | Description |
---|---|---|
namespace | KVNamespace |
the binding to the namespace that script references |
key | string |
the key in the namespace used to reference the stored value |
password | string |
the password used to encrypt the data |
Returns decrypted value as string - Promise<ArrayBuffer>
Sample implementation:
try {
let decryptedData = await getDecryptedKV(ENCRYPTED, 'data', password)
let strDecryptedData = dec.decode(decryptedData)
return new Response(`${strDecryptedData}`, {
headers: { 'content-type': 'text/html; charset=utf-8' },
})
} catch (e) {
return new Response(e.message, { status: e.status })
}
An explanation of the steps used behind the scenes for encryption and decryption in src/index.ts
.
Encryption:
- Creates a password based key (PBKDF2) that will be used to derive the AES-GCM key used for encryption / decryption.
- Creates an AES-GCM key using the PBKDF2 key and a randomized salt value.
- Encrypts the input data using the AES-GCM key and a randomized initialization vector (iv).
- The values used for the password, salt, iv for encryption are needed for decryption. Therefore, creates an ArrayBuffer to be stored that includes the salt that was used when creating the password based key (PBKDF2), iv used for creating the AES key, and the encrypted content. The password should remain secret, so recommend storing it as a Worker Secret.
Decryption:
- Derives the salt, iv, and encrypted data from the ArrayBuffer.
- Creates a password based key (PBKDF2) that will be used to derive the AES-GCM key used for encryption / decryption. Password must be the same used for encryption and is obtained from the Workers Secret.
- Creates an AES-GCM key using the PBKDF2 key and the salt from the ArrayBuffer.
- Decrypts the input data using the AES-GCM key and the iv from the ArrayBuffer.
A test worker is used to test the library, located in test-worker/
. Configure wrangler.toml
in that folder with your account information. Then, create a new Workers KV namespace and add the configuration to wrangler.toml.
wrangler kv:namespace create "ENCRYPTED"
Add the password for PBKDF2 as a Workers Secret.
wrangler secret put PASSWORD
To deploy the test worker and run the the automated tests, change directory back to the project root directory and:
npm run test:deploy && npm run test
A sample implementation is available in the Workers Azure AD auth example, which uses encrypt-workers-kv
to encrypt session token information stored as values in Workers KV.
Further info on Web Crypto usage:
- Ernie Turner: Dodging Web Crypto API Landmines | Web Rebels 2018
- Web Crypto API
- Example usage in browser bradyjoslin/webcrypto-example