TinyAES
TinyAES is a lightweight, dependency-free Elixir wrapper for AES-256-GCM encryption and decryption using Erlang's :crypto module. It provides robust error handling, support for Additional Authenticated Data (AAD), and a simple API. The encryption key is securely retrieved from the ENCRYPTION_KEY environment variable.
Features
- Lightweight: Less than 50 lines of core code.
- Dependency-Free: Relies only on Erlang's
:cryptomodule. - Robust Error Handling: Covers returned
:error, raised{etag, reason, stack}exceptions, and key validation errors. - AES-256-GCM: Secure, authenticated encryption with 16-byte IV and tag.
- AAD Support: Optional Additional Authenticated Data for enhanced security.
- Key Management: Environment-based key retrieval with Base64 encoding.
- 3-tuples Compatible: Handles the latest
:cryptoexception format introduced with Erlang OTP 25.
Installation
Add TinyAES to your mix.exs dependencies:
{:tiny_aes, "~> 0.1"}
Run mix deps.get to fetch the dependency.
Setup
Generate a 32-byte encryption key, and add it to your .env file:
mix run -e 'TinyAES.puts_generate_key_env()'
# Copy the output to .env:
ENCRYPTION_KEY=your_base64_encoded_key_here
The function outputs a base64-encoded key, e.g., OuaO+dtNNgxJjQLGHMLJ9m8rSQDsVdqkGrf7ySSj3Yg=. Add the key to your .env file:
Ensure the ENCRYPTION_KEY environment variable is set in your application (e.g., using env_loader or dotenv).
Usage
Encrypt and decrypt data without optional AAD::
# Encrypt a message
plaintext = "Sensitive data"
ciphertext = TinyAES.encrypt(plaintext)
# Decrypt it
{:ok, decrypted} = TinyAES.decrypt(ciphertext)
assert decrypted == plaintextEncrypt and decrypt data with optional AAD (e.g., user or session ID)
# Encrypt a message
plaintext = "Sensitive data"
ciphertext = TinyAES.encrypt(plaintext, "optional_aad")
# Decrypt it
{:ok, decrypted} = TinyAES.decrypt(ciphertext, "optional_aad")
assert decrypted == plaintextHandle edge cases:
# Handle invalid input
TinyAES.decrypt("not a binary")
# {:error, "Ciphertext must be a binary with at least 32 bytes"}
# Handle missing key
System.delete_env("ENCRYPTION_KEY")
TinyAES.encrypt("test")
# {:error, "Encryption key not found in environment variable ENCRYPTION_KEY"}API
TinyAES.encrypt(plaintext, aad \\ ""):-
Encrypts plaintext, returning
<<iv::binary-16, tag::binary-16, ciphertext::binary>>or{:error, reason}.
-
Encrypts plaintext, returning
TinyAES.decrypt(ciphertext, aad \\ ""):-
Decrypts ciphertext, returning
{:ok, plaintext}or{:error, reason}.
-
Decrypts ciphertext, returning
TinyAES.puts_generate_key_env():-
Generates, prints, and returns
:okfor a Base64-encoded 32-byte key.
-
Generates, prints, and returns
TinyAES.generate_key_env():- Generates a Base64-encoded 32-byte key.
TinyAES.get_key_env():-
Retrieves and decodes the key from
ENCRYPTION_KEYreturning{:ok, key}or{:error, reason}.
-
Retrieves and decodes the key from
See HexDocs for full documentation.
Contributing
Contributions are welcome! Please open an issue or pull request on GitHub. For major changes, discuss them in an issue first. Ensure tests pass with mix test.
License
Released under the MIT License. See the LICENSE file for details.
Acknowledgments
Developed with the help of Grok, created by xAI. Thanks to Erlang's :crypto for providing a solid foundation.