{"record":{"id":"8bffe50013e092c2","repo":"slackhq/nebula","slug":"incompatible-argon2-version-d","errorCode":null,"errorMessage":"incompatible Argon2 version: %d","messagePattern":"incompatible Argon2 version: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/crypto.go","lineNumber":131,"sourceCode":"\t\tparams.salt = make([]byte, 32)\n\t\tif _, err := rand.Read(params.salt); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\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","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/crypto.go#L113-L149","documentation":"deriveKey checks that the Argon2Parameters version matches the argon2.Version the library was compiled against (argon2id, version 0x13). A mismatch means the stored/constructed KDF parameters came from an incompatible Argon2 variant (argon2i/argon2d or a different version byte).","triggerScenarios":"Decrypting (or deriving with) parameters whose params.version was set manually or deserialized from data produced by a different Argon2 version — note Argon2Parameters.version is unexported, so this only happens via NewArgon2Parameters mishandling or crafted/edited encrypted blobs.","commonSituations":"Hand-editing encrypted key metadata, cross-version decryption between forks that used different argon2 libraries, or tests constructing Argon2Parameters without NewArgon2Parameters.","solutions":["Create parameters with NewArgon2Parameters(memory, parallelism, iterations) so the correct version is set.","If the blob came from another tool, re-encrypt the key with this library's EncryptAndMarshalSigningPrivateKey.","Align library versions between encrypting and decrypting parties."],"exampleFix":"// before\nparams := &cert.Argon2Parameters{Memory: 9k...} // version left zero-value\n// after\nparams := cert.NewArgon2Parameters(9*1024, 1, 4) // sets version = argon2.Version","handlingStrategy":"validation","validationCode":"// always construct parameters via the constructor so version is set correctly\nparams := cert.NewArgon2Parameters(9*1024, 1, 4) // version := argon2.Version (0x13)","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"incompatible Argon2 version\") {\n    return fmt.Errorf(\"encrypted key was produced with an incompatible Argon2 variant; re-encrypt with this library\")\n}","preventionTips":["Never construct Argon2Parameters literals manually; use NewArgon2Parameters.","Re-encrypt keys created by other tools or forks before use.","Keep the golang.org/x/crypto/argon2 dependency consistent across services."],"tags":["encryption","argon2","kdf"],"backgroundTag":"argon2-version-mismatch","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"}