Metadata-Version: 2.4
Name: pxa-security
Version: 1.0.0
Summary: Purpose-specific credential and user-info encryption utilities.
Author-email: Daniel Lee <rootuser.kr@gmail.com>
License-Expression: Apache-2.0
Keywords: encryption,aes,aes-gcm,password,kdf,scrypt
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography>=42
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Dynamic: license-file

# pxa-security

Purpose-specific credential and user-info encryption utilities.

```bash
pip install pxa-security
```

The distribution name is `pxa-security`; the import name is `pxa_security`.

## Credential API

Use a secret master key that is supplied separately from the configuration
file, normally through an environment variable or a secret manager. Tokens
use scrypt with a per-token random salt and AES-GCM authenticated
encryption.

```python
import os

from pxa_security import encrypt_credential, decrypt_credential

master_key = os.environ["PXA_CREDENTIAL_MASTER_KEY"]

# The token is safe to store in a config file; the master key is not.
token = encrypt_credential(master_key, "s3cret!")

# Decrypt with the separately supplied master key.
password = decrypt_credential(master_key, token)
assert password == "s3cret!"
```

A wrong master key, damaged token, or modified token raises `ValueError`:

```python
decrypt_credential("wrong-master-key", token)  # ValueError
```

Use at least 32 random bytes for the master key and never write it beside the
encrypted token. A username, application name, or other public identifier is
not a master key. One suitable value can be generated with
`secrets.token_urlsafe(32)` and then provisioned through your deployment's
secret store.

A master key shorter than 32 bytes is accepted — every token carries a
random scrypt salt, so short keys still encrypt and decrypt correctly — but
`encrypt_credential` emits a `UserWarning` to keep the recommendation
visible. Decryption never warns.

## User-info API

AES-128-CBC in a wire format compatible with the legacy Node.js
implementation: ciphertext is a hex string, the IV equals the key, and the
plaintext is a JSON object whose string values are wrapped in MIME
B-encoding (`=?UTF-8?B?<base64>?=`).

```python
from pxa_security import encrypt_userinfo, decrypt_userinfo

key = "0123456789abcdef"  # must be exactly 16 bytes (AES-128)

# Pass a dict: values are MIME-encoded and JSON-serialized automatically
data = encrypt_userinfo({"name": "홍길동", "dept": "IT"}, key)

userinfo = decrypt_userinfo(data, key)
assert userinfo == {"name": "홍길동", "dept": "IT"}
```

`encrypt_userinfo` also accepts a ready-made plaintext string (legacy
usage), and `decrypt_userinfo` decrypts data produced by the original
Node.js code as-is.

## API summary

| Function | Description |
| --- | --- |
| `encrypt_credential(master_key: str \| bytes, credential: str) -> str` | Encrypts a credential with a separately managed secret and returns an ASCII token. |
| `decrypt_credential(master_key: str \| bytes, encrypted_credential: str \| bytes) -> str` | Authenticates and decrypts a token produced by `encrypt_credential`. |
| `encrypt_userinfo(userinfo: str \| dict, key: str) -> str` | Encrypts user info with AES-128-CBC (legacy format); returns a hex string. |
| `decrypt_userinfo(encrypted_userinfo: str, key: str) -> dict` | Decrypts the hex string and returns the user-info dict with MIME-encoded values decoded. Raises `ValueError` on failure. |

## Security notes

- **Credential API**: AES-GCM ensures ciphertext modification and
  wrong keys are detected. scrypt makes offline guessing more expensive, but
  it cannot compensate for a weak or exposed master key. Keep the master key
  out of source control and configuration files.
- **User-info API**: the legacy format reuses the key as the IV, which makes
  encryption deterministic (identical plaintexts produce identical
  ciphertexts) and is kept **only for interoperability with existing data**.
  Prefer the credential API for new data.

## License

Apache License 2.0 — see [LICENSE](LICENSE).
