Make an AES-256 key from quantum entropy

Time target: about 5 minutes No SDK needed: one HTTPS GET, then standard crypto.

1. Get a token

Create an account at portal.qrypt.com/register and generate a token for the Entropy service. It is shown only once and is billed like a password: keep it secret.

2. Save it in .env

QRYPT_API_KEY=paste-your-token-here

Put .env next to the script and add it to .gitignore. Never print it, not even partly (no cat .env). To check it is set, run grep -q '^QRYPT_API_KEY=.' .env && echo set.

3. Run the snippet

Python 3.9+. Uses requests: Cloudflare blocks Python's built-in urllib User-Agent.

python3 -m venv .venv && .venv/bin/pip install requests cryptography python-dotenv
# Qrypt quickstart (Python): turn 1 KiB of quantum entropy into an AES-256-GCM key.
# Needs: pip install -r requirements.txt  and a .env file with QRYPT_API_KEY=...
import base64, os, sys
import requests
from dotenv import load_dotenv
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

load_dotenv()
token = os.getenv("QRYPT_API_KEY")
if not token:
    sys.exit("QRYPT_API_KEY is missing. Copy .env.example to .env and paste your token from portal.qrypt.com.")
base = os.getenv("QRYPT_BASE_URL", "https://api-eus.qrypt.com")  # override only for the mock server
# size is in KiB, not bytes: size=1 returns 1,024 bytes. A custom User-Agent avoids Cloudflare's urllib block.
try:
    r = requests.get(f"{base}/api/v1/quantum-entropy", params={"size": 1}, timeout=15, headers={
        "Authorization": f"Bearer {token}", "Accept": "application/json",
        "User-Agent": "qrypt-quickstart/1.0", "X-Qrypt-Client": "quickstart-py/1.0"})
    data = r.json() if r.status_code == 200 else None
except (requests.RequestException, ValueError) as e:
    sys.exit(f"Network error or non-JSON reply from Qrypt ({type(e).__name__}). Check your connection, proxy or TLS settings, then try again shortly.")
errors = {
    400: "400 Bad request: size must be an integer from 1 to 512 (it counts KiB, not bytes).",
    401: "401 Missing, malformed or expired token header: it must be 'Bearer <token>'.",
    403: "403 Token invalid OR monthly quota reached. Check the token first (Qrypt returns 403 for a wrong token, not 401).",
    429: "429 Rate limited. Live can return 429 about 1 s after a single prior call; wait 10 s or more and never loop.",
    500: "500 Qrypt internal error. Try again shortly; contact support@qrypt.com if it persists.",
    503: "503 Qrypt entropy supply is temporarily low. Try again shortly."}
if r.status_code != 200:
    sys.exit(errors.get(r.status_code, f"Unexpected HTTP {r.status_code}. See the troubleshooting page."))
key = base64.b64decode(data["random"][0])[:32]  # decode first, then take 32 bytes = AES-256 key
aes, nonce, message = AESGCM(key), os.urandom(12), b"hello, quantum entropy"
assert aes.decrypt(nonce, aes.encrypt(nonce, message, None), None) == message
print("Success: AES-256-GCM round trip with a Qrypt entropy key (key not shown).")
.venv/bin/python quickstart.py

4. Expected output

Success: AES-256-GCM round trip with a Qrypt entropy key (key not shown).

Things that trip people up

Errors? See Troubleshooting.