{"id":18401377,"url":"https://github.com/dozyio/js-blockstore-encrypt","last_synced_at":"2025-04-14T12:12:06.221Z","repository":{"id":257683629,"uuid":"858457262","full_name":"dozyio/js-blockstore-encrypt","owner":"dozyio","description":"Encrypted Blockstore for IPFS / Helia","archived":false,"fork":false,"pushed_at":"2024-10-13T17:12:13.000Z","size":238,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-14T12:12:00.850Z","etag":null,"topics":["blockstore","encryption","helia","ipfs"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dozyio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-16T23:36:45.000Z","updated_at":"2024-12-17T08:23:41.000Z","dependencies_parsed_at":"2024-11-23T22:46:53.814Z","dependency_job_id":null,"html_url":"https://github.com/dozyio/js-blockstore-encrypt","commit_stats":null,"previous_names":["dozyio/js-blockstore-encrypt"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dozyio%2Fjs-blockstore-encrypt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dozyio%2Fjs-blockstore-encrypt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dozyio%2Fjs-blockstore-encrypt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dozyio%2Fjs-blockstore-encrypt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dozyio","download_url":"https://codeload.github.com/dozyio/js-blockstore-encrypt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248877959,"owners_count":21176244,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockstore","encryption","helia","ipfs"],"created_at":"2024-11-06T02:38:40.504Z","updated_at":"2025-04-14T12:12:06.195Z","avatar_url":"https://github.com/dozyio.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# blockstore-enc\n\nA JS/TS transparent encrypted wrapper around any existing Blockstore implementation.\n\n## Features\n\n* Data Security: Encrypts blocks to ensure privacy and security. CIDs are stored as secure hashes.\n* Compatibility: Works with any Blockstore implementation conforming to the `interface-blockstore` specification.\n* Strong Cryptography:\n    * Uses AES-GCM for block encryption.\n    * Uses HMAC-SHA256 for CID hashing.\n    * Master key is derived from a password using PBKDF2.\n    * Derives encryption and MAC keys from a master key using HKDF.\n\n## Installation\n\n```sh\nnpm install blockstore-enc\n```\n\nOr with Yarn:\n\n```sh\nyarn add blockstore-enc\n```\n\n## Usage\n\n```js\nimport { EncBlockstore } from 'blockstore-enc';\nimport { FsBlockstore } from 'blockstore-fs';\nimport { CID } from 'multiformats/cid';\n\n(async () =\u003e {\n  try {\n    const password = 'strong-password-is-strong'; // Must be at least 16 bytes long\n    const masterSalt = new TextEncoder().encode('4d1A2eF42C9F09BF8ba6141D3dBA3521') // Must be at least 16 bytes long\n\n    const store = new EncBlockstore(new FsBlockstore('./data'));\n    await store.init(password, masterSalt);\n    await store.open();\n\n    // Use the store as you would use any Blockstore\n    const someCid = CID.parse('bafkreigh2akiscaildc6en5ynpwp45fucjk64o4uqa5fmsrzc4i4vqveae')\n    const someData = new Uint8Array([1, 2, 3, 4, 5]);\n\n    await store.put(someCid, someData);\n\n    const data = await store.get(someCid);\n    console.log('Retrieved data:', data);\n  } catch (err) {\n    console.error(err);\n  }\n})();\n```\n\n## API\n\n### Class: `EncBlockstore`\n\n#### Constructor\n\n```js\nnew EncBlockstore(blockstore: Blockstore, init?: EncBlockstoreInit)\n```\n\nCreates a new instance of EncBlockstore wrapping the provided blockstore.\n\n* blockstore: The underlying Blockstore to wrap.\n* init (optional): Initialization options.\n\n#### Methods\n\n```js\ninit(password: string, masterSalt: Uint8Array): Promise\u003cvoid\u003e\n```\n\nInitializes the encryption and MAC keys. Must be called before using the blockstore.\n* password: The password to derive the master key from. Must be at least 16 bytes long.\n* masterSalt: The master salt used for key derivation. Must be at least 16 bytes long.\n\n```js\nopen(): Promise\u003cvoid\u003e\n```\n\nOpens the underlying blockstore.\n\n```js\nclose(): Promise\u003cvoid\u003e\n```\n\nCloses the underlying blockstore.\n\n```js\nput(key: CID, val: Uint8Array): Promise\u003cCID\u003e\n```\n\nEncrypts and stores a block under the original CID.\n\n* `key`: The original CID.\n* `val`: The plaintext data to encrypt and store.\n* *Returns*: The original CID.\n\n```js\nget(key: CID): Promise\u003cUint8Array\u003e\n```\n\nRetrieves and decrypts a block by its original CID.\n\n* `key`: The original CID.\n* *Returns*: The decrypted plaintext data.\n\nDeletes a block by its original CID.\n\n* `key`: The original CID.\n\n```js\nhas(key: CID): Promise\u003cboolean\u003e\n```\n\nChecks if a block exists by its original CID.\n\n* `key`: The original CID.\n* *Returns*: A boolean indicating existence.\n\n```js\nputMany(source: AwaitIterable\u003cPair\u003e): AsyncIterable\u003cCID\u003e\n```\n\nStores multiple blocks in parallel.\n\n* `source`: An iterable of { cid, block } pairs.\n* *Returns*: An async iterable of CIDs.\n\n```js\ngetMany(source: AwaitIterable\u003cCID\u003e): AsyncIterable\u003cPair\u003e\n```\n\nRetrieves multiple blocks in parallel.\n\n* ```source```: An iterable of CIDs.\n* *Returns*: An async iterable of `{ cid, block }` pairs.\n\n```js\ndeleteMany(source: AwaitIterable\u003cCID\u003e): AsyncIterable\u003cCID\u003e\n```\n\nDeletes multiple blocks in parallel.\n\n* `source`: An iterable of CIDs.\n* *Returns*: An async iterable of deleted CIDs.\n\n### Initialization Options (`EncBlockstoreInit`)\nYou can configure the behavior of the `EncBlockstore` using the `init` parameter.\n\n* `pbkdf2Iterations` (number): The number of PBKDF2 iterations to use. Default: `210000` for SHA-512.\n* `pbkdf2hash` ('SHA-512' | 'SHA-256'): The hash algorithm to use for PBKDF2. Default: `'SHA-512'`.\n* `saltByteLength` (number): The length of the salt to use for PBKDF2. Default: `16` bytes.\n* `putManyConcurrency` (number): How many blocks to put in parallel when `.putMany` is called. Default: `50`.\n* `getManyConcurrency` (number): How many blocks to read in parallel when `.getMany` is called. Default: `50`.\n* `deleteManyConcurrency` (number): How many blocks to delete in parallel when `.deleteMany` is called. Default: `50`.\n\n## Cryptography Details\n* **Key Derivation**:\n    * Uses PBKDF2 to derive a master key from the password and master salt.\n    * Default PBKDF2 settings: 210,000 iterations and SHA-512 hash function.\n* **Key Expansion**:\n    * Uses HKDF with SHA-256 to derive separate encryption and MAC keys from the master key.\n    * The encryption key is used for per-block key derivation.\n* **Per-block Encryption**:\n    * For each block, a unique per-block salt is generated.\n    * Uses HKDF with the per-block salt to derive a per-block encryption key.\n    * The block data is encrypted using AES-GCM with a random IV.\n    * The salt and IV are stored alongside the encrypted data.\n* **CID Hashing**:\n    * The original CID is transformed using HMAC-SHA256 with the MAC key to compute a storage CID.\n    * The storage CID serves as a mapping to the original CID - it is **not** a content addressed hash of the encrypted block.\n    * The storage CID is used to store and retrieve the encrypted block.\n\n## Security Considerations\n* Password and Salt:\n    * The security of the encrypted blockstore depends critically on the secrecy of the password and the master salt.\n    * **If either is compromised, the encrypted data may be at risk.**\n    * **If either is lost, the data cannot be recovered.**\n\n## Limitations\n* No `getAll` Support:\n    * Due to the one-way mapping of CIDs, the getAll() method is not supported.\n\n* Performance Overhead:\n    * Encryption and decryption operations introduce computational overhead.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdozyio%2Fjs-blockstore-encrypt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdozyio%2Fjs-blockstore-encrypt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdozyio%2Fjs-blockstore-encrypt/lists"}