{"record":{"id":"55dddbd3b2ac3f0c","repo":"OpenNHP/opennhp","slug":"failed-to-decrypt-ztdo-file-v","errorCode":null,"errorMessage":"Failed to decrypt ztdo file: %v","messagePattern":"Failed to decrypt ztdo file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/agent/udpagent.go","lineNumber":1425,"sourceCode":"\t\t\tdataKeyPairEccMode := ztdo.GetECCMode()\n\n\t\t\tdataMsgPattern := [][]ztdolib.MessagePattern{\n\t\t\t\t{ztdolib.MessagePatternS, ztdolib.MessagePatternDHSS},\n\t\t\t\t{ztdolib.MessagePatternRS, ztdolib.MessagePatternDHSS},\n\t\t\t}\n\n\t\t\tdataPrk, _ := base64.StdEncoding.DecodeString(dataPrkBase64)\n\t\t\tsaData := ztdolib.NewSymmetricAgreement(dataKeyPairEccMode, false)\n\t\t\tsaData.SetMessagePatterns(dataMsgPattern)\n\t\t\tsaData.SetStaticKeyPair(core.ECDHFromKey(dataKeyPairEccMode.ToEccType(), dataPrk))\n\n\t\t\tproviderPublicKey, _ := base64.StdEncoding.DecodeString(dataPrkWrapping.ProviderPublicKeyBase64)\n\t\t\tsaData.SetRemoteStaticPublicKey(providerPublicKey)\n\n\t\t\tgcmKey, ad = saData.AgreeSymmetricKey()\n\n\t\t\tif err := ztdo.DecryptZtdoFile(ztdoPath, output, gcmKey[:], ad); err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"Failed to decrypt ztdo file: %v\", err)\n\t\t\t} else {\n\t\t\t\ta.decryptedZtdoRecord[ztdoId] = output\n\t\t\t}\n\t\t} else {\n\t\t\toutput = decryptedOutput\n\t\t}\n\t} else {\n\t\tteeNotAuthorizedCode, _ := strconv.Atoi(common.ErrTEENotAuthorized.ErrorCode())\n\t\tif dagMsg.ErrCode == teeNotAuthorizedCode {\n\t\t\ta.trustedByNHPDB.Store(false)\n\t\t}\n\n\t\treturn \"\", fmt.Errorf(\"Error: fail to request ztdo with error: %s.\", dagMsg.ErrMsg)\n\t}\n\treturn output, nil\n}\n\n// GetFirstServerPeer returns the representative peer of an arbitrary","sourceCodeStart":1407,"sourceCodeEnd":1443,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/agent/udpagent.go#L1407-L1443","documentation":"ztdo.DecryptZtdoFile failed while decrypting the ztdo file from ztdoPath into the output path using the agreed gcmKey and ad. Failures include GCM authentication tag mismatch (wrong key/AD), unreadable input file, or unwritable output path. On success the decrypted path is recorded in decryptedZtdoRecord.","triggerScenarios":"DecryptZtdoFile(ztdoPath, output, gcmKey[:], ad) errors: AES-GCM/SM4-GCM open failure because the derived key or AD differs from encryption time, wrong ECC-mode algorithm chosen, corrupt ciphertext, or file IO error on output.","commonSituations":"Provider key rotated between encryption and decryption; symmetric agreement inputs (PSK, patterns, remote static key) mismatched; data altered in storage breaking the AEAD tag; output directory missing or permission denied; mixing curve and GMSM cipher schemes.","solutions":["Confirm the same provider public key and cipher scheme (curve vs gmsm) used at encryption time.","Verify the downloaded file is intact (its id check passed and size matches) — AEAD failures usually mean altered data or wrong key.","Check output path is writable and its directory exists.","Re-request a fresh ztdo copy; if it persists, have the provider re-encrypt with current keys.","Align ztdolib versions so DataMessagePatterns/AD computation match."],"exampleFix":"// before: scheme guessed from header only\nsaData.SetRemoteStaticPublicKey(providerPublicKey)\ngcmKey, ad = saData.AgreeSymmetricKey()\n\n// after: verify scheme matches encryption metadata\nif ztdo.GetCipherScheme() != localCipherScheme {\n    return \"\", fmt.Errorf(\"cipher scheme mismatch: file=%d local=%d\", ztdo.GetCipherScheme(), localCipherScheme)\n}\ngcmKey, ad = saData.AgreeSymmetricKey()","handlingStrategy":"try-catch","validationCode":"if fi, err := os.Stat(ztdoPath); err != nil || fi.Size() == 0 {\n    return fmt.Errorf(\"ztdo input missing or empty\")\n}\nif err := os.MkdirAll(filepath.Dir(output), 0o755); err != nil {\n    return fmt.Errorf(\"output dir not writable: %w\", err)\n}","typeGuard":"func outputWritable(path string) bool { return filepath.Dir(path) != \"\" && unix.Access(filepath.Dir(path), unix.W_OK) == nil }","tryCatchPattern":"if err := ztdo.DecryptZtdoFile(ztdoPath, output, gcmKey[:], ad); err != nil {\n    os.Remove(output) // avoid partial plaintext\n    return \"\", fmt.Errorf(\"Failed to decrypt ztdo file: %v\", err)\n}","preventionTips":["Use the same cipher scheme (curve vs gmsm) end-to-end; never mix.","Re-verify ztdo id before decrypting so wrong records fail earlier.","Delete partial output files on failure to avoid trusting corrupt plaintext.","Rotate provider keys with a re-encryption migration, not in place."],"tags":["crypto","decryption","aead","ztdo"],"backgroundTag":"decryption-failed","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}