Status: Draft (Non-Normative Core)
Version: 1.0
Author: Massimo Russo
Last update: 2025-12
License: MIT
MX² (“MAX 2 eXcryption”) is a portable, password-protected container format for encrypting long-term, high-entropy secret phrases.
MX² is:
- open
- verifiable
- ASCII-safe
- fully reproducible
- based exclusively on standardized cryptography
The format is intentionally minimal and suitable for:
- file storage
- text encoding
- QR encoding
- cross-platform interoperability
This document defines:
- the MX2:pc:v1 container format
- the internal JSON record (MAXREC)
- the password-based encryption mechanism
- the normative requirements for compliant implementations.
MX² uses a simple but powerful three-layer trust model:
[1] Password (user secret)
│
▼
[2] MX² Container (encrypted vault)
│
▼
[3] Secret Phrases p1, p2 (root secrets)
[1] Password
- The only value the user must remember.
- It does not generate the secret phrases.
- It merely derives the key that unlocks the container.
[2] MX² Container
- An encrypted structure holding a JSON record (“MAXREC”).
- The container is portable and platform-agnostic.
[3] Secret Phrases (p1, p2)
Two long, high-entropy strings stored inside MAXREC.
These phrases act as the root secret from which applications may deterministically derive:
- encryption keys
- authentication keys
- identity keys
- post-quantum keypairs
- recovery or migration seeds
MX² does not prescribe any derivation mechanism — this is left to applications.
MX² only defines:
a secure, auditable, password-protected container
for storing p1 and p2.
Most cryptographic systems:
- store keys directly in a vault,
- derive one deterministic key from a password, or
- use a seed phrase tied to one specific ecosystem.
MX² introduces a different model:
A portable, password-protected container that stores two high-entropy secret phrases from
which unlimited deterministic keys can be derived — for any purpose and on any implementation.
The password only opens the vault. The phrases are the root secret.
MX² guarantees:
- no private keys stored on disk
- unlimited key derivations from a single root
- long-term recoverability
- complete auditability
- interoperability across independent implementations
MX² standardizes only the encrypted container format and the cryptographic mechanism used to protect the internal JSON record (MAXREC).
Implementations and applications:
- MUST treat p1 and p2 as application-level root secrets;
- MAY derive p1 and p2 from user input in any way they choose (passwords, hardware tokens, local RNG, external systems, etc.);
- MAY use p1 and p2 to derive a wide range of keys and identities.
MX² explicitly does not define:
- how p1 and p2 are generated or managed over time;
- key management, rotation, or backup policies;
- multi-device synchronization or account recovery flows;
- user authentication, identity, or access control.
These aspects are intentionally left to the surrounding application or ecosystem.
The following terms are to be interpreted as defined in RFC 2119:
- MUST, MUST NOT
- SHOULD, SHOULD NOT
- MAY
A compliant implementation MUST satisfy:
- Portability — MX² must be representable as an ASCII-safe string.
- Interoperability — any implementation must be able to decrypt payloads generated by others.
- Transparency — MX² must use only standardized, public cryptographic primitives.
- Minimalism — the format must contain no unnecessary metadata.
- Security — secrecy of p1 and p2 must rely on password strength and modern primitives.
An MX² container MUST use the following structure:
MX2:pc:v1|xchacha20poly1305|salt_b64|nonce_b64|tag_b64|ciphertext_b64
Fields MUST be separated by the ASCII | character.
All fields except the header MUST be base64-encoded.
5.1 Header
Literal value:
MX2:pc:v1
Meaning:
- MX2: container family
- pc: Portable Container
- v1: version 1 of the format
Implementations MUST reject containers with an unknown version.
5.2 Algorithm identifier
Literal value: xchacha20poly1305
Meaning: The AEAD algorithm used for encryption. Implementations MUST reject any value different from "xchacha20poly1305".
5.3 salt_b64
- Base64 encoding of the Argon2id salt
- MUST be exactly 16 bytes
- MUST be unique per container
5.4 nonce_b64
- Base64 encoding of the XChaCha20 nonce
- MUST be exactly 24 bytes
- MUST be generated from a secure RNG
- MUST NOT repeat under the same key
5.5 tag_b64
- Base64 encoding of the 16-byte Poly1305 authentication tag
5.6 ciphertext_b64
- Base64 encoding of the AEAD ciphertext
- MUST contain a JSON document (MAXREC)
- MUST be produced using XChaCha20-Poly1305 AEAD
The decrypted payload MUST be valid UTF-8 JSON.
MAXREC = {
"type": "MAXREC", // MUST be literal "MAXREC"
"v": <uint>, // version of the record
"ts": <uint>, // timestamp (seconds)
"p1": <string>, // secret phrase 1
"p2": <string>, // secret phrase 2
"meta": { ... } OPTIONAL // non-normative
}
Requirements:
typeMUST be "MAXREC".- p1 and p2 MUST be high-entropy secret phrases. The specification does not impose any minimum length: entropy requirements depend on the application.
metaMAY contain arbitrary non-critical fields.- Implementations MUST ignore unknown fields.
The MX² encryption pipeline consists of:
- Password preprocessing
- Key derivation
- AEAD encryption
- Assembly of the MX² container
7.1 Password Preprocessing
The user password (a UTF-8 string) MUST be transformed into an internal byte string before Argon2id is applied.
The reference construction used in this specification is:
- Compute the SHA-256 hash of the password and encode it as a 64-character lowercase hexadecimal string:
hex = SHA256(password) // 64 hex chars
- Let
first8 = the first 8 characters of hex
last8 = the last 8 characters of hex
- Derive two internal passcodes:
pass1 = password || "•1" || first8
pass2 = password || "•2" || last8
where all strings are encoded as UTF-8.
- Build a single internal byte string pwd_internal as:
pwd_internal = "P1" || 0x00 || pass1 || 0x00 || "P2" || 0x00 || pass2
where "P1" and "P2" are ASCII strings and 0x00 is a single zero byte.
This pwd_internal value is then used as the password input to Argon2id in Section 7.2.
Alternative domain-separated SHA-256 constructions MAY be used in non-interoperable deployments, but implementations that wish to be compatible with the reference Rust and Swift code MUST reproduce this exact pwd_internal construction.
7.2 Key Derivation (Argon2id)
The encryption key MUST be derived using Argon2id with the following parameters:
- memory: 64 MiB
- iterations: 3
- parallelism: 1
- output length: 32 bytes
Formally:
key32 = Argon2id(
password = pwd_internal,
salt = salt,
memory = 64 MiB,
iterations = 3,
parallelism= 1,
outputLen = 32
)
where pwd_internal is defined in Section 7.1 and salt is a 16–32 byte random value generated from a secure RNG.
Implementations that wish to decrypt containers produced by the reference code MUST derive key32 exactly as shown above.
7.3 AEAD Encryption (XChaCha20-Poly1305)
Plaintext: UTF-8 JSON (MAXREC)
Associated Data (AAD):
"MAX|MX2|pc|v1"
Nonce: 24 random bytes (MUST NOT repeat for the same key)
Output:
ciphertext, tag = XChaCha20-Poly1305_Encrypt(key32, nonce, plaintext, AAD)
7.4 Assembly
The final MX² container MUST be constructed as:
MX2:pc:v1|xchacha20poly1305|salt_b64|nonce_b64|tag_b64|ciphertext_b64
MX² is not deterministic as an encryption scheme.
- The format and key derivation are deterministic.
- The final ciphertext is randomized because of nonce + salt.
Thus:
- Two MX² containers created from the same inputs MUST differ.
- Implementations MUST NOT reuse nonce or salt.
This follows AEAD best practices.
- MX² does not contain private keys — only root secrets.
- p1 and p2 MUST be treated as highly sensitive values.
- MX² MUST be stored and transmitted securely.
- JSON payloads MUST NOT include derivable private keys.
- Changing p1 or p2 requires generating a new MX² container.
- The security of MX² depends on password strength and Argon2id parameters.
Current version:
MX2:pc:v1
Planned extensions:
- MX2:pc:v2 — extended metadata
- MX2:pc:v3 — binary compact container
- MX2:EX:v1 — extended eXcryption container
Implementations SHOULD support future version negotiation.
MX2:pc:v1|xchacha20poly1305|2sQ3QzF1zN0=|AAECAwQFBgcICQoLDA0ODxAREhM=|W7Rzuu9J6t5WZg==|p9S0P9uzp8DLiGsQmZq1zknHnNn0ZIqQ2xFZ2w==
This is a synthetic example and MUST NOT be interpreted as a valid container.
- Rust implementation (this repository)
- Swift implementation (MAX App)
- Python validator (planned)
All implementations MUST adhere to this specification for interoperability.
v1.0 — Draft
- Defines the MX2:pc:v1 format
- Defines MAXREC JSON structure
- Defines password preprocessing
- Defines Argon2id parameters
- Defines AEAD encryption and AAD
- Introduces normative and non-normative sections