How the TeslaMate Vault Module Encrypts API Tokens Using AES-256-GCM
The TeslaMate Vault module encrypts API tokens using AES-256-GCM by deriving a 256-bit key from a configured secret via SHA-256 hashing and delegating cryptographic operations to the Cloak library with a mandatory 12-byte initialization vector.
TeslaMate, the open-source data logger for Tesla vehicles, secures sensitive API credentials through its TeslaMate.Vault module. This Elixir GenServer implements robust encryption mechanisms to ensure that stored access tokens remain confidential and tamper-proof. Understanding how the Vault module encrypts API tokens using AES-256-GCM requires examining the key derivation process, cipher configuration, and integration with the Cloak encryption library as implemented in the teslamate-org/teslamate repository.
Architecture and Cipher Configuration
The Vault module in lib/teslamate/vault.ex acts as a thin wrapper around the Cloak encryption library. When the Vault process initializes, it constructs a cipher configuration that specifies the exact cryptographic parameters for all encryption operations.
AES-256-GCM Implementation
According to the TeslaMate source code, the default_cipher/1 function (lines 38-40) configures Cloak to use the AES-GCM algorithm with a mandatory 12-byte IV length required for GCM interoperability:
# From lib/teslamate/vault.ex
defp default_cipher(encryption_key) do
{Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: encryption_key, iv_length: 12}
end
This configuration ensures that every encryption operation uses AES-256-GCM, providing both confidentiality through encryption and integrity via authentication tags.
Key Derivation and Management
Before encryption can occur, the Vault must obtain and process the encryption key through a multi-step derivation process defined in lib/teslamate/vault.ex.
Obtaining the Raw Encryption Key
The Vault reads the initial encryption key from multiple sources, as implemented in lines 48-84. The system checks:
- Application environment configuration
- A temporary file stored at runtime
- An import directory for migration purposes
If no existing key is found, the Vault generates a cryptographically secure random key and logs its creation for administrative purposes.
SHA-256 Key Derivation
To ensure compatibility with AES-256-GCM's 256-bit key requirement, the raw key undergoes hashing. Lines 80-83 of lib/teslamate/vault.ex implement this derivation:
# Key derivation for AES-256 compatibility
encryption_key
|> :crypto.hash(:sha256)
|> binary_part(0, 32)
This SHA-256 hash of the raw key produces exactly 32 bytes (256 bits), satisfying the AES-256 key size requirements regardless of the original key length.
The Encryption Workflow
Once initialized, the Vault processes use the derived key and Cloak configuration to protect API tokens.
Cipher Tuple Construction
The final cipher tuple pairs Cloak.Ciphers.AES.GCM with specific options including the derived key, the tag identifier "AES.GCM.V1", and the IV length of 12 bytes. This tuple controls all subsequent cryptographic operations.
Encryption and Decryption Operations
When encrypting a token, Cloak automatically generates a fresh random 12-byte IV for each operation. The resulting encrypted binary contains:
- A header with the key tag
- The 12-byte IV
- The authentication tag (for integrity verification)
- The ciphertext
The test suite in test/teslamate/vault_test.exs (lines 98-103) verifies that the default cipher indeed uses AES-GCM with the specified 12-byte IV length, ensuring the implementation matches the security requirements.
Practical Implementation Examples
To encrypt a raw API token using the Vault module:
# Encrypt a raw API token
{:ok, encrypted_token} = TeslaMate.Vault.encrypt("my-api-token")
# Decrypt the stored token later
{:ok, "my-api-token"} = TeslaMate.Vault.decrypt(encrypted_token)
To inspect the active cipher configuration for debugging:
# Inspect the cipher that Vault uses
cipher = TeslaMate.Vault.default_cipher(:crypto.strong_rand_bytes(32))
# => {Cloak.Ciphers.AES.GCM,
# [tag: "AES.GCM.V1", key: <<…>>, iv_length: 12]}
The migration file at priv/migrations/20220123131732_encrypt_api_tokens.exs creates the tm_encryption.key file that Vault uses to persist the encryption key across restarts.
Summary
- TeslaMate.Vault wraps the Cloak library to provide AES-256-GCM encryption for API tokens in
lib/teslamate/vault.ex. - The encryption key is derived using SHA-256 hashing to produce a 256-bit key compatible with AES-256-GCM requirements.
- The cipher configuration specifies a 12-byte IV and uses the
Cloak.Ciphers.AES.GCMmodule for all cryptographic operations. - Each encryption generates a fresh random IV and produces a binary containing the header, IV, authentication tag, and ciphertext.
- The implementation is verified by the test suite in
test/teslamate/vault_test.exsto ensure AES-GCM compliance.
Frequently Asked Questions
What encryption algorithm does TeslaMate use for API tokens?
TeslaMate uses AES-256-GCM (Galois/Counter Mode) to encrypt API tokens. This algorithm provides both confidentiality and integrity protection through authentication tags, ensuring that encrypted tokens cannot be read or modified without detection.
How is the encryption key generated or loaded?
The Vault module attempts to load the encryption key from the application environment, a temporary file, or an import directory. If no key exists, it generates a cryptographically secure random key using Erlang's :crypto module. The key is then hashed with SHA-256 to derive the final 256-bit encryption key used by AES-GCM.
Why does TeslaMate use a 12-byte IV for AES-GCM?
The 12-byte (96-bit) IV length is the standard required for GCM interoperability and optimal performance. This length is hardcoded in the default_cipher/1 function via the @iv_length attribute set to 12, ensuring compatibility with the Cloak library's AES.GCM implementation and compliance with NIST recommendations for GCM mode.
Where is the encryption key stored in TeslaMate?
The encryption key is stored in the tm_encryption.key file within the TeslaMate data directory. This file is created during database migrations (specifically priv/migrations/20220123131732_encrypt_api_tokens.exs) and read at runtime by the Vault process to ensure persistent access to encrypted data across application restarts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →