# How the TeslaMate Vault Module Encrypts API Tokens Using AES-256-GCM

> Discover how the TeslaMate Vault module secures API tokens with AES-256-GCM encryption. Learn about key derivation hashing and Cloak library integration for robust security.

- Repository: [TeslaMate/teslamate](https://github.com/teslamate-org/teslamate)
- Tags: internals
- Published: 2026-06-16

---

**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`](https://github.com/teslamate-org/teslamate/blob/main/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:

```elixir

# 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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/vault.ex) implement this derivation:

```elixir

# 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`](https://github.com/teslamate-org/teslamate/blob/main/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:

```elixir

# 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:

```elixir

# 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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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.