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:

  1. Application environment configuration
  2. A temporary file stored at runtime
  3. 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.GCM module 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.exs to 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →