A pure Lua implementation of common cryptographic primitives with zero external dependencies and optional OpenSSL acceleration. Runs on Lua 5.1, 5.2, 5.3, 5.4, and LuaJIT.
Hashing (SHA-256/512, BLAKE2), AEAD ciphers (ChaCha20-Poly1305, AES-GCM), the Poly1305 MAC, the ChaCha20 stream cipher, and Curve25519/448 Diffie-Hellman — portable enough to run inside sandboxed Lua hosts such as Control4 DriverWorks.
- Zero Dependencies: Pure Lua implementation, no C extensions required
- Portable: Runs on any Lua interpreter (5.1+) and LuaJIT
- Optional OpenSSL acceleration: Transparently prefers the host
lua-opensslbinding for hashing and AEAD when available, and falls back to pure Lua automatically - Well-tested: Every module ships known-answer self-tests (RFC vectors)
| Category | Algorithms | Module |
|---|---|---|
| Hash | SHA-256, SHA-512 (+ HMAC) | crypto.sha256, crypto.sha512 |
| Hash | BLAKE2s, BLAKE2b (+ HMAC) | crypto.blake2 |
| AEAD | ChaCha20-Poly1305 | crypto.chacha20_poly1305 |
| AEAD | AES-GCM | crypto.aes_gcm |
| Stream cipher | ChaCha20 | crypto.chacha20 |
| MAC | Poly1305 | crypto.poly1305 |
| Diffie-Hellman | X25519 | crypto.x25519 |
| Diffie-Hellman | X448 | crypto.x448 |
The pure-Lua implementations are the baseline and always work. When the host
provides the lua-openssl binding —
for example, Control4 DriverWorks exposes it beginning with OS 3.4.1 — you can
opt in to hardware-accelerated hashing and AEAD:
local crypto = require("crypto")
crypto.use_openssl(true) -- safe: falls back to pure Lua when unavailableAcceleration is applied per primitive and degrades gracefully: if the binding is
missing, or a particular operation is not supported by it, the pure-Lua path is
used instead. The Curve25519/448 Diffie-Hellman functions always use the
pure-Lua implementations regardless of this flag, because the shipped
lua-openssl builds cannot perform the raw X25519/X448 operations.
Download a pre-built single-file module from the Releases page:
crypto.lua— the canonical core build. Requiresbitn(lua-bitn) on the Lua path. Use this when composing with other libraries that already providebitn, so the shared dependency is vendored only once.crypto-portable.lua— portable build with every dependency bundled in (zero external dependencies). Use this when you want a single drop-in file.
git clone https://github.com/finitelabs/lua-crypto.git
cd lua-cryptoAdd the src and vendor directories to your Lua path, or copy the files into
your project.
local crypto = require("crypto")
print(crypto.version())
-- Optionally enable OpenSSL acceleration if available
-- crypto.use_openssl(true)
-- Hashing
local digest = crypto.sha512.sha512_hex("hello world")
-- HMAC
local tag = crypto.sha256.hmac_sha256_hex(key, message)
-- AEAD: encrypt returns ciphertext..tag; decrypt returns plaintext or nil
local sealed = crypto.chacha20_poly1305.encrypt(key, nonce, plaintext, aad)
local opened = crypto.chacha20_poly1305.decrypt(key, nonce, sealed, aad)
-- Diffie-Hellman (X25519); generate_keypair() returns private, public
local alice_priv, alice_pub = crypto.x25519.generate_keypair()
local bob_priv, bob_pub = crypto.x25519.generate_keypair()
local shared_a = crypto.x25519.diffie_hellman(alice_priv, bob_pub)
local shared_b = crypto.x25519.diffie_hellman(bob_priv, alice_pub)
assert(shared_a == shared_b)# Install development dependencies (stylua, luacheck, amalg)
make install-depsmake test # Run all module self-tests
make test-sha512 # Run a specific module's self-test
make test-matrix # Run tests across all Lua versions
make test-matrix-x25519 # Run a specific module across all Lua versions
# Or use the script directly with a custom Lua binary
LUA_BINARY=lua5.1 ./run_tests.shmake bench # Run all benchmarks
make bench-x25519 # Run a specific module benchmark
LUA_BINARY=luajit ./run_benchmarks.shmake check # Run format check and lint
make format # Format code with stylua
make lint # Run luacheckmake build # Build single-file distribution (build/crypto.lua)
make clean # Remove generated filesThis is a pure Lua implementation intended for portability and ease of use. While the algorithms are implemented correctly and pass their test vectors, the implementation:
- Cannot guarantee constant-time operations
- Has not been independently audited
- Is significantly slower than native implementations (enable OpenSSL acceleration where available)
For production use in security-critical applications, prefer native cryptographic libraries or the OpenSSL-accelerated path.
GNU Affero General Public License v3.0 — see LICENSE file for details.
Contributions are welcome! Please ensure all tests pass and add new tests for any new functionality.
