Skip to content

envelope

envelope

Hybrid AES-256-GCM + RSA-OAEP(SHA-256) envelope encryption.

The datacrew.space website encrypts a Domo token with the VPS public key and stores only the resulting envelope in KV; the VPS MCP server is the sole holder of the private key and decrypts at call time.

Wire format (so the TypeScript/WebCrypto side can interop): base64( json({ "v": 1, "alg": "RSA-OAEP-256+A256GCM", "wrapped_key": b64(RSA-OAEP-SHA256(aes_key)), "iv": b64(12-byte GCM nonce), "ct": b64(AES-256-GCM ciphertext WITH the 16-byte tag appended), }) )

Both Python's AESGCM and WebCrypto's AES-GCM append the auth tag to the ciphertext, and RSA-OAEP with SHA-256 matches WebCrypto RSA-OAEP over a SHA-256 key, so envelopes round-trip across the two runtimes.

decrypt

decrypt(envelope: str, private_key_pem: str) -> str

Decrypt a base64 envelope using an RSA private key (PEM). Raises on tamper.

Source code in src/crew_dcs/mcp_server/envelope.py
68
69
70
71
72
73
74
75
76
77
78
79
def decrypt(envelope: str, private_key_pem: str) -> str:
    """Decrypt a base64 envelope using an RSA private key (PEM). Raises on tamper."""
    private_key = serialization.load_pem_private_key(
        private_key_pem.encode(), password=None
    )

    payload = json.loads(_b64d(envelope).decode("utf-8"))
    aes_key = private_key.decrypt(_b64d(payload["wrapped_key"]), _OAEP)
    plaintext = AESGCM(aes_key).decrypt(
        _b64d(payload["iv"]), _b64d(payload["ct"]), None
    )
    return plaintext.decode("utf-8")

encrypt

encrypt(plaintext: str, public_key_pem: str) -> str

Encrypt plaintext into a base64 envelope using an RSA public key (PEM).

Source code in src/crew_dcs/mcp_server/envelope.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def encrypt(plaintext: str, public_key_pem: str) -> str:
    """Encrypt `plaintext` into a base64 envelope using an RSA public key (PEM)."""
    public_key = serialization.load_pem_public_key(public_key_pem.encode())

    aes_key = os.urandom(32)
    iv = os.urandom(12)
    ciphertext = AESGCM(aes_key).encrypt(iv, plaintext.encode("utf-8"), None)
    wrapped_key = public_key.encrypt(aes_key, _OAEP)

    payload = {
        "v": ENVELOPE_VERSION,
        "alg": ENVELOPE_ALG,
        "wrapped_key": _b64e(wrapped_key),
        "iv": _b64e(iv),
        "ct": _b64e(ciphertext),
    }
    return _b64e(json.dumps(payload).encode("utf-8"))