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): 1 KiB of quantum entropy -> AES-256-GCM key.
# Setup: pip install requests cryptography python-dotenv
# Then put QRYPT_API_KEY=<your token> in a .env file next to this script.
import base64
import os
import sys

import requests
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from dotenv import load_dotenv

API = os.getenv("QRYPT_BASE_URL", "https://api-eus.qrypt.com")  # mock override

# One friendly message per failure. We never retry automatically.
HELP = {None: "QRYPT_API_KEY is missing: add it to .env (see .env.example).",
        400: "400: size must be 1-512. It counts KiB, not bytes.",
        401: "401: Authorization header missing, malformed or expired.",
        403: "403: Token invalid OR monthly quota used. Check the token first.",
        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, 503 and anything else: Qrypt is busy or erroring, so try again later.

# Step 1: read the token from .env. Never print or log it.
load_dotenv()
token = os.getenv("QRYPT_API_KEY") or sys.exit(HELP[None])

# Step 2: fetch 1 KiB of entropy. A custom User-Agent avoids Cloudflare's
# block on Python's urllib; X-Qrypt-Client tags quickstart traffic.
headers = {
    "Authorization": f"Bearer {token}", "Accept": "application/json",
    "User-Agent": "qrypt-quickstart/1.0", "X-Qrypt-Client": "quickstart-py/1.0"}
try:
    resp = requests.get(f"{API}/api/v1/quantum-entropy", params={"size": 1},
                        headers=headers, timeout=15)
    if resp.status_code != 200:
        sys.exit(HELP.get(resp.status_code, f"{resp.status_code}: Qrypt is "
                          "busy or erroring. Try again shortly."))
    entropy_b64 = resp.json()["random"][0]
except (requests.RequestException, ValueError):
    sys.exit("Network error or non-JSON reply: check proxy/TLS, retry soon.")

# Step 3: decode first, then keep 32 bytes as the AES-256 key.
key = base64.b64decode(entropy_b64)[:32]

# Step 4: encrypt and decrypt a sample message with AES-256-GCM.
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 key (not shown).")
.venv/bin/python quickstart.py

What the API returns

One base64 string per KiB requested. Decode it before use; it never contains the key itself.

{
  "random": ["<base64 string: 1,024 random bytes when decoded>"],
  "size": 1
}

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.

Using an AI coding agent?

In our tests, AI agents read part of .env (for example head -c 20 .env) in 14 of 15 runs, even when these docs told them not to. A doc can't stop that habit, but file permissions can. Run your agent inside this small Docker sandbox:

  1. Download the sandbox files: Dockerfile, entrypoint.sh, qrypt-run, qrypt-run-inner, run.sh, all into one folder called agent-sandbox/. Then run chmod +x agent-sandbox/*.sh agent-sandbox/qrypt-run*.
  2. Start the agent inside it (the project folder must already contain your .env):
    agent-sandbox/run.sh ~/my-project ~/my-project/.env your-agent-command
  3. Inside the sandbox, the agent runs as user agent. .env belongs to a separate user (qrypt, mode 600), so cat .env gets Permission denied. The program runs with qrypt-run quickstart.py, a fixed rule that runs one .py/.mjs/.js file as the qrypt user, so it can still read QRYPT_API_KEY from .env.

The agent CLI has to be available in the container. Either add it to the Dockerfile (for example RUN npm i -g your-agent) or mount it by setting SANDBOX_DOCKER_ARGS. For example, for Cursor CLI: SANDBOX_DOCKER_ARGS="-v $HOME/.local/share/cursor-agent/versions/VERSION:/opt/cursor-agent:ro -v $HOME/agent-home:/home/agent -e PATH=/opt/cursor-agent:/usr/local/bin:/usr/bin:/bin", with your agent's login file copied into ~/agent-home.

Limits: this stops accidental reads such as cat, head or an editor opening .env. It does not stop an agent that deliberately writes a program to print the token and runs it with qrypt-run. Review what your agent runs, and use a test token, not a production one.