unstorage icon indicating copy to clipboard operation
unstorage copied to clipboard

feat(encryption): Implement e2e encryption using encryptedStorage composable

Open itpropro opened this issue 2 years ago โ€ข 4 comments

๐Ÿ”— Linked issue

#24

โ“ Type of change

  • [x] ๐Ÿ“– Documentation (updates to the documentation, readme, or JSdoc annotations)
  • [ ] ๐Ÿž Bug fix (a non-breaking change that fixes an issue)
  • [ ] ๐Ÿ‘Œ Enhancement (improving an existing functionality like performance)
  • [X] โœจ New feature (a non-breaking change that adds functionality)
  • [ ] ๐Ÿงน Chore (updates to the build process or auxiliary tools and libraries)
  • [ ] โš ๏ธ Breaking change (fix or feature that would cause existing functionality to change)

๐Ÿ“š Description

Implements a new composable function encryptedStorage similar to prefixStorage that wraps a unstorage instance and offers encryption for values and optionally for keys as well.

  • Adds new composable encryptedStorage that can also be used in combination with others like prefixStorage. Usage is encryptedStorage(createStorage({ driver }), encryptionKey, true) where the last parameter (set to true) defines if keys should also be encrypted
  • Uses @noble/ciphers for encryption, as it is 0 deps and works in Node, Bun, Deno and Workers (tested on CF). It supports AES-GCM-SIV (not implemented in Web/Node Crypto) which is nonce misuse resistant, what we need for deterministic key encryption with the same IV/nonce for keys.
  • For content encryption, XChaCha20-Poly1305 (which is also used in TLS 1.3) is used. It is a fast modern and future proof cipher and safe to use with random nonces. Nonces are generated with getRandomValues from uncrypto. The content is wrapped into a StorageValueEnvelope:
export interface StorageValueEnvelope {
  nonce: string;
  encryptedValue: string;
}
  • The implementation was tested against common drivers like fs, memory, redis, 'lrs' and azure-blob-storage for content as well as key encryption and in combination with prefixStorage:
    const storage = createStorage();
    const pStorage = prefixStorage(storage, "foo");
    const encStorage = encryptedStorage(pStorage, encryptionKey, true);
  • Tests include an encryption example for fs driver, an update to the testDriver utility to optionally test for content and key encryption as well es tests for the storage server and the combination with prefixStorage

๐Ÿ“ Checklist

  • [X] I have linked an issue or discussion.
  • [ ] I have updated the documentation accordingly.

itpropro avatar Jan 02 '24 15:01 itpropro

Would appreciate your feedback @pi0, @danielroe, @Atinux. If the implementation is fine for you, I would add an option to provide the encryption key via. env variable and write the docs.

itpropro avatar Jan 02 '24 16:01 itpropro

Codecov Report

Attention: 28 lines in your changes are missing coverage. Please review.

Comparison is base (293a2a6) 75.32% compared to head (1c88d64) 76.08%.

Files Patch % Lines
src/utils.ts 83.97% 25 Missing :warning:
src/drivers/encryption.ts 94.87% 2 Missing :warning:
src/_utils.ts 98.92% 1 Missing :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #363      +/-   ##
==========================================
+ Coverage   75.32%   76.08%   +0.76%     
==========================================
  Files          30       31       +1     
  Lines        3534     3822     +288     
  Branches      494      531      +37     
==========================================
+ Hits         2662     2908     +246     
- Misses        871      913      +42     
  Partials        1        1              

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov[bot] avatar Jan 02 '24 16:01 codecov[bot]

Anything I can do to bring this forward @pi0 ?

itpropro avatar Jun 25 '24 18:06 itpropro

Anything I can do to bring this forward @pi0 ?

@pi0 ?

itpropro avatar Sep 18 '24 18:09 itpropro