{"id":37442689,"url":"https://github.com/mysto/node-fpe","last_synced_at":"2026-01-16T06:46:12.464Z","repository":{"id":49063020,"uuid":"350439875","full_name":"mysto/node-fpe","owner":"mysto","description":"FPE - Format Preserving Encryption with FF3 in Node-js","archived":false,"fork":false,"pushed_at":"2025-02-20T04:30:32.000Z","size":70,"stargazers_count":33,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-12T04:58:03.177Z","etag":null,"topics":["anonymization","crypto","cryptography","encryption","ff3","format-preserving-encryption","fpe","nist-recommendation","nist-specification","node","nodejs","privacy-tools","tokenization"],"latest_commit_sha":null,"homepage":"https://privacylogistics.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mysto.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":"2021-03-22T17:58:26.000Z","updated_at":"2025-07-21T06:59:47.000Z","dependencies_parsed_at":"2024-03-13T21:47:07.881Z","dependency_job_id":null,"html_url":"https://github.com/mysto/node-fpe","commit_stats":{"total_commits":48,"total_committers":2,"mean_commits":24.0,"dds":"0.47916666666666663","last_synced_commit":"313e9bb6726eac6099b5525a7ade9e6aeb4397e5"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/mysto/node-fpe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mysto%2Fnode-fpe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mysto%2Fnode-fpe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mysto%2Fnode-fpe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mysto%2Fnode-fpe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mysto","download_url":"https://codeload.github.com/mysto/node-fpe/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mysto%2Fnode-fpe/sbom","scorecard":{"id":671403,"data":{"date":"2025-08-11","repo":{"name":"github.com/mysto/node-fpe","commit":"951c3d9053a36317f8fc894cc6fa6f20e90e382d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.6,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":2,"reason":"dependency not pinned by hash detected -- score normalized to 2","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/mysto/node-fpe/build.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/mysto/node-fpe/build.yml/main?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/build.yml:18","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   2 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 1 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T20:11:49.200Z","repository_id":49063020,"created_at":"2025-08-21T20:11:49.200Z","updated_at":"2025-08-21T20:11:49.200Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28477950,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: 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":["anonymization","crypto","cryptography","encryption","ff3","format-preserving-encryption","fpe","nist-recommendation","nist-specification","node","nodejs","privacy-tools","tokenization"],"created_at":"2026-01-16T06:46:12.092Z","updated_at":"2026-01-16T06:46:12.441Z","avatar_url":"https://github.com/mysto.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://github.com/mysto/node-fpe/actions/workflows/build.yml/badge.svg)](https://github.com/mysto/node-fpe/actions)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![npm module downloads](https://badgen.net/npm/dt/ff3)](https://www.npmjs.org/package/ff3)\n[![npm version](https://badge.fury.io/js/ff3.svg)](https://badge.fury.io/js/ff3)\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://privacylogistics.com/\"\u003e\n    \u003cimg\n      alt=\"Mysto\"\n      src=\"https://privacylogistics.com/Mysto-logo.jpg\"\n    /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n# ff3 - Format Preserving Encryption in Node.js\n\nAn implementation of the NIST approved FF3 and FF3-1 Format Preserving Encryption (FPE) algorithm in Node.js.\n\nThis package implements the FF3 algorithm for Format Preserving Encryption as described in the March 2016 NIST publication 800-38G Methods for Format-Preserving Encryption, and revised on February 28th, 2019 with a draft update for FF3-1.\n* [NIST Recommendation SP 800-38G (FF3)](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf)\n* [NIST Recommendation SP 800-38G Revision 1 (FF3-1)](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38Gr1-draft.pdf)\n* [NIST SP 800-38G Rev. 1(2nd Public Draft)(https://csrc.nist.gov/pubs/sp/800/38/g/r1/2pd)]\n\n**NOTE:** NIST's Feburary 2025 Draft 2 has removed FF3 from the NIST standard. Contact me about a licensed version of FF1 in NodeJS.\n\nChanges to minimum domain size and revised tweak length have been implemented in this package with\nsuport for both 64-bit and 56-bit tweaks. NIST has only published official test vectors for 64-bit tweaks,\nbut draft ACVP test vectors have been used for testing FF3-1. It is expected the final\nNIST standard will provide updated test vectors with 56-bit tweak lengths.\n\n## Installation\n\n`npm install ff3`\n\n## Usage\n\nFF3 is a Feistel cipher, and Feistel ciphers are initialized with a radix representing an alphabet. The number of \ncharacters in an alphabet is called the _radix_.\nPractical radix limits of 36 in Node.js means the following radix values are typical:\n* radix 10: digits 0..9\n* radix 36: alphanumeric 0..9, a-z\n\nSpecial characters and international character sets, such as those found in UTF-8, would require a larger radix, and are not supported. \nAlso, all elements in a plaintext string share the same radix. Thus, an identification number that consists of a letter followed \nby 6 digits (e.g. A123456) cannot be correctly encrypted by FPE while preserving this convention.\n\nInput plaintext has maximum length restrictions based upon the chosen radix (2 * floor(96/log2(radix))):\n* radix 10: 56\n* radix 36: 36\n\nTo work around string length, its possible to encode longer text in chunks.\n\nThe key length must be 128, 192, or 256 bits in length. The tweak is 7 bytes (FF3-1) or 8 bytes for the origingal FF3.\n\nAs with any cryptographic package, managing and protecting the key(s) is crucial. The tweak is generally not kept secret.\nThis package does not protect the key in memory.\n\n## Code Example\n\nThe example code below can help you get started.\n\nUsing default domain [0-9]\n\n```js\nconst FF3Cipher = require('ff3/lib/FF3Cipher');\n\nconst key = \"EF4359D8D580AA4F7F036D6F04FC6A94\"\nconst tweak = \"D8E7920AFA330A73\"\nconst c = new FF3Cipher(key, tweak)\n\nconst plaintext = \"4000001234567899\"\nlet ciphertext = c.encrypt(plaintext)\nlet decrypted = c.decrypt(ciphertext)\n\nconsole.log(\"%s -\u003e %s -\u003e %s\", plaintext, ciphertext, decrypted)\n\n```\n## Requires\n\nThis project was built and tested with Node.js 12 and later versions.  It requires the 'crypto' library.\n\n## Testing\n\nThere are official [test vectors](https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/ff3samples.pdf) for FF3 provided by NIST, which are used for testing in this package.\n\nTo run unit tests on this implementation, including all test vectors from the NIST specification, run the command:\n\n  1. node test/FF3CipherTest.js\n\n## The FF3 Algorithm\n\nThe FF3 algorithm is a tweakable block cipher based on an eight round Feistel cipher. A block cipher operates on fixed-length groups of bits, called blocks. A Feistel Cipher is not a specific cipher,\nbut a design model.  The encryption process consisting of eight rounds of \nprocessing of the plaintext, each round applies an internal round function followed by transformation steps.\n\nThe FF3 round function uses AES encryption in ECB mode, which is performed each iteration \non alternating halves of the text being encrypted. The *key* value in FF3 is used only to initialize the AES cipher. Thereafter\nthe *tweak* is used together with the intermediate encrypted text as input to the round function.\n\n## Other FPE Algorithms\n\nOnly FF1 and FF3 have been approved by NIST for format preserving encryption. There are patent claims on FF1 which allegedly include open source implementations. Given the issues raised in [\"The Curse of Small Domains: New Attacks on Format-Preserving Encryption\"](https://eprint.iacr.org/2018/556.pdf) by Hoang, Tessaro and Trieu in 2018, it is prudent to be very cautious about using any FPE that isn't a standard and hasn't stood up to public scrutiny.\n\n## Implementation Notes\n\nThis implementation follows the algorithm as outlined in the NIST specification as closely as possible, including naming.\n\nFPE can be used for sensitive data tokenization, especially with PCI and cryptographically reversible tokens. This implementation does not provide any guarantees regarding PCI DSS or other validation.\n\nWhile all test vectors pass, this package has not otherwise been extensively tested.\n\nThe standard built-in [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) package supports radices/bases up to 36. Therefore, this release supports a max base of 36, which can contain numeric digits 0-9 and lowercase alphabetic characters a-z.\n\nThe cryptographic library used is [crypto](https://nodejs.org/api/crypto.html) for AES encryption. FF3 uses a single-block with an IV of 0, which is effectively ECB mode. AES ECB is the only block cipher function which matches the requirement of the FF3 spec.\n\nThe domain size was revised in FF3-1 to radix\u003csup\u003eminLen\u003c/sup\u003e \u003e= 1,000,000 and is represented by the constant `DOMAIN_MIN` in `ff3.py`. FF3-1 is in draft status and updated 56-bit test vectors are not yet available.\n\nThe tweak is required in the initial `FF3Cipher` constructor, but can optionally be overridden in each `encrypt` and `decrypt` call. This is similar to passing an IV or nonce when creating an encrypter object.\n\n## Author\n\nBrad Schoening\n\n## License\n\nThis project is licensed under the terms of the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmysto%2Fnode-fpe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmysto%2Fnode-fpe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmysto%2Fnode-fpe/lists"}