{"record":{"id":"3419bd68497718e7","repo":"slackhq/nebula","slug":"invalid-aes-256-key-length-d-cowardly-refusin","errorCode":null,"errorMessage":"invalid AES-256 key length (%d) - cowardly refusing to encrypt","messagePattern":"invalid AES-256 key length \\((.+?)\\) - cowardly refusing to encrypt","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/crypto.go","lineNumber":56,"sourceCode":"\treturn &Argon2Parameters{\n\t\tversion:     argon2.Version,\n\t\tMemory:      memory, // KiB\n\t\tParallelism: parallelism,\n\t\tIterations:  iterations,\n\t}\n}\n\n// Encrypts data using AES-256-GCM and the Argon2id key derivation function\nfunc aes256Encrypt(passphrase []byte, kdfParams *Argon2Parameters, data []byte) ([]byte, error) {\n\tkey, err := aes256DeriveKey(passphrase, kdfParams)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// this should never happen, but since this dictates how our calls into the\n\t// aes package behave and could be catastraphic, let's sanity check this\n\tif len(key) != 32 {\n\t\treturn nil, fmt.Errorf(\"invalid AES-256 key length (%d) - cowardly refusing to encrypt\", len(key))\n\t}\n\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgcm, err := cipher.NewGCM(block)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnonce := make([]byte, gcm.NonceSize())\n\tif _, err := io.ReadFull(rand.Reader, nonce); err != nil {\n\t\treturn nil, err\n\t}\n\n\tciphertext := gcm.Seal(nil, nonce, data, nil)","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/crypto.go#L38-L74","documentation":"aes256Encrypt derives a 32-byte key via Argon2id and sanity-checks the length before AES-256-GCM encryption. A length other than 32 would silently degrade AES behavior, so the library refuses. With the fixed keySize of 32 in aes256DeriveKey this should never happen; it guards internal regressions.","triggerScenarios":"EncryptAndMarshalSigningPrivateKey reaching aes256Encrypt with a derived key whose length != 32 — only possible if internal KDF wiring changes or the function is invoked with modified code paths.","commonSituations":"Custom forks that changed deriveKey keySize, or patched crypto code; practically unreachable with the stock library.","solutions":["Use the stock library; do not modify aes256DeriveKey/deriveKey keySize.","If forking, ensure deriveKey is called with keySize=32 and Argon2 parameters produce a 32-byte output.","Report a bug if this occurs on unmodified code."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// ensure you use the stock API; the KDF key size is fixed at 32 bytes internally\n_, err := cert.EncryptAndMarshalSigningPrivateKey(key, cert.NewArgon2Parameters(9*1024, 1, 4))","typeGuard":null,"tryCatchPattern":"blob, err := cert.EncryptAndMarshalSigningPrivateKey(key, params)\nif err != nil && strings.Contains(err.Error(), \"invalid AES-256 key length\") {\n    return fmt.Errorf(\"internal KDF regression; do not modify keySize wiring: %w\", err)\n}","preventionTips":["Do not fork or patch aes256DeriveKey/deriveKey key sizes.","Report to upstream if triggered on unmodified code.","Pin the library version and review diffs when upgrading crypto code."],"tags":["encryption","aes","internal"],"backgroundTag":"invalid-key-length","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}