OpenNHP/opennhp · error
Failed to decrypt ztdo file
Error message
Failed to decrypt ztdo file: %v
What it means
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.
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.
Example fix
// before: scheme guessed from header only
saData.SetRemoteStaticPublicKey(providerPublicKey)
gcmKey, ad = saData.AgreeSymmetricKey()
// after: verify scheme matches encryption metadata
if ztdo.GetCipherScheme() != localCipherScheme {
return "", fmt.Errorf("cipher scheme mismatch: file=%d local=%d", ztdo.GetCipherScheme(), localCipherScheme)
}
gcmKey, ad = saData.AgreeSymmetricKey() Defensive patterns
Strategy: try-catch
Validate before calling
if fi, err := os.Stat(ztdoPath); err != nil || fi.Size() == 0 {
return fmt.Errorf("ztdo input missing or empty")
}
if err := os.MkdirAll(filepath.Dir(output), 0o755); err != nil {
return fmt.Errorf("output dir not writable: %w", err)
} Type guard
func outputWritable(path string) bool { return filepath.Dir(path) != "" && unix.Access(filepath.Dir(path), unix.W_OK) == nil } Try / catch
if err := ztdo.DecryptZtdoFile(ztdoPath, output, gcmKey[:], ad); err != nil {
os.Remove(output) // avoid partial plaintext
return "", fmt.Errorf("Failed to decrypt ztdo file: %v", err)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to unwrap data private key
- failed to create ChaCha20-Poly1305
- unsupported GCM type
- private key parse error
- failed to create device
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/55dddbd3b2ac3f0c.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/agent/udpagent.go:1425
dataKeyPairEccMode := ztdo.GetECCMode()
dataMsgPattern := [][]ztdolib.MessagePattern{
{ztdolib.MessagePatternS, ztdolib.MessagePatternDHSS},
{ztdolib.MessagePatternRS, ztdolib.MessagePatternDHSS},
}
dataPrk, _ := base64.StdEncoding.DecodeString(dataPrkBase64)
saData := ztdolib.NewSymmetricAgreement(dataKeyPairEccMode, false)
saData.SetMessagePatterns(dataMsgPattern)
saData.SetStaticKeyPair(core.ECDHFromKey(dataKeyPairEccMode.ToEccType(), dataPrk))
providerPublicKey, _ := base64.StdEncoding.DecodeString(dataPrkWrapping.ProviderPublicKeyBase64)
saData.SetRemoteStaticPublicKey(providerPublicKey)
gcmKey, ad = saData.AgreeSymmetricKey()
if err := ztdo.DecryptZtdoFile(ztdoPath, output, gcmKey[:], ad); err != nil {
return "", fmt.Errorf("Failed to decrypt ztdo file: %v", err)
} else {
a.decryptedZtdoRecord[ztdoId] = output
}
} else {
output = decryptedOutput
}
} else {
teeNotAuthorizedCode, _ := strconv.Atoi(common.ErrTEENotAuthorized.ErrorCode())
if dagMsg.ErrCode == teeNotAuthorizedCode {
a.trustedByNHPDB.Store(false)
}
return "", fmt.Errorf("Error: fail to request ztdo with error: %s.", dagMsg.ErrMsg)
}
return output, nil
}
// GetFirstServerPeer returns the representative peer of an arbitraryView on GitHub (pinned to 6e04ca5ff0)