{"record":{"id":"01079bbc1339ac51","repo":"AlexxIT/go2rtc","slug":"w-unable-to-decrypt","errorCode":null,"errorMessage":"%w: unable to decrypt","messagePattern":"%w: unable to decrypt","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/tutk/dtls/cipher.go","lineNumber":209,"sourceCode":"\t\treturn err\n\t}\n\n\tc.aead.Store(aead)\n\treturn nil\n}\n\nfunc (c *TLSEcdhePskWithChacha20Poly1305Sha256) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {\n\taead, ok := c.aead.Load().(*ChaCha20Poly1305Cipher)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"%w: unable to encrypt\", errCipherSuiteNotInit)\n\t}\n\treturn aead.Encrypt(pkt, raw)\n}\n\nfunc (c *TLSEcdhePskWithChacha20Poly1305Sha256) Decrypt(h recordlayer.Header, raw []byte) ([]byte, error) {\n\taead, ok := c.aead.Load().(*ChaCha20Poly1305Cipher)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"%w: unable to decrypt\", errCipherSuiteNotInit)\n\t}\n\treturn aead.Decrypt(h, raw)\n}\n\nfunc CustomCipherSuites() []dtls.CipherSuite {\n\treturn []dtls.CipherSuite{\n\t\tNewTLSEcdhePskWithChacha20Poly1305Sha256(),\n\t}\n}\n","sourceCodeStart":191,"sourceCodeEnd":219,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/tutk/dtls/cipher.go#L191-L219","documentation":"Mirror of the Encrypt path: Decrypt on TLSEcdhePskWithChacha20Poly1305Sha256 requires the AEAD cipher to be initialized by the handshake. If the atomic pointer does not hold a *ChaCha20Poly1305Cipher (typically nil before key derivation), the library returns errCipherSuiteNotInit wrapped with 'unable to decrypt'.","triggerScenarios":"Calling Decrypt (directly or via record-layer processing) before the handshake has set c.aead — reading records on a session whose key material was never derived, or concurrent decrypts during handshake.","commonSituations":"Receiving encrypted flight data before handshake completes; using the cipher suite object standalone without running handshake; handshake aborted partway leaving aead unset; negotiated suite mismatch so the concrete type never loads.","solutions":["Ensure the DTLS handshake fully completes before processing records; gate reads on handshake completion.","Confirm the ChaCha20-Poly1305 suite is negotiated on both ends so aead gets populated.","Protect against concurrent access — initialize/read c.aead through the DTLS layer's synchronization.","Re-establish the session if aead remains uninitialized; the suite instance is unusable."],"exampleFix":"// before\nout, err := suite.Decrypt(h, raw)\n// after\nif !suite.Initialized() { // or <-handshakeDone\n\treturn errors.New(\"cipher suite not ready; handshake incomplete\")\n}\nout, err := suite.Decrypt(h, raw)","handlingStrategy":"try-catch","validationCode":"// Only process records after key derivation\nif !handshakeCompleted.Load() {\n\treturn errors.New(\"records cannot be decrypted before handshake\")\n}","typeGuard":"func suiteReady(s *TLSEcdhePskWithChacha20Poly1305Sha256) bool {\n\t_, ok := s.aead.Load().(*ChaCha20Poly1305Cipher)\n\treturn ok\n}","tryCatchPattern":"out, err := suite.Decrypt(h, raw)\nif err != nil {\n\tif errors.Is(err, errCipherSuiteNotInit) {\n\t\treturn errors.New(\"handshake incomplete — wait for handshake done signal\")\n\t}\n\treturn err\n}","preventionTips":["Complete the DTLS handshake before feeding records to the suite","Confirm both sides negotiate the ChaCha20-Poly1305 suite so aead is set","Use the DTLS conn layer (which manages suite lifecycle) rather than raw suites","Re-establish the session if initialization never happens"],"tags":["dtls","crypto","tls","initialization"],"backgroundTag":"invalid-state-transition","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}