Skip to content

3ncr/tokencrypt-python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tokencrypt (3ncr.org)

Test PyPI version License: MIT

3ncr.org is a standard for string encryption / decryption (algorithms + storage format), originally intended for encrypting tokens in configuration files but usable for any UTF-8 string. v1 uses AES-256-GCM for authenticated encryption with a 12-byte random IV:

3ncr.org/1#<base64(iv[12] || ciphertext || tag[16])>

Encrypted values look like 3ncr.org/1#pHRufQld0SajqjHx+FmLMcORfNQi1d674ziOPpG52hqW5+0zfJD91hjXsBsvULVtB017mEghGy3Ohj+GgQY5MQ.

This is the official Python implementation.

Install

pip install tokencrypt

Requires Python 3.9+.

Usage

Pick a constructor based on the entropy of your secret — see the 3ncr.org v1 KDF guidance for the canonical recommendation.

Recommended: raw 32-byte key (high-entropy secrets)

If you already have a 32-byte AES-256 key, skip the KDF and pass it directly.

import os
from tokencrypt import TokenCrypt

key = os.urandom(32)  # or load from an env variable / secret store
tc = TokenCrypt.from_raw_key(key)

For a high-entropy secret that is not already 32 bytes (e.g. a random API token), hash it through SHA3-256:

tc = TokenCrypt.from_sha3("some-high-entropy-api-token")

Recommended: Argon2id (passwords / low-entropy secrets)

For passwords or passphrases, use TokenCrypt.from_argon2id. It uses the parameters recommended by the 3ncr.org v1 spec (m=19456 KiB, t=2, p=1). The salt must be at least 16 bytes.

from tokencrypt import TokenCrypt

tc = TokenCrypt.from_argon2id("correct horse battery staple", b"0123456789abcdef")

Legacy: PBKDF2-SHA3 (existing data only)

This library does not implement the legacy PBKDF2-SHA3 KDF that earlier 3ncr.org libraries (Go, Node.js, PHP, Java) shipped for backward compatibility. If you need to decrypt data produced by that KDF, derive the 32-byte key with hashlib.pbkdf2_hmac("sha3_256", ...) yourself and pass it to from_raw_key.

Encrypt / decrypt

plaintext = "08019215-B205-4416-B2FB-132962F9952F"
encrypted = tc.encrypt_3ncr(plaintext)
# e.g. "3ncr.org/1#pHRu..."

tc.decrypt_if_3ncr(encrypted)  # -> plaintext

decrypt_if_3ncr returns the input unchanged when it does not start with the 3ncr.org/1# header. This makes it safe to route every configuration value through it regardless of whether it was encrypted.

Decryption failures (bad tag, truncated input, malformed base64) raise tokencrypt.TokenCryptError.

Cross-implementation interop

This implementation decrypts the canonical v1 envelope test vectors shared with the Go, Node.js, and PHP reference libraries. The 32-byte AES key behind those vectors was originally derived via PBKDF2-SHA3-256 with secret = "a", salt = "b", iterations = 1000; the tests hardcode the resulting key and verify the AES-256-GCM envelope round-trips exactly. See tests/test_tokencrypt.py.

License

MIT — see LICENSE.

About

3ncr.org v1 string encryption for Python

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages