How croc's --store Feature Handles Encrypted Temporary File Storage

croc encrypts all files locally using AES-GCM with HKDF-derived keys before uploading to temporary storage, ensuring the server only handles ciphertext and never accesses plaintext or encryption keys.

The schollz/croc secure file transfer tool provides a --store flag that enables encrypted temporary file storage, allowing users to queue transfers that persist until retrieval or expiration. This feature uploads encrypted data to a relay storage service while maintaining strict zero-knowledge guarantees. The architecture ensures that all cryptographic operations occur client-side, rendering the temporary storage server incapable of decrypting or inspecting transferred content.

Client-Side Encryption Architecture

Master Key Generation and HKDF Derivation

When initiating a stored transfer, croc generates a cryptographically secure 256-bit master key using storecrypto.GenerateKey. This key serves as the root secret from which all purpose-specific subkeys are derived using HKDF (HMAC-based Extract-and-Expand Key Derivation Function).

Redeem Capabilities and Authorization Tokens

The system creates a redeem capability via storecrypto.RedeemCapability, which derives a 32-byte token authorizing read access without revealing decryption keys. This capability enables the storage service to verify download permissions while maintaining the zero-knowledge property.

Encrypting Manifests and File Chunks

Manifest Encryption with Transfer Binding

Before any file data uploads, croc encrypts the JSON manifest containing filenames, sizes, and SHA-256 hashes using storecrypto.SealManifest. This function employs AES-GCM AEAD encryption with associated data (AAD) that binds the manifest to the specific transfer ID, preventing substitution attacks.

Chunk-Level AEAD Protection

Files are split into 4 MiB blocks, with each chunk encrypted independently via storecrypto.SealChunk. Each chunk receives unique AAD containing the chunk index and transfer ID, ensuring integrity at the block level and preventing reordering attacks.

Uploading to Encrypted Temporary Storage

Storage Reservation and Metadata

The client initiates the upload process by calling storeclient.Client.createUpload, which POSTs encrypted manifest size, per-chunk sizes, and the redeem capability verifier to the storage service. The server returns a transfer ID and upload token without receiving any plaintext or cryptographic material.

Encrypted Data Transmission

Using storeclient.Client.uploadObjects and storeclient.Client.uploadFile, croc uploads the ciphertext manifest and encrypted chunks via authenticated HTTP PUT requests. The putWithRetry mechanism ensures reliable delivery of the encrypted payload without exposing plaintext to network errors.

Finalization and Local Receipts

After successful upload, storeclient.Client.completeUpload finalizes the transfer on the server. The CLI layer saves a local receipt via saveStoreReceipt in store-receipts.json, preserving the upload token for subsequent revocation.

Receiving and Revoking Stored Transfers

Decryption Process

Recipients parse the share token using storecrypto.ParseShare to extract the master key and transfer metadata. The client retrieves the encrypted manifest using the redeem capability, decrypts it with storecrypto.OpenManifest, then downloads and decrypts each chunk using storecrypto.OpenChunk, verifying SHA-256 checksums before atomic file installation.

Revocation Mechanism

Senders can revoke unclaimed transfers using croc --revoke <id>, which utilizes the locally stored receipt to authenticate a DELETE request to the storage service, immediately invalidating the encrypted temporary files regardless of their remaining lifetime.

Practical CLI Usage for Encrypted Storage

Send files to encrypted temporary storage:

croc send --store document.pdf photos/

Output includes the encrypted browser link and transfer token:

Stored transfer is encrypted and available until Thu, 01 Aug 2026 12:34:56 GMT
Browser link:
    https://store.example.com/s/ABCD1234#v1.<base64-master-key>
CLI recipient:
    croc-store-v1.<base64-origin>.<transfer-id>.<base64-master-key>

Receive the encrypted files:

croc

# Paste the token when prompted

Revoke before download:

croc --revoke ABCD1234

Summary

  • Client-side encryption uses AES-GCM with keys derived via HKDF from a 256-bit master key generated per transfer.
  • The storage server only handles ciphertext and redeem capabilities, maintaining zero-knowledge security.
  • Manifest and chunk-level integrity is enforced through transfer-specific AAD bindings that prevent tampering and reordering.
  • Local receipt storage in store-receipts.json enables secure revocation and transfer management.
  • All cryptographic operations in schollz/croc occur before data reaches the network, ensuring encrypted temporary file storage remains confidential even if the remote service is compromised.

Frequently Asked Questions

How does croc ensure the storage server cannot access my files?

All encryption occurs client-side before transmission. The server receives only AES-GCM ciphertext and redeem capabilities (authorization tokens), while the master encryption key remains exclusively with the sender and recipient through the share token. The server cannot decrypt content because it never possesses the HKDF-derived keys used for manifests or chunks.

What happens if a chunk upload fails during transfer?

The retry logic in storeclient/client.go automatically handles transient HTTP PUT failures for encrypted chunks, ensuring complete encrypted payload delivery without exposing plaintext to network errors. The client validates each upload before finalizing the transfer via completeUpload.

How long do encrypted files remain in temporary storage?

Transfers persist until the expiration time returned by Client.completeUpload, typically 24 hours, or until explicitly revoked using the local receipt saved by saveStoreReceipt. The encrypted data is automatically purged by the service after this period regardless of download status.

Why does croc use HKDF instead of using the master key directly?

HKDF enables separation of concerns by deriving distinct keys for manifests, data chunks, and redeem capabilities from the single master key. This prevents cryptographic key reuse across different contexts and ensures that compromise of one component (such as the redeem capability) does not endanger the confidentiality of file contents.

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 →