{"record":{"id":"906bae33dfea8d20","repo":"OpenNHP/opennhp","slug":"signature-verification-failed","errorCode":null,"errorMessage":"signature verification failed","messagePattern":"signature verification failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nhp/core/ztdo/ztdo.go","lineNumber":476,"sourceCode":"\t\t\t\treturn fmt.Errorf(\"invalid ztdo file\")\n\t\t\t}\n\t\t} else {\n\t\t\tif remainingCiphertextFileSize == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t// update recalculated signature\n\trecalcSig.sign(gcmKey)\n\n\tif ztdo.header.HasSignature() {\n\t\tif err := toStructure(ciphertextFile, &ztdo.signature); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !ztdo.signature.verify(recalcSig) {\n\t\t\treturn fmt.Errorf(\"signature verification failed\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// marshal searilizs Go struct into bytes buffer\nfunc marshal(buf *bytes.Buffer, data any) error {\n\trData := reflect.ValueOf(data)\n\tif rData.Kind() == reflect.Pointer {\n\t\trData = rData.Elem()\n\t}\n\n\tif rData.Kind() != reflect.Struct {\n\t\treturn fmt.Errorf(\"data must be a struct\")\n\t}\n\n\tfor i := range rData.NumField() {","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/core/ztdo/ztdo.go#L458-L494","documentation":"After decrypting, DecryptZtdoFile reads the trailing signature block and calls signature.verify(recalcSig), which recomputes the expected signature (recalcSig) and compares it with the one stored in the file. A mismatch means the file content was altered after signing or the signature was produced with different keys/data. The library throws to refuse processing tampered or mis-signed data.","triggerScenarios":"Calling DecryptZtdoFile on a signed ztdo file where signature.verify() returns false — the stored signature does not match the recalculated signature over the decrypted content.","commonSituations":"File modified after signing (edited metadata, re-chunked content); signed by a different key than the one used to verify; a bug in a custom writer that serialized the header/signature out of order; partial re-encryption of the file by another tool.","solutions":["Confirm the file came from a trusted, unmodified source and re-download/re-copy it.","Check that the signing key used by the producer matches the verification key expected here.","Regenerate the file: re-create the ztdo (including metadata/signature) from the original data instead of patching the corrupted one.","If you produce signed files, verify the signature immediately after writing to catch serialization-order bugs."],"exampleFix":"// before: assume file intact\nerr := ztdo.DecryptZtdoFile(f, pass)\n// after: detect and surface tampering distinctly\nif err := ztdo.DecryptZtdoFile(f, pass); err != nil {\n    if strings.Contains(err.Error(), \"signature verification failed\") {\n        return ErrTamperedZtdo // treat as security event, not I/O error\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := ztdo.DecryptZtdoFile(f, pass); err != nil {\n    if strings.Contains(err.Error(), \"signature verification failed\") {\n        log.SecurityEvent(\"ztdo_signature_mismatch\", path)\n        return ErrTampered\n    }\n    return err\n}","preventionTips":["Sign and verify with matching keys; keep key rotation coordinated","Verify signature immediately after writing signed ztdo files","Transport ztdo files over integrity-checked channels (TLS/checksums)","Never edit a signed ztdo file in place"],"tags":["ztdo","signature","integrity","tampering"],"backgroundTag":"checksum-mismatch","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"}