tink-fpe


Nametink-fpe JSON
Version 0.4.0 PyPI version JSON
download
home_pagehttps://github.com/statisticsnorway/tink-fpe-project
SummaryFormat-Preserving Encryption support for Google Tink
upload_time2023-08-31 09:25:58
maintainer
docs_urlNone
authorStatistics Norway
requires_python>=3.8,<4.0
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Tink FPE Python

[![PyPI](https://img.shields.io/pypi/v/tink-fpe.svg)][pypi_]
[![Status](https://img.shields.io/pypi/status/tink-fpe.svg)][status]
[![Python Version](https://img.shields.io/pypi/pyversions/tink-fpe)][python version]
[![License](https://img.shields.io/pypi/l/tink-fpe)][license]

[![Tests](https://github.com/statisticsnorway/tink-fpe-python/workflows/Tests/badge.svg)][tests]
[![Codecov](https://codecov.io/gh/statisticsnorway/tink-fpe-python/branch/main/graph/badge.svg)][codecov]

[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)][pre-commit]
[![Black](https://img.shields.io/badge/code%20style-black-000000.svg)][black]

[pypi_]: https://pypi.org/project/tink-fpe/
[status]: https://pypi.org/project/tink-fpe-python/
[python version]: https://pypi.org/project/tink-fpe-python
[tests]: https://github.com/statisticsnorway/tink-fpe-python/actions?workflow=Tests
[codecov]: https://app.codecov.io/gh/statisticsnorway/tink-fpe-python
[pre-commit]: https://github.com/pre-commit/pre-commit
[black]: https://github.com/psf/black

Format-Preserving Encryption (FPE) is a type of encryption that encrypts data in a way that preserves the format of the original plaintext. This means that after encryption, the encrypted data retains the same format as the original plaintext, such as a specific length or character set.

## Features

- _Tink FPE_ implements a [Primitive](https://developers.google.com/tink/glossary) that extends the Google Tink framework with support for Format-Preserving Encryption (FPE).
- The following [NIST compliant](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38Gr1-draft.pdf) algorithms are currently supported: `FF3-1`.
- The implementation of the underlying algorithm is built on top of the excellent [Mysto FPE](https://github.com/mysto/python-fpe) library.
- Tink FPE is currently available for Python and Java.
- Regarding sensitivity for alphabet, FPE is designed to work with a specific alphabet, which is typically defined in the encryption algorithm. If the plaintext data contains characters that are not part of the defined alphabet, Tink FPE supports different _strategies_ for dealing with the data or substitute the characters with ones that are part of the alphabet.

## Requirements

- Google Tink for Python - the bleeding edge version (until [this issue](https://github.com/google/tink/issues/623) is resolved)

## Installation

You can install _Tink FPE_ via [pip] from [PyPI]:

```console
$ pip install tink-fpe
```

## Usage

```python
import tink
import tink_fpe

# Register Tink FPE with the Tink runtime
tink_fpe.register()

# Specify the key template to use. In this example we want a 256 bits FF3-1 key that can handle
# alphanumeric characters (ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789)
key_template = tink_fpe.fpe_key_templates.FPE_FF31_256_ALPHANUMERIC

# Create a keyset
keyset_handle = tink.new_keyset_handle(key_template)

# Get the FPE primitive
fpe = keyset_handle.primitive(tink_fpe.Fpe)

# Encrypt
ciphertext = fpe.encrypt(b'Secret123')
print(ciphertext.decode('utf-8')) #-> sN3gt6q0V

# Decrypt
decrypted = fpe.decrypt(ciphertext)
print(decrypted.decode('utf-8')) #-> Secret123
```

### Handling non-alphabet characters

A characteristic of Format-Preserving Encryption is that plaintext can only be composed of letters or symbols
from a predefined set of characters called the "alphabet". Tink FPE supports different ways of coping with
texts that contain non-alphabet characters. The approach to use can be expressed via the `UnknownCharacterStrategy` enum.

The following _stragies_ are supported:

- `FAIL` - Raise an error and bail out if encountering a non-alphabet character. **(this is the default)**
- `SKIP` - Ignore non-alphabet characters, leaving them unencrypted (nested into the ciphertext).
- `DELETE` - Remove all characters that are not part of the alphabet prior to processing. \_Warning: Using this strategy implies that the length of the plaintext and ciphertext may differ.
- `REDACT` - Replace non-alphabet characters with an alphabet-compliant character prior to processing. _Warning: Using this strategy means that decryption may not result in the exact same plaintext being restored._

```python
from tink_fpe import FpeParams, UnknownCharacterStrategy

# The following will raise an Error
ciphertext = fpe.encrypt(b'Ken sent me...', FpeParams(strategy=UnknownCharacterStrategy.FAIL))

# Skipping non-supported characters might reveal too much of the plaintext, but it is currently the only
# approach that will handle any plaintext without either failing or irreversibly transforming the plaintext.
params = FpeParams(strategy=UnknownCharacterStrategy.SKIP)
fpe.encrypt(b'Ken sent me...', params) #-> UEj l1Ns sj...
fpe.decrypt(ciphertext, params) #-> Ken sent me...

# Notice that using the DELETE strategy implies that the length of the plaintext and ciphertext may differ.
# Furthermore, it might be impossible to go back to the original plaintext.
params = FpeParams(strategy=UnknownCharacterStrategy.DELETE)
ciphertext = fpe.encrypt(b'Ken sent me...', params) #-> EsQPgkE9Y
decrypted = fpe.decrypt(ciphertext, params) #-> Kensentme

# Notice that using the REDACT strategy it might be impossible to go back to the original plaintext.
# If not specified, the redaction character will be deduced automatically from the alphabet.
# For alphanumeric alphabets the 'X' character is used.
params = FpeParams(strategy=UnknownCharacterStrategy.REDACT)
ciphertext = fpe.encrypt(b'Ken sent me...', params) #-> MMY2HXvLwzIDoY
decrypted = fpe.decrypt(ciphertext, params) #-> KenXsentXmeXXX

# It is also possible to specify the redaction character explicitly, like so:
params = FpeParams(strategy=UnknownCharacterStrategy.REDACT, redaction_char='Q')
ciphertext = fpe.encrypt(b'Ken sent me...', params) #-> 9fVDzAODt2vvdz
decrypted = fpe.decrypt(ciphertext, params) #-> KenQsentQmeQQQ
```

### Loading predefined key material

It is easy to initialize key material from a predefined JSON. The following uses a cleartext keyset,
but it will be similar for a wrapped/encrypted key as well.

```python
import json
from tink import JsonKeysetReader
from tink import cleartext_keyset_handle
import tink_fpe

tink_fpe.register()

keyset_json = json.dumps({
    "primaryKeyId": 1382079328,
    "key": [
        {
            "keyData": {
                "typeUrl": "type.googleapis.com/ssb.crypto.tink.FpeFfxKey",
                "value": "EhD4978shQNRpBNaBjbF4KO4GkIQAho+QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
                "keyMaterialType": "SYMMETRIC"
            },
            "status": "ENABLED",
            "keyId": 1382079328,
            "outputPrefixType": "RAW"
        }
    ]
})

keyset_handle = cleartext_keyset_handle.read(JsonKeysetReader(keyset_json))
fpe = keyset_handle.primitive(tink_fpe.Fpe)
```

### Using key material protected by Google Cloud KMS

```python
import json

from tink import JsonKeysetReader
from tink import read_keyset_handle
from tink.integration import gcpkms

import tink_fpe


# Define uri to key encryption key and path to GCP credentials
gcp_credentials = "path/to/sa-key.json"

# Register Tink FPE with the Tink runtime
tink_fpe.register()

# Get hold of a wrapped data encryption key (WDEK)
keyset_json = {
    "kekUri": "gcp-kms://projects/<project-id>/locations/<region>/keyRings/my-keyring/cryptoKeys/my-kek",
    "encryptedKeyset": "CiQAp91NBsClBYjw4AS9sOdB65peMwlzY4AiOzyMe+b+dFjSBuIS2QEAZ30rtRcDkuvtUgeENQCt29Vsalf+FtaNZc8wpOXKb3sD2c8hTXKaf34iq2QRMaQUBXxG+YSJPV4PvJZMGydZpjowM9K2eAJFZs5JaVxb3BMfUt0miNaORZmczqZhKlXXHbMoQ71GLwfSnf4jJnIRJK4s38ThnxS2ebm4b5T0qno6PWg84TtUw9eIIieqlUFhIqBjCcMugGTsE+xfWIOct22RDEUI3cAboCew5ppjOREAxzbaH8LaUBct5eLN8wtakY3Vv8KxBoT3Hq6fnNSSGOKmkqMVrK0p",
    "keysetInfo":
        {
            "primaryKeyId": 593699223,
            "keyInfo":
                [
                    {
                        "typeUrl": "type.googleapis.com/ssb.crypto.tink.FpeFfxKey",
                        "status": "ENABLED",
                        "keyId": 593699223,
                        "outputPrefixType": "RAW"
                    }
                ]
        }
}

# Extract the kek uri from the keyset json
kek_uri = keyset_json.pop('kekUri')

# Unwrap key using Google Cloud KMS
kms_client = gcpkms.GcpKmsClient(kek_uri, gcp_credentials)
kms_aead = kms_client.get_aead(kek_uri)
keyset_handle = read_keyset_handle(keyset_reader=JsonKeysetReader(json.dumps(keyset_json)),
                                   master_key_aead=kms_aead)

# Get the FPE primitive
fpe = keyset_handle.primitive(tink_fpe.Fpe)
```

### Dockerfile

As of this writing (27.03.2023), Tink does not yet provide Python wheels for versions `>1.6.x`.
Thus, in order to use Tink FPE, we need to build Tink, which involves using bazel and and
compiling protobuf sources. The following shows a Dockerfile that demonstrates how this can
be done. Notice that this is for the `x86` architecture. If you are on another
architecture (e.g. `arm`), you need to substitute the bazel and protobuf references to match
your system architecture.

```dockerfile
FROM python:3.10-bullseye

RUN apt-get update && apt-get upgrade -y

# Install curl and git
RUN apt-get install -y curl git

# Install bazel
RUN curl -L https://github.com/bazelbuild/bazelisk/releases/download/v1.16.0/bazelisk-linux-amd64 > /usr/local/bin/bazelisk && chmod +x /usr/local/bin/bazelisk

# Install latest protobuf compiler (note: protobuf-compiler from apt is an older non-compliant version)
WORKDIR /opt/protobuf
RUN curl -L https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_64.zip > protoc.zip
RUN unzip protoc.zip && chmod +x ./bin/protoc
RUN ln -s /opt/protobuf/bin/protoc /usr/local/bin/protoc

# Update pip
RUN pip install --upgrade pip

# ...
WORKDIR /app
```

## Known issues

// TODO: Describe issue about chunking that results in up to last 3 characters not being encrypted.
// TODO: Describe issue with minimum length depending on the alphabet radix (e.g. 4 characters for alphanumeric and 6 for digits)

## Contributing

Contributions are very welcome.
To learn more, see the [Contributor Guide].

## License

Distributed under the terms of the [MIT license][license],
_Tink FPE Python_ is free and open source software.

## Issues

If you encounter any problems,
please [file an issue] along with a detailed description.

## Credits

This project was generated from [@cjolowicz]'s [Hypermodern Python Cookiecutter] template.

[@cjolowicz]: https://github.com/cjolowicz
[pypi]: https://pypi.org/
[hypermodern python cookiecutter]: https://github.com/cjolowicz/cookiecutter-hypermodern-python
[file an issue]: https://github.com/statisticsnorway/tink-fpe/issues
[pip]: https://pip.pypa.io/

<!-- github-only -->

[license]: https://github.com/statisticsnorway/tink-fpe-python/blob/main/LICENSE
[contributor guide]: https://github.com/statisticsnorway/tink-fpe-python/blob/main/CONTRIBUTING.md


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/statisticsnorway/tink-fpe-project",
    "name": "tink-fpe",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "",
    "author": "Statistics Norway",
    "author_email": "stat-dev@ssb.no",
    "download_url": "https://files.pythonhosted.org/packages/6d/f1/8d5b1669910c3ce9e888d0eaa42e1d87a9447ff8b5025903c529a529278c/tink_fpe-0.4.0.tar.gz",
    "platform": null,
    "description": "# Tink FPE Python\n\n[![PyPI](https://img.shields.io/pypi/v/tink-fpe.svg)][pypi_]\n[![Status](https://img.shields.io/pypi/status/tink-fpe.svg)][status]\n[![Python Version](https://img.shields.io/pypi/pyversions/tink-fpe)][python version]\n[![License](https://img.shields.io/pypi/l/tink-fpe)][license]\n\n[![Tests](https://github.com/statisticsnorway/tink-fpe-python/workflows/Tests/badge.svg)][tests]\n[![Codecov](https://codecov.io/gh/statisticsnorway/tink-fpe-python/branch/main/graph/badge.svg)][codecov]\n\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)][pre-commit]\n[![Black](https://img.shields.io/badge/code%20style-black-000000.svg)][black]\n\n[pypi_]: https://pypi.org/project/tink-fpe/\n[status]: https://pypi.org/project/tink-fpe-python/\n[python version]: https://pypi.org/project/tink-fpe-python\n[tests]: https://github.com/statisticsnorway/tink-fpe-python/actions?workflow=Tests\n[codecov]: https://app.codecov.io/gh/statisticsnorway/tink-fpe-python\n[pre-commit]: https://github.com/pre-commit/pre-commit\n[black]: https://github.com/psf/black\n\nFormat-Preserving Encryption (FPE) is a type of encryption that encrypts data in a way that preserves the format of the original plaintext. This means that after encryption, the encrypted data retains the same format as the original plaintext, such as a specific length or character set.\n\n## Features\n\n- _Tink FPE_ implements a [Primitive](https://developers.google.com/tink/glossary) that extends the Google Tink framework with support for Format-Preserving Encryption (FPE).\n- The following [NIST compliant](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38Gr1-draft.pdf) algorithms are currently supported: `FF3-1`.\n- The implementation of the underlying algorithm is built on top of the excellent [Mysto FPE](https://github.com/mysto/python-fpe) library.\n- Tink FPE is currently available for Python and Java.\n- Regarding sensitivity for alphabet, FPE is designed to work with a specific alphabet, which is typically defined in the encryption algorithm. If the plaintext data contains characters that are not part of the defined alphabet, Tink FPE supports different _strategies_ for dealing with the data or substitute the characters with ones that are part of the alphabet.\n\n## Requirements\n\n- Google Tink for Python - the bleeding edge version (until [this issue](https://github.com/google/tink/issues/623) is resolved)\n\n## Installation\n\nYou can install _Tink FPE_ via [pip] from [PyPI]:\n\n```console\n$ pip install tink-fpe\n```\n\n## Usage\n\n```python\nimport tink\nimport tink_fpe\n\n# Register Tink FPE with the Tink runtime\ntink_fpe.register()\n\n# Specify the key template to use. In this example we want a 256 bits FF3-1 key that can handle\n# alphanumeric characters (ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789)\nkey_template = tink_fpe.fpe_key_templates.FPE_FF31_256_ALPHANUMERIC\n\n# Create a keyset\nkeyset_handle = tink.new_keyset_handle(key_template)\n\n# Get the FPE primitive\nfpe = keyset_handle.primitive(tink_fpe.Fpe)\n\n# Encrypt\nciphertext = fpe.encrypt(b'Secret123')\nprint(ciphertext.decode('utf-8')) #-> sN3gt6q0V\n\n# Decrypt\ndecrypted = fpe.decrypt(ciphertext)\nprint(decrypted.decode('utf-8')) #-> Secret123\n```\n\n### Handling non-alphabet characters\n\nA characteristic of Format-Preserving Encryption is that plaintext can only be composed of letters or symbols\nfrom a predefined set of characters called the \"alphabet\". Tink FPE supports different ways of coping with\ntexts that contain non-alphabet characters. The approach to use can be expressed via the `UnknownCharacterStrategy` enum.\n\nThe following _stragies_ are supported:\n\n- `FAIL` - Raise an error and bail out if encountering a non-alphabet character. **(this is the default)**\n- `SKIP` - Ignore non-alphabet characters, leaving them unencrypted (nested into the ciphertext).\n- `DELETE` - Remove all characters that are not part of the alphabet prior to processing. \\_Warning: Using this strategy implies that the length of the plaintext and ciphertext may differ.\n- `REDACT` - Replace non-alphabet characters with an alphabet-compliant character prior to processing. _Warning: Using this strategy means that decryption may not result in the exact same plaintext being restored._\n\n```python\nfrom tink_fpe import FpeParams, UnknownCharacterStrategy\n\n# The following will raise an Error\nciphertext = fpe.encrypt(b'Ken sent me...', FpeParams(strategy=UnknownCharacterStrategy.FAIL))\n\n# Skipping non-supported characters might reveal too much of the plaintext, but it is currently the only\n# approach that will handle any plaintext without either failing or irreversibly transforming the plaintext.\nparams = FpeParams(strategy=UnknownCharacterStrategy.SKIP)\nfpe.encrypt(b'Ken sent me...', params) #-> UEj l1Ns sj...\nfpe.decrypt(ciphertext, params) #-> Ken sent me...\n\n# Notice that using the DELETE strategy implies that the length of the plaintext and ciphertext may differ.\n# Furthermore, it might be impossible to go back to the original plaintext.\nparams = FpeParams(strategy=UnknownCharacterStrategy.DELETE)\nciphertext = fpe.encrypt(b'Ken sent me...', params) #-> EsQPgkE9Y\ndecrypted = fpe.decrypt(ciphertext, params) #-> Kensentme\n\n# Notice that using the REDACT strategy it might be impossible to go back to the original plaintext.\n# If not specified, the redaction character will be deduced automatically from the alphabet.\n# For alphanumeric alphabets the 'X' character is used.\nparams = FpeParams(strategy=UnknownCharacterStrategy.REDACT)\nciphertext = fpe.encrypt(b'Ken sent me...', params) #-> MMY2HXvLwzIDoY\ndecrypted = fpe.decrypt(ciphertext, params) #-> KenXsentXmeXXX\n\n# It is also possible to specify the redaction character explicitly, like so:\nparams = FpeParams(strategy=UnknownCharacterStrategy.REDACT, redaction_char='Q')\nciphertext = fpe.encrypt(b'Ken sent me...', params) #-> 9fVDzAODt2vvdz\ndecrypted = fpe.decrypt(ciphertext, params) #-> KenQsentQmeQQQ\n```\n\n### Loading predefined key material\n\nIt is easy to initialize key material from a predefined JSON. The following uses a cleartext keyset,\nbut it will be similar for a wrapped/encrypted key as well.\n\n```python\nimport json\nfrom tink import JsonKeysetReader\nfrom tink import cleartext_keyset_handle\nimport tink_fpe\n\ntink_fpe.register()\n\nkeyset_json = json.dumps({\n    \"primaryKeyId\": 1382079328,\n    \"key\": [\n        {\n            \"keyData\": {\n                \"typeUrl\": \"type.googleapis.com/ssb.crypto.tink.FpeFfxKey\",\n                \"value\": \"EhD4978shQNRpBNaBjbF4KO4GkIQAho+QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=\",\n                \"keyMaterialType\": \"SYMMETRIC\"\n            },\n            \"status\": \"ENABLED\",\n            \"keyId\": 1382079328,\n            \"outputPrefixType\": \"RAW\"\n        }\n    ]\n})\n\nkeyset_handle = cleartext_keyset_handle.read(JsonKeysetReader(keyset_json))\nfpe = keyset_handle.primitive(tink_fpe.Fpe)\n```\n\n### Using key material protected by Google Cloud KMS\n\n```python\nimport json\n\nfrom tink import JsonKeysetReader\nfrom tink import read_keyset_handle\nfrom tink.integration import gcpkms\n\nimport tink_fpe\n\n\n# Define uri to key encryption key and path to GCP credentials\ngcp_credentials = \"path/to/sa-key.json\"\n\n# Register Tink FPE with the Tink runtime\ntink_fpe.register()\n\n# Get hold of a wrapped data encryption key (WDEK)\nkeyset_json = {\n    \"kekUri\": \"gcp-kms://projects/<project-id>/locations/<region>/keyRings/my-keyring/cryptoKeys/my-kek\",\n    \"encryptedKeyset\": \"CiQAp91NBsClBYjw4AS9sOdB65peMwlzY4AiOzyMe+b+dFjSBuIS2QEAZ30rtRcDkuvtUgeENQCt29Vsalf+FtaNZc8wpOXKb3sD2c8hTXKaf34iq2QRMaQUBXxG+YSJPV4PvJZMGydZpjowM9K2eAJFZs5JaVxb3BMfUt0miNaORZmczqZhKlXXHbMoQ71GLwfSnf4jJnIRJK4s38ThnxS2ebm4b5T0qno6PWg84TtUw9eIIieqlUFhIqBjCcMugGTsE+xfWIOct22RDEUI3cAboCew5ppjOREAxzbaH8LaUBct5eLN8wtakY3Vv8KxBoT3Hq6fnNSSGOKmkqMVrK0p\",\n    \"keysetInfo\":\n        {\n            \"primaryKeyId\": 593699223,\n            \"keyInfo\":\n                [\n                    {\n                        \"typeUrl\": \"type.googleapis.com/ssb.crypto.tink.FpeFfxKey\",\n                        \"status\": \"ENABLED\",\n                        \"keyId\": 593699223,\n                        \"outputPrefixType\": \"RAW\"\n                    }\n                ]\n        }\n}\n\n# Extract the kek uri from the keyset json\nkek_uri = keyset_json.pop('kekUri')\n\n# Unwrap key using Google Cloud KMS\nkms_client = gcpkms.GcpKmsClient(kek_uri, gcp_credentials)\nkms_aead = kms_client.get_aead(kek_uri)\nkeyset_handle = read_keyset_handle(keyset_reader=JsonKeysetReader(json.dumps(keyset_json)),\n                                   master_key_aead=kms_aead)\n\n# Get the FPE primitive\nfpe = keyset_handle.primitive(tink_fpe.Fpe)\n```\n\n### Dockerfile\n\nAs of this writing (27.03.2023), Tink does not yet provide Python wheels for versions `>1.6.x`.\nThus, in order to use Tink FPE, we need to build Tink, which involves using bazel and and\ncompiling protobuf sources. The following shows a Dockerfile that demonstrates how this can\nbe done. Notice that this is for the `x86` architecture. If you are on another\narchitecture (e.g. `arm`), you need to substitute the bazel and protobuf references to match\nyour system architecture.\n\n```dockerfile\nFROM python:3.10-bullseye\n\nRUN apt-get update && apt-get upgrade -y\n\n# Install curl and git\nRUN apt-get install -y curl git\n\n# Install bazel\nRUN curl -L https://github.com/bazelbuild/bazelisk/releases/download/v1.16.0/bazelisk-linux-amd64 > /usr/local/bin/bazelisk && chmod +x /usr/local/bin/bazelisk\n\n# Install latest protobuf compiler (note: protobuf-compiler from apt is an older non-compliant version)\nWORKDIR /opt/protobuf\nRUN curl -L https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_64.zip > protoc.zip\nRUN unzip protoc.zip && chmod +x ./bin/protoc\nRUN ln -s /opt/protobuf/bin/protoc /usr/local/bin/protoc\n\n# Update pip\nRUN pip install --upgrade pip\n\n# ...\nWORKDIR /app\n```\n\n## Known issues\n\n// TODO: Describe issue about chunking that results in up to last 3 characters not being encrypted.\n// TODO: Describe issue with minimum length depending on the alphabet radix (e.g. 4 characters for alphanumeric and 6 for digits)\n\n## Contributing\n\nContributions are very welcome.\nTo learn more, see the [Contributor Guide].\n\n## License\n\nDistributed under the terms of the [MIT license][license],\n_Tink FPE Python_ is free and open source software.\n\n## Issues\n\nIf you encounter any problems,\nplease [file an issue] along with a detailed description.\n\n## Credits\n\nThis project was generated from [@cjolowicz]'s [Hypermodern Python Cookiecutter] template.\n\n[@cjolowicz]: https://github.com/cjolowicz\n[pypi]: https://pypi.org/\n[hypermodern python cookiecutter]: https://github.com/cjolowicz/cookiecutter-hypermodern-python\n[file an issue]: https://github.com/statisticsnorway/tink-fpe/issues\n[pip]: https://pip.pypa.io/\n\n<!-- github-only -->\n\n[license]: https://github.com/statisticsnorway/tink-fpe-python/blob/main/LICENSE\n[contributor guide]: https://github.com/statisticsnorway/tink-fpe-python/blob/main/CONTRIBUTING.md\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Format-Preserving Encryption support for Google Tink",
    "version": "0.4.0",
    "project_urls": {
        "Changelog": "https://github.com/statisticsnorway/tink-fpe-python/releases",
        "Documentation": "https://statisticsnorway.github.io/tink-fpe-project",
        "Homepage": "https://github.com/statisticsnorway/tink-fpe-project",
        "Repository": "https://github.com/statisticsnorway/tink-fpe-python"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c188d4149c3187073562426cb428f32e20842fc0167f1c28e7afa2f903b65397",
                "md5": "04c9f6cc116b64a5cafbb6740cb34abb",
                "sha256": "2af48c84987ebf7117d665126dcfd60c19d55768824493d1f881440936517cc3"
            },
            "downloads": -1,
            "filename": "tink_fpe-0.4.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "04c9f6cc116b64a5cafbb6740cb34abb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 16497,
            "upload_time": "2023-08-31T09:25:56",
            "upload_time_iso_8601": "2023-08-31T09:25:56.356631Z",
            "url": "https://files.pythonhosted.org/packages/c1/88/d4149c3187073562426cb428f32e20842fc0167f1c28e7afa2f903b65397/tink_fpe-0.4.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6df18d5b1669910c3ce9e888d0eaa42e1d87a9447ff8b5025903c529a529278c",
                "md5": "d67d364dfe51ecfa48c3acecc0c2fb65",
                "sha256": "b3f5d52e92f66145bd69fb9287daf76b6c7fd5ec61e006db2682fc94b1ac2486"
            },
            "downloads": -1,
            "filename": "tink_fpe-0.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "d67d364dfe51ecfa48c3acecc0c2fb65",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 17227,
            "upload_time": "2023-08-31T09:25:58",
            "upload_time_iso_8601": "2023-08-31T09:25:58.449253Z",
            "url": "https://files.pythonhosted.org/packages/6d/f1/8d5b1669910c3ce9e888d0eaa42e1d87a9447ff8b5025903c529a529278c/tink_fpe-0.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-08-31 09:25:58",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "statisticsnorway",
    "github_project": "tink-fpe-project",
    "github_not_found": true,
    "lcname": "tink-fpe"
}
        
Elapsed time: 0.33761s