{"record":{"id":"035efb961d887bd7","repo":"shadowsocks/shadowsocks-rust","slug":"eih-key-length-mismatch-035efb","errorCode":null,"errorMessage":"EIH key length mismatch","messagePattern":"EIH key length mismatch","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks/src/relay/udprelay/aead_2022.rs","lineNumber":351,"sourceCode":"                    // Extensible Identity Header\n                    // https://github.com/Shadowsocks-NET/shadowsocks-specs/blob/main/2022-2-shadowsocks-2022-extensible-identity-headers.md\n\n                    let (eih, remain_message) = message.split_at_mut(16);\n                    message = remain_message;\n\n                    let session_id_packet_id = &packet_header[0..16];\n\n                    trace!(\n                        \"server EIH {:?}, session_id_packet_id: {:?}\",\n                        ByteStr::new(eih),\n                        ByteStr::new(session_id_packet_id)\n                    );\n\n                    match method {\n                        CipherKind::AEAD2022_BLAKE3_AES_128_GCM => {\n                            let cipher = Aes128::new_from_slice(key).expect(\"AES-128 init\");\n                            cipher.decrypt_block(\n                                <&mut Block as TryFrom<&mut [u8]>>::try_from(eih).expect(\"EIH key length mismatch\"),\n                            );\n                        }\n                        CipherKind::AEAD2022_BLAKE3_AES_256_GCM => {\n                            let cipher = Aes256::new_from_slice(key).expect(\"AES-256 init\");\n                            cipher.decrypt_block(\n                                <&mut Block as TryFrom<&mut [u8]>>::try_from(eih).expect(\"EIH key length mismatch\"),\n                            )\n                        }\n                        _ => unreachable!(\"{} doesn't support EIH\", method),\n                    }\n\n                    for i in 0..16 {\n                        eih[i] ^= session_id_packet_id[i];\n                    }\n\n                    match user_manager.clone_user_by_hash(eih) {\n                        None => {\n                            error!(\"user with identity {:?} not found\", ByteStr::new(eih));","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks/src/relay/udprelay/aead_2022.rs#L333-L369","documentation":"While decrypting the Extensible Identity Header, the 16-byte EIH slice is converted to an aes::Block via TryFrom<&mut [u8]>; only a slice of exactly 16 bytes converts successfully, otherwise .expect(\"EIH key length mismatch\") panics. This is an internal invariant: EIH blocks are fixed at 16 bytes by the 2022 EIH spec, so failure means the packet buffer layout is wrong.","triggerScenarios":"decrypt_client_payload_aead_2022 / decrypt_server_payload_aead_2022 on a packet where the bytes following the 16-byte header are fewer than 16 (message too short to contain the EIH), so eih = message.split_at_mut(16) cannot yield a full block — the split itself panics — or a shorter slice is fed into try_from(eih).","commonSituations":"Truncated or malformed client UDP packets reaching the EIH branch, a client implementing EIH incorrectly (EIH length not 16), or fuzzing/scanner traffic on an EIH-enabled server.","solutions":["Before decryption, check packet.len() >= method.tag_len() + 16 + 16*eih_count so header plus every EIH block fits; drop short packets.","Verify the client's EIH implementation emits exactly 16 bytes per identity header per the shadowsocks-2022 EIH spec.","Only enable EIH-capable methods with clients that actually support EIH; mismatched implementations produce malformed packets.","Patch the expect to return ProtocolError::DecryptPayloadError so malformed packets are dropped instead of crashing the relay task."],"exampleFix":"// before\ndecrypt_server_payload_aead_2022(ctx, method, key, &mut buf) // buf may be truncated\n// after\nlet eih_count = ident_psks.len();\nif buf.len() < method.tag_len() + 16 + 16 * eih_count {\n    return; // drop malformed packet\n}\ndecrypt_server_payload_aead_2022(ctx, method, key, &mut buf)","handlingStrategy":"validation","validationCode":"// ensure packet fits header + all EIH blocks before decrypt\nlet eih_count = ident_psks.len();\nif packet.len() < method.tag_len() + 16 + 16 * eih_count {\n    return Ok(()); // drop malformed packet\n}","typeGuard":"fn fits_eih(method: CipherKind, packet: &[u8], eih_count: usize) -> bool {\n    packet.len() >= method.tag_len() + 16 + 16 * eih_count\n}","tryCatchPattern":"// drop on decrypt failure instead of panicking:\nmatch decrypt_server_payload_aead_2022(ctx, method, key, &mut buf) {\n    Err(_) => { /* drop malformed EIH packet */ }\n    Ok(_) => { /* proceed */ }\n}","preventionTips":["Size-check datagrams against tag + 16 + 16*EIH-count before decryption.","Only enable EIH with clients verified to emit 16-byte identity headers.","Drop (don't unwrap on) packets from unauthenticated sources.","Fuzz-test the server UDP path with truncated EIH packets."],"tags":["panic","crypto","eih","malformed-packet","shadowsocks"],"backgroundTag":"internal-invariant-violation","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"}