JuliusBrussee/caveman · error

envelope: aes

Error message

envelope: aes: %w

What it means

After generating the data key, seal calls aes.NewCipher(dataKey) and wraps any failure as 'envelope: aes: %w'. With a 32-byte key this should always produce AES-256, so the error indicates the cipher could not be constructed — practically only possible if the key length is wrong or the crypto backend is unavailable (e.g. FIPS builds without AES).

Solutions

  1. Inspect the wrapped cause; confirm the data key is exactly 32 bytes.
  2. Verify the Go build includes standard AES support (avoid stripped/patched crypto packages).
  3. Rebuild with the official Go toolchain and retry.
  4. If on a restricted platform, enable an AES-capable crypto provider.
Defensive patterns

Strategy: try-catch

Try / catch

ciphertext, meta, err := envelope.Seal(plaintext, aad)
if err != nil {
    if strings.Contains(err.Error(), "envelope: aes") {
        log.Fatalf("AES unavailable in this build — rebuild with standard crypto: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Seal/SealForScope reaching aes.NewCipher with a dataKey whose length is not a valid AES key size, or a Go build whose AES implementation is unavailable.

Common situations: Custom/patched crypto stacks (FIPS-restricted builds); toolchain or hardware AES issues; code paths that modified the key material length before sealing.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/1948a73ee19d8f18. Report an issue: GitHub.

Appendix: source

Thrown at shared/platform/envelope/envelope.go:76

// SealForScope binds ciphertext authentication to tenant/object scope. Moving
// ciphertext plus metadata to another tenant, project, or object class makes
// decryption fail even when storage and KMS credentials are compromised.
func SealForScope(plaintext []byte, scope Scope) (ciphertext []byte, metaJSON []byte, err error) {
	aad, scopeHash, err := scopeAAD(scope)
	if err != nil {
		return nil, nil, err
	}
	return seal(plaintext, schemeV2, aad, scopeHash)
}

func seal(plaintext []byte, scheme string, aad []byte, scopeHash string) (ciphertext []byte, metaJSON []byte, err error) {
	dataKey := make([]byte, 32)
	if _, err := rand.Read(dataKey); err != nil {
		return nil, nil, fmt.Errorf("envelope: data key entropy: %w", err)
	}
	block, err := aes.NewCipher(dataKey)
	if err != nil {
		return nil, nil, fmt.Errorf("envelope: aes: %w", err)
	}
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, nil, fmt.Errorf("envelope: gcm: %w", err)
	}
	nonce := make([]byte, gcm.NonceSize())
	if _, err := rand.Read(nonce); err != nil {
		return nil, nil, fmt.Errorf("envelope: nonce entropy: %w", err)
	}
	ciphertext = gcm.Seal(nonce, nonce, plaintext, aad)

	wrapped, err := secretbox.EncryptPayloadKey(dataKey)
	if err != nil {
		return nil, nil, fmt.Errorf("envelope: wrap data key: %w", err)
	}
	meta := Metadata{Scheme: scheme, WrappedDataKey: base64.StdEncoding.EncodeToString(wrapped), ScopeHash: scopeHash}
	metaJSON, err = json.Marshal(meta)
	if err != nil {

View on GitHub (pinned to 3ee70a1026)