ChaCha20-Poly1305 mock in Python
Simulates ChaCha20-Poly1305 AEAD encryption and authentication using SHA-256 as a deterministic keystream and tag generator.
Python code
38 linesfrom hashlib import sha256
import struct
def chacha20_block(key, counter, nonce):
"""Mock ChaCha20 block: deterministic pseudo-random keystream from key+counter+nonce."""
state_input = key + struct.pack("<I", counter) + nonce + b"ChaCha20"
return sha256(state_input).digest()[:64] # 64-byte keystream block
def chacha20_encrypt(key, nonce, plaintext):
"""Encrypt plaintext by XORing with keystream blocks (mock ChaCha20)."""
ciphertext = b""
counter = 0
for i in range(0, len(plaintext), 64):
keystream = chacha20_block(key, counter + i // 64, nonce)
chunk = plaintext[i:i+64]
ciphertext += bytes(a ^ b for a, b in zip(chunk, keystream))
return ciphertext
def poly1305_tag(key, message):
"""Mock Poly1305: deterministic 16-byte tag using HMAC-style hashing."""
auth_key = sha256(key + b"poly1305").digest()
return sha256(auth_key + message).digest()[:16]
def aead_encrypt(key, nonce, plaintext, aad):
"""ChaCha20-Poly1305 mock: encrypt then authenticate ciphertext and AAD."""
ciphertext = chacha20_encrypt(key, nonce, plaintext)
tag = poly1305_tag(key, aad + ciphertext)
return ciphertext, tag
if __name__ == "__main__":
key = b"0123456789abcdef" # 16-byte key
nonce = b"abcdefghijkl" # 12-byte nonce
plaintext = b"hello world"
aad = b"metadata header"
ct, tag = aead_encrypt(key, nonce, plaintext, aad)
print("ciphertext:", ct.hex())
print("tag:", tag.hex())
Output
ciphertext: 7b7e3d1f0a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
tag: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f
How it works
This is a mock implementation for learning purposes only—it does not implement the actual ChaCha20 stream cipher or Poly1305 MAC. It substitutes SHA-256 to produce deterministic pseudo-random keystream and tag outputs, so encryption/authentication are conceptually demonstrated but not cryptographically secure. The chacha20_block function derives a keystream block from the key, counter, and nonce, while poly1305_tag derives a tag from the key, message, and a constant. The aead_encrypt function combines encryption and authentication to mimic an AEAD operation. Use the cryptography library or PyCryptodome for production-grade ChaCha20-Poly1305.
Common mistakes
- Using this mock in production believing it is secure.
- Reusing the same nonce with the same key.
- Not including the AAD in the authentication tag.
Variations
- Use `cryptography.hazmat.primitives.ciphers.aead.ChaCha20Poly1305` for a real, tested implementation.
- Implement actual ChaCha20 quarter-round functions and Poly1305 polynomial multiplication for a reference-compliant version.
Real-world use cases
- Demoing AEAD concepts in a security training or code sample without external dependencies.
- Prototyping a protocol that requires authenticated encryption before integrating a vetted library.
- Generating deterministic test vectors for a custom encryption module during development.
Sponsored
More from Auth & security at scale
- ACME LetsEncrypt Mock Challenge Server in Python medium
- AES GCM encryption and decryption in Python medium
- Build a Mock OIDC Userinfo Endpoint in Python with Flask easy
- ECDH key agreement in Python with cryptography medium
- Enforce TLS 1.2 Minimum in Python easy
- Fetch Secrets from a Mock Secrets Manager in Python easy
Keep learning
Related tutorials and quizzes for this topic.