{"record":{"id":"ae547295ae2d9e33","repo":"slackhq/nebula","slug":"salt-must-be-set-in-argon2parameters","errorCode":null,"errorMessage":"salt must be set in argon2Parameters","messagePattern":"salt must be set in argon2Parameters","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/crypto.go","lineNumber":135,"sourceCode":"\t}\n\n\t// keySize of 32 bytes will result in AES-256 encryption\n\tkey, err := deriveKey(passphrase, 32, params)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn key, nil\n}\n\n// Derives a key from a passphrase using Argon2id\nfunc deriveKey(passphrase []byte, keySize uint32, params *Argon2Parameters) ([]byte, error) {\n\tif params.version != argon2.Version {\n\t\treturn nil, fmt.Errorf(\"incompatible Argon2 version: %d\", params.version)\n\t}\n\n\tif params.salt == nil {\n\t\treturn nil, fmt.Errorf(\"salt must be set in argon2Parameters\")\n\t} else if len(params.salt) < 16 {\n\t\treturn nil, fmt.Errorf(\"salt must be at least 128  bits\")\n\t}\n\n\tkey := argon2.IDKey(passphrase, params.salt, params.Iterations, params.Memory, params.Parallelism, keySize)\n\n\treturn key, nil\n}\n\n// Prepends nonce to ciphertext\nfunc joinNonceCiphertext(nonce []byte, ciphertext []byte) []byte {\n\treturn append(nonce, ciphertext...)\n}\n\n// Splits nonce from ciphertext\nfunc splitNonceCiphertext(blob []byte, nonceSize int) ([]byte, []byte, error) {\n\tif len(blob) <= nonceSize {\n\t\treturn nil, nil, fmt.Errorf(\"invalid ciphertext blob - blob shorter than nonce length\")","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/crypto.go#L117-L153","documentation":"deriveKey requires params.salt to be non-nil and at least 16 bytes. The public aes256DeriveKey auto-generates a random 32-byte salt when nil, so reaching this error means deriveKey was called directly (or via a path bypassing aes256DeriveKey) with no salt configured. A salt is required for Argon2id key derivation.","triggerScenarios":"Calling deriveKey (unexported) or constructing Argon2Parameters and invoking a KDF path that skips aes256DeriveKey's nil-salt random generation, e.g. custom code or a salt that is a non-nil empty slice would hit the <16 bytes branch instead.","commonSituations":"Forks/custom crypto code that call deriveKey directly; tests building Argon2Parameters manually; deserializing parameters from data with a zero-length salt field.","solutions":["Set a random >=16-byte salt: params.salt = make([]byte, 32); rand.Read(params.salt).","Prefer the public flow (NewArgon2Parameters + aes256Encrypt/aes256Decrypt) which generates the salt automatically.","If decrypting, ensure the salt stored in the metadata blob was not stripped or zeroed."],"exampleFix":"// before\nparams := cert.NewArgon2Parameters(9*1024, 1, 4)\nparams.Salt = nil // derive fails downstream in custom KDF call\n// after\nsalt := make([]byte, 32)\nio.ReadFull(rand.Reader, salt)\nparams.Salt = salt","handlingStrategy":"validation","validationCode":"params := cert.NewArgon2Parameters(9*1024, 1, 4)\n// for decrypt flows, ensure salt from metadata is >= 16 bytes before use\nif len(storedSalt) > 0 && len(storedSalt) < 16 {\n    return fmt.Errorf(\"stored salt must be at least 16 bytes\")\n}","typeGuard":"func validSalt(salt []byte) bool {\n    return len(salt) >= 16\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"salt must be set\") {\n    return fmt.Errorf(\"Argon2 parameters missing salt; use NewArgon2Parameters + the public encrypt/decrypt API\")\n}","preventionTips":["Use the public encrypt/decrypt API which auto-generates a random salt.","Never pass nil or empty salts to KDF code directly.","Preserve the salt bytes stored in encrypted metadata when moving files between systems."],"tags":["encryption","argon2","kdf","salt"],"backgroundTag":"missing-argon2-salt","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"}