{"id":32176117,"url":"https://github.com/mysto/python-fpe","last_synced_at":"2026-02-18T21:02:55.376Z","repository":{"id":46123197,"uuid":"314666886","full_name":"mysto/python-fpe","owner":"mysto","description":"FPE - Format Preserving Encryption with FF3 in Python","archived":false,"fork":false,"pushed_at":"2026-01-26T02:10:47.000Z","size":180,"stargazers_count":102,"open_issues_count":0,"forks_count":20,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-01-26T14:44:15.629Z","etag":null,"topics":["anonymization","crypto","cryptographic","cryptography","encryption","ff3","format-preserving-encryption","fpe","nist-recommendation","nist-specification","privacy-enhancing-technologies","privacy-tools","python","tokenization"],"latest_commit_sha":null,"homepage":"https://privacylogistics.com","language":"Python","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-11-20T20:53:47.000Z","updated_at":"2026-01-26T02:10:51.000Z","dependencies_parsed_at":"2024-03-13T05:29:35.650Z","dependency_job_id":"1e3733b4-61dc-4547-b5ef-8484050ce98d","html_url":"https://github.com/mysto/python-fpe","commit_stats":{"total_commits":158,"total_committers":5,"mean_commits":31.6,"dds":"0.45569620253164556","last_synced_commit":"c4741445ff0af4d373284e173580940149ebdad9"},"previous_names":["mysto/fpe"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/mysto/python-fpe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mysto%2Fpython-fpe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mysto%2Fpython-fpe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mysto%2Fpython-fpe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mysto%2Fpython-fpe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mysto","download_url":"https://codeload.github.com/mysto/python-fpe/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mysto%2Fpython-fpe/sbom","scorecard":{"id":671404,"data":{"date":"2025-08-11","repo":{"name":"github.com/mysto/python-fpe","commit":"1dd20057e58218eaf024d1dc7c850b0ed7ec3c9f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.2,"checks":[{"name":"Maintained","score":0,"reason":"1 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":"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":"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":"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":"Code-Review","score":0,"reason":"Found 1/26 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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build-py.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":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-py.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/mysto/python-fpe/build-py.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build-py.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/mysto/python-fpe/build-py.yml/main?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/build-py.yml:21","Warn: pipCommand not pinned by hash: .github/workflows/build-py.yml:22","Warn: pipCommand not pinned by hash: .github/workflows/build-py.yml:23","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 pipCommand 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":"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":"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":"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":"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":"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":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2018-21 / GHSA-hgg3-g7gr-66r7","Warn: Project is vulnerable to: GHSA-j225-cvw7-qrx7"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 7 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:51.063Z","repository_id":46123197,"created_at":"2025-08-21T20:11:51.063Z","updated_at":"2025-08-21T20:11:51.063Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29596125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T20:59:56.587Z","status":"ssl_error","status_checked_at":"2026-02-18T20:58:41.434Z","response_time":162,"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":["anonymization","crypto","cryptographic","cryptography","encryption","ff3","format-preserving-encryption","fpe","nist-recommendation","nist-specification","privacy-enhancing-technologies","privacy-tools","python","tokenization"],"created_at":"2025-10-21T19:54:43.449Z","updated_at":"2026-02-18T21:02:55.370Z","avatar_url":"https://github.com/mysto.png","language":"Python","readme":"[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Build Status](https://github.com/mysto/python-fpe/actions/workflows/build-py.yml/badge.svg)](https://github.com/mysto/python-fpe/actions)\n[![Coverage Status](https://coveralls.io/repos/github/mysto/python-fpe/badge.svg?branch=main)](https://coveralls.io/github/mysto/python-fpe?branch=main)\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/ff3)\n[![Downloads](https://pepy.tech/badge/ff3)](https://pepy.tech/project/ff3)\n[![PyPI version](https://badge.fury.io/py/ff3.svg)](https://badge.fury.io/py/ff3)\n[![Percentage of issues still open](http://isitmaintained.com/badge/open/mysto/python-fpe.svg)](http://isitmaintained.com/project/mysto/python-fpe \"Percentage of issues still open\")\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**⚠️ WARNING**\n \n **NOTE:** NIST's February 2025 Draft 2 has entirely withdrawn FF3 and FF3-1 from the NIST standard due to published vulnerabilities. \n\nThis software is provided for educational and experimental use and comes with no warranty of any kind.\nIt is intended for developers and researchers familiar with cryptographic standards.\n\n# FF3 - Format Preserving Encryption in Python\n\nAn implementation of the draft NIST FF3 and FF3-1 Format Preserving Encryption (FPE) algorithms in Python. FF1 implementations are outside the scope of this open source project. \n\nThis package implements the FF3 and FF3-1 algorithms as specified in NIST Special Publication 800-38G _Methods for Format-Preserving Encryption_ (now withdrawn), and includes the revisions on February 28th, 2019 with a draft update for FF3-1 (now withdrawn).\n\n-  **[NIST SP 800-38G (FF1 \u0026 FF3)](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf)** — *Withdrawn due to published vulnerabilities in FF3*\n-  **[NIST SP 800-38G Revision 1 (FF3-1)](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38Gr1-draft.pdf)** — *Withdrawn due to published vulnerabilities in FF3-1*\n-  **[NIST SP 800-38G Revision 1 (2nd Public Draft)](https://csrc.nist.gov/pubs/sp/800/38/g/r1/2pd)** — *Current draft; FF1 only (does not define FF3/FF3-1)*\n\nChanges to minimum domain size and revised tweak length have been implemented in this package with\nsupport 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.\n\n## Installation\n\n`pip3 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_.\nThe following radix values are typical:\n\n* radix 10: digits 0..9\n* radix 36: alphanumeric 0..9, a-z\n* radix 62: alphanumeric 0..9, a-z, A-Z\n\nSpecial characters and international character sets, such as those found in UTF-8, are supported by specifying a custom alphabet.\nAlso, all elements in a plaintext string share the same radix. Thus, an identification number that consists of an initial 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\n* radix 10: 56\n* radix 36: 36\n* radix 62: 32\n\nTo work around string length, it's 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 original FF3.\n\nAs with any cryptographic package, managing and protecting the key(s) is crucial. The tweak is generally not kept secret.\nThis implementation does not intentionally retain key material beyond cipher initialization.\n\n## Code Example\n\nThe example code below uses the default domain [0-9] and can help you get started.\n\n```python3\n\nfrom ff3 import FF3Cipher\n\nkey = \"2DE79D232DF5585D68CE47882AE256D6\"\ntweak = \"CBD09280979564\"\nc = FF3Cipher(key, tweak)\n\nplaintext = \"3992520240\"\nciphertext = c.encrypt(plaintext)\ndecrypted = c.decrypt(ciphertext)\n\nprint(f\"{plaintext} -\u003e {ciphertext} -\u003e {decrypted}\")\n\n# format encrypted value\nccn = f\"{ciphertext[:4]} {ciphertext[4:8]} {ciphertext[8:12]} {ciphertext[12:]}\"\nprint(f\"Encrypted CCN value with formatting: {ccn}\")\n```\n## CLI Example\n\nThis package installs the command line scripts ff3_encrypt and ff3_decrypt which can be run\nfrom the Linux or Windows command line.\n\n```bash\n% ff3_encrypt 2DE79D232DF5585D68CE47882AE256D6 CBD09280979564 3992520240\n8901801106\n% ff3_decrypt 2DE79D232DF5585D68CE47882AE256D6 CBD09280979564 8901801106\n3992520240\n\n```\n\n\n## Custom alphabets\n\nCustom alphabets up to 256 characters are supported. To use an alphabet consisting of the uppercase letters A-F (radix=6), we can continue\nfrom the above code example with:\n\n```python3\nc6 = FF3Cipher.withCustomAlphabet(key, tweak, \"ABCDEF\")\nplaintext = \"BADDCAFE\"\nciphertext = c6.encrypt(plaintext)\ndecrypted = c6.decrypt(ciphertext)\n\nprint(f\"{plaintext} -\u003e {ciphertext} -\u003e {decrypted}\")\n```\n## Requires\n\nThis project was built and tested with Python 3.9 and later versions.  The only dependency is [PyCryptodome](https://pycryptodome.readthedocs.io).\n\n## Testing\n\nOfficial [test vectors](https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/ff3samples.pdf) for FF3 provided by NIST,\nare used for testing in this package. Also included are draft ACVP test vectors with 56-bit tweaks.\n\nTo run unit tests on this implementation, including all test vectors from the NIST specification, run the command:\n\n```bash\npython3 -m ff3.ff3_test\n```\n\n## Performance Benchmarks\n\nThe Mysto FF3 was benchmarked on a MacBook Air (1.1 GHz Quad-Core Intel Core i5)\nperforming 70,000 tokenization per second with random 8 character data input. Performance \nresults are indicative only and depend on hardware, workload, and configuration\n\nTo run the performance tests:\n\n```bash\npython3 -m ff3.ff3_perf\n```\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.  This FF3 Feistel encryption consisting of eight rounds of processing\nthe plaintext. Each round applies an internal function or _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 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## Reporting Issues and Contributing\n\nBug reports, feature requests, and pull requests are welcome.  Please use the GitHub Issues page to report problems or ask questions:\nhttps://github.com/mysto/python-fpe/issues.\n\nBy contributing, you agree that your contributions are provided under the Apache 2.0 license. All documentation and issue discussions are conducted in English.\n\n## Implementation Notes\n\nThis implementation was originally based upon the [Capital One Go implementation](https://github.com/capitalone/fpe).  It follows the algorithm as outlined in the NIST specification as closely as possible, including naming.\n\nFPE can be used for data tokenization of sensitive data which is cryptographically reversible. This implementation does not provide any guarantees regarding PCI DSS or other validation.\n\nWhile all NIST and ACVP test vectors pass, this package has not undergone independent security review or formal cryptographic validation.\n\nThe cryptographic library used is [PyCryptodome](https://pypi.org/project/pycryptodome/) 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. This does not imply that ECB mode is safe for general-purpose encryption; it is used here solely because it is required by the FF3 specification\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.\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## Developer Installation\n\nUse `python -m build` to build the project.\n\nTo install the development version:\n\n```bash\ngit clone https://github.com/mysto/python-fpe.git\ncd python-fpe\npip3 install --editable .\n```\n\nBefore contributing any pull requests, you will need to first fork this repository. \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","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmysto%2Fpython-fpe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmysto%2Fpython-fpe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmysto%2Fpython-fpe/lists"}