{"id":25766665,"url":"https://github.com/zhongfuze/crypto-dare","last_synced_at":"2026-05-12T21:02:25.359Z","repository":{"id":65166201,"uuid":"582563515","full_name":"ZhongFuze/crypto-dare","owner":"ZhongFuze","description":"TypeScript implementation of the Data At Rest Encryption (DARE) format. DARE combines a modern AE scheme with a simple reordering protection mechanism to build a tamper-resistant encryption scheme.","archived":false,"fork":false,"pushed_at":"2023-01-06T09:05:01.000Z","size":1192,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-01T10:39:27.347Z","etag":null,"topics":["aead","aes","aes-gcm","bigfile","crypto","dare","decryption","encryption","nodejs"],"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/ZhongFuze.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}},"created_at":"2022-12-27T08:10:03.000Z","updated_at":"2023-01-13T07:13:24.000Z","dependencies_parsed_at":"2023-01-12T14:45:10.062Z","dependency_job_id":null,"html_url":"https://github.com/ZhongFuze/crypto-dare","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ZhongFuze/crypto-dare","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZhongFuze%2Fcrypto-dare","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZhongFuze%2Fcrypto-dare/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZhongFuze%2Fcrypto-dare/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZhongFuze%2Fcrypto-dare/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ZhongFuze","download_url":"https://codeload.github.com/ZhongFuze/crypto-dare/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZhongFuze%2Fcrypto-dare/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32956830,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-12T09:19:52.626Z","status":"ssl_error","status_checked_at":"2026-05-12T09:17:33.438Z","response_time":102,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["aead","aes","aes-gcm","bigfile","crypto","dare","decryption","encryption","nodejs"],"created_at":"2025-02-26T23:16:57.969Z","updated_at":"2026-05-12T21:02:25.289Z","avatar_url":"https://github.com/ZhongFuze.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# crypto-dare\n\n```typescript\nimport DARE from 'crypto-dare';\n\nconst origin = '/unix/input.txt'; // must be absolute\nconst encrypt = '/unix/encrypt.txt'; // must be absolute\nconst decrypt = '/unix/decrypt.txt'; // must be absolute\nconst password = '012345678901234567890';\nconst dare = new DARE(password);\n\nconst m = await Promise.resolve(dare.Encrypt(origin, encrypt));\nconsole.log('Number of encryption package:', m);\n\nconst m = await Promise.resolve(dare.Encrypt(encrypt, decrypt));\nconsole.log('Number of decryption package:', m);\n```\n\n```typescript\nimport DARE from 'crypto-dare';\n\nconst origin = Buffer.from('Hello world');\nconst password = '012345678901234567890';\nconst dare = new DARE(password);\nconst encrypt = await Promise.resolve(dare.Encrypt(origin));\nconst decrypt = await Promise.resolve(dare.Decrypt(encrypt));\nconsole.log('Origin content is:', dst.toString());\nconsole.log('Encrypt content is:', encrypt.toString());\nconsole.log('Decrypt content is:', dst.toString());\n```\n\n## Introduce\n\nStoring data securely is a common problem -- especially on untrusted remote storage. One solution to this problem is cryptography. Encrypt data before storing it to ensure data confidentiality. Unfortunately, encrypting data is not enough to prevent more sophisticated attacks. Anyone with access to stored data can attempt to manipulate it -- even if it's encrypted.\n\nTo prevent such attacks, data must be encrypted in a tamper-resistant manner. This means an attacker should not be able to:\n\n- Read stored data - this is achieved through modern encryption algorithms.\n- Modify data by changing parts of encrypted data.\n- Rearrange or reorder partially encrypted data.\n\nAuthenticated encryption schemes (AE) - such as AES-GCM - encrypt and authenticate data.\nDetect any modification to encrypted data (ciphertext) while decrypting the data.\nBut even AE schemes alone are not enough to prevent various data manipulations.\n\nAll modern AE schemes produce an authentication tag, which is verified after the ciphertext is decrypted. If a large amount of data is decrypted, it is not always possible to buffer all the decrypted data until the authentication tag is verified. Returning unauthenticated data has the same problems as unauthenticated encrypted data.\n\nBreaking the data into small **chunks** solves the problem of delayed authentication checks, but introduces a new problem. Blocks can be reordered - for example swapping blocks 1 and 2 - because each block is encrypted individually. Therefore, the order of the blocks must somehow be encoded into the blocks themselves to be able to detect rearranging any number of blocks.\n\nThis project specifies a format for encrypting/decrypting arbitrary data streams and provides recommendations on how to use and implement Data at Rest Encryption (DARE).\nAdditionally, the project provides a reference implementation in **TypeScript**.\n\n## Application\n\nDARE was designed with simplicity and efficiency in mind.\nIt combines a modern AE scheme with a very simple reordering protection mechanism to build a tamper-resistant encryption scheme.\nDARE can be used to encrypt files, backups and even large object storage systems.\n\nIts main properties are:\n\n- Rely on the security and performance of modern AEAD ciphers\n- Low overhead - encryption increases data size by about 0.05%\n- Support for long data streams - up to 256 TB under the same key\n- Random access - arbitrary sequences/ranges can be decrypted independently\n\nInstall: `npm install crypto-dare`\n\n## Data At Rest Encryption (DARE)\n\nDARE specifies how to split an arbitrary data stream into small chunks (packages)\nand concatenate them into a tamper-proof chain. Tamper-proof means that an attacker\nis not able to:\n\n- decrypt one or more packages.\n- modify the content of one or more packages.\n- reorder/rearrange one or more packages.\n\nAn attacker is defined as somebody who has full access to the encrypted data\nbut not to the encryption key. An attacker can also act as storage provider.\n\n### 1. Keys\n\nAES-256_GCM equire a 32 byte key. The key **must** be unique for one encrypted data stream.\nReusing a key **compromises** some security properties provided by DARE.\n\n#### 1.2 Key Derivation\n\nDARE needs a unique encryption key per data stream. The best approach to ensure that the keys\nare unique is to derive every encryption key from a master key.\nTherefore a key derivation function (KDF) - e.g. HKDF can be used. The master key itself may be derived from a password using functions like **scrypt**. Deriving those keys is the responsibility of the\nusers of DARE.\n\n#### 1.2 Generating random values\n\nDARE does not require random values which are indistinguishable from a truly random bit sequence.\nHowever, a random value **must** never be repeated. Therefore it is **recommended** to use a\ncryptographically secure pseudorandom number generator (CSPRNG) to generate random values.\n\n### 2. Package Format\n\nDARE splits an arbitrary data stream into a sequence of packages. Each package is\nencrypted separately. A package consists of a header, a payload and an authentication\ntag.\n\n| Header   | Payload        | Tag      |\n| -------- | -------------- | -------- |\n| 16 bytes | 1 byte - 64 KB | 16 bytes |\n\nThe header contains information about the package. It consists of:\n\n| Version | Cipher suite | Payload size     | Sequence number  | nonce   |\n| ------- | ------------ | ---------------- | ---------------- | ------- |\n| 1 byte  | 1 byte       | 2 bytes / uint16 | 4 bytes / uint32 | 8 bytes |\n\nThe first byte specifies the version of the format and is equal to 0x10 for DARE\nversion 1.0. The second byte specifies the cipher used to encrypt the package.\n\n### 3. Encryption\n\nThe nonce **should** be generated randomly once\nat the beginning of the encryption process and repeated in every header.\n\nThe sequence number is the sequence number of the previous package plus 1. The sequence number\n**must** be a monotonically increasing number within one sequence of packages. The sequence number\nof the first package is **always** 0.\n\nThe payload field is the length of the plaintext in bytes minus 1. The encryption process is\ndefined as following:\n\n```\nheader[0]       = 0x10\nheader[1]       = {AES-256_GCM, CHACHA20_POLY1305}\nheader[2:4]     = little_endian( len(plaintext) - 1 )\nheader[4:8]     = little_endian( sequence_number )\nheader[8:16]    = nonce\n\npayload || tag  = ENC(key, header[4:16], plaintext, header[0:4])\n\nsequence_number = sequence_number + 1\n```\n\n### 4. Decryption\n\n1. Verify that the header\n2. Verify that the sequence number of the packages matches the expected sequence number.\n3. Verify that the nonce matches. Compare nonce **must** happen in constant time.\n4. Verify that the authentication tag at the end of the package is equal to the authentication tag\n   computed while decrypting the package.\n\nThe decryption is defined as following:\n\n```\nheader[0]                          != 0x10                            =\u003e err_unsupported_version\nheader[1]                          != {AES-256_GCM,CHACHA20_POLY1305} =\u003e err_unsupported_cipher\nlittle_endian_uint32(header[4:8])  != expected_sequence_number        =\u003e err_package_out_of_order\n\npayload_size      := little_endian_uint32(header[2:4]) + 1\nplaintext || tag  := DEC(key, header[4:16], ciphertext, header[0:4])\n\nCTC(ciphertext[len(plaintext) : len(plaintext) + 16], tag) != 1       =\u003e err_tag_mismatch\n\nexpected_sequence_number = expected_sequence_number + 1\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhongfuze%2Fcrypto-dare","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzhongfuze%2Fcrypto-dare","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhongfuze%2Fcrypto-dare/lists"}