{"record":{"id":"077291d423862185","repo":"shadowsocks/shadowsocks-rust","slug":"packet-header-length-mismatch","errorCode":null,"errorMessage":"Packet header length mismatch","messagePattern":"Packet header length mismatch","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks/src/relay/udprelay/aead_2022.rs","lineNumber":229,"sourceCode":"            let cipher = get_cipher(method, key, session_id);\n\n            // Encrypt the rest of the packet with AEAD cipher (AES-*-GCM)\n            let (packet_header, mut message) = packet.split_at_mut(16);\n            let nonce = &packet_header[4..16];\n\n            if eih_len > 0 {\n                message = &mut message[eih_len..];\n            }\n\n            cipher.encrypt_packet(nonce, message);\n\n            // [SessionID + PacketID] is encrypted with AES-ECB with PSK\n            // No padding is required because these 2 fields are 128-bits, which is exactly the same as AES's block size\n            match method {\n                CipherKind::AEAD2022_BLAKE3_AES_128_GCM => {\n                    let cipher = Aes128::new_from_slice(ipsk).expect(\"AES-128 init\");\n                    let block = <&mut Block as TryFrom<&mut [u8]>>::try_from(packet_header)\n                        .expect(\"Packet header length mismatch\");\n                    cipher.encrypt_block(block);\n                }\n                CipherKind::AEAD2022_BLAKE3_AES_256_GCM => {\n                    let cipher = Aes256::new_from_slice(ipsk).expect(\"AES-256 init\");\n                    let block = <&mut Block as TryFrom<&mut [u8]>>::try_from(packet_header)\n                        .expect(\"Packet header length mismatch\");\n                    cipher.encrypt_block(block);\n                }\n                _ => unreachable!(\"{} is not an AES-*-GCM cipher\", method),\n            }\n        }\n        _ => unreachable!(\"{} is not an AEAD 2022 cipher\", method),\n    }\n}\n\nfn decrypt_message(\n    _context: &Context,\n    method: CipherKind,","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks/src/relay/udprelay/aead_2022.rs#L211-L247","documentation":"Panic from `<&mut Block as TryFrom<&mut [u8]>>::try_from(packet_header).expect(\"Packet header length mismatch\")` in UDP `encrypt_message`. The packet header carrying SessionID+PacketID must be exactly one AES block (16 bytes); the conversion fails when the buffer passed as `packet_header` is not exactly 16 bytes.","triggerScenarios":"Calling `encrypt_message` (or `encrypt_client_payload_aead_2022` / `encrypt_server_payload_aead_2022`) with a `packet_header` slice that is not 16 bytes — e.g. a header built with wrong field sizes (SessionID or PacketID of unexpected width) or an offset/split error on the payload buffer.","commonSituations":"Hand-rolled packet builders using 4-byte or 8-byte session/packet ID fields instead of the AEAD-2022 sizes; passing the whole datagram instead of the 16-byte header prefix; protocol fuzzing/custom interop with a non-conformant peer format.","solutions":["Build the packet header as exactly 16 bytes: 8-byte session ID + 8-byte packet ID, and pass only that slice.","Verify the split of the outgoing buffer: header = first 16 bytes, remainder is the AEAD-encrypted message.","Check the serialization of SessionID/PacketID field widths against the shadowsocks-2022 spec.","Add a length check `packet_header.len() == 16` with a clear error before the TryFrom."],"exampleFix":"// before\nlet block = <&mut Block as TryFrom<&mut [u8]>>::try_from(packet_header)\n    .expect(\"Packet header length mismatch\");\n// after\nassert_eq!(packet_header.len(), 16, \"UDP AEAD-2022 header (session_id + packet_id) must be 16 bytes\");\nlet block = <&mut Block as TryFrom<&mut [u8]>>::try_from(packet_header)\n    .expect(\"Packet header length mismatch\");","handlingStrategy":"validation","validationCode":"if packet_header.len() != 16 {\n    return Err(format!(\"UDP AEAD-2022 header must be 16 bytes, got {}\", packet_header.len()));\n}","typeGuard":"fn is_valid_header(buf: &[u8]) -> bool { buf.len() == 16 }","tryCatchPattern":null,"preventionTips":["Serialize session ID (8 bytes) + packet ID (8 bytes) to get a 16-byte header.","Split outgoing datagrams correctly: 16-byte header, then encrypted payload.","Unit-test packet builders against the shadowsocks-2022 layout."],"tags":["rust","panic","udp","packet-header","block-length","aead-2022"],"backgroundTag":"shape-mismatch","analyzedSha":"8eb0f0a65b1d976ab6bed5787327ef86529b0435","analyzedAt":"2026-09-09T12:20:43.168Z","contentChangedAt":"2026-09-09T12:20:43.168Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}