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-herePut .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.pyNode 20.12+ (built-in fetch and process.loadEnvFile). No dependencies.
// Qrypt quickstart (Node 20.12+): turn 1 KiB of quantum entropy into an AES-256-GCM key.
// No dependencies. Needs a .env file with QRYPT_API_KEY=...
import { existsSync } from "node:fs";
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
if (existsSync(".env")) process.loadEnvFile(".env");
const fail = (msg) => { console.error(msg); process.exit(1); }, token = process.env.QRYPT_API_KEY;
if (!token) fail("QRYPT_API_KEY is missing. Copy .env.example to .env and paste your token from portal.qrypt.com.");
const base = process.env.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.
let res, body;
try {
res = await fetch(`${base}/api/v1/quantum-entropy?size=1`, { headers: {
Authorization: `Bearer ${token}`, Accept: "application/json",
"User-Agent": "qrypt-quickstart/1.0", "X-Qrypt-Client": "quickstart-js/1.0" } });
body = res.status === 200 ? await res.json() : null;
} catch (e) { fail(`Network error or non-JSON reply from Qrypt (${e.cause?.code ?? e.name}). Check your connection, proxy or TLS settings, then try again shortly.`); }
const 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 (res.status !== 200) fail(errors[res.status] ?? `Unexpected HTTP ${res.status}. See the troubleshooting page.`);
const key = Buffer.from(body.random[0], "base64").subarray(0, 32); // decode, then 32 bytes
const iv = randomBytes(12), msg = "hello, quantum entropy";
const c = createCipheriv("aes-256-gcm", key, iv), ct = Buffer.concat([c.update(msg), c.final()]);
const d = createDecipheriv("aes-256-gcm", key, iv); d.setAuthTag(c.getAuthTag());
if (Buffer.concat([d.update(ct), d.final()]).toString() !== msg) fail("Round trip failed.");
console.log("Success: AES-256-GCM round trip with a Qrypt entropy key (key not shown).");
node quickstart.mjs4. Expected output
Success: AES-256-GCM round trip with a Qrypt entropy key (key not shown).
Things that trip people up
sizecounts KiB, not bytes. Ask forsize=1(1,024 bytes) and take 32 bytes.- Base64-decode the string first; never use the text itself as the key.
- Live can return 429 about 1 s after a single prior call; wait 10 s or more and never loop.
- A wrong token returns 403, the same as an exhausted quota. Check the token first.
- Never print, log or commit the key or token. Use fresh entropy for each key.
Errors? See Troubleshooting.