{"record":{"id":"db2a79147fa531d2","repo":"shadowsocks/shadowsocks-rust","slug":"eih-key-length-mismatch","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/tcprelay/aead_2022.rs","lineNumber":319,"sourceCode":"            match self.user_manager {\n                Some(ref user_manager) => {\n                    // Assume we have at least 1 EIH\n                    if header_chunk.len() < 16 {\n                        error!(\"expecting EIH, but header chunk len: {}\", header_chunk.len());\n                        return Err(ProtocolError::MissingExtendedIdentityHeader).into();\n                    }\n\n                    let (eih, remain_header_chunk) = header_chunk.split_at_mut(16);\n                    header_chunk = remain_header_chunk;\n\n                    let key_material = [key, salt].concat();\n                    let identity_sub_key = blake3::derive_key(AEAD2022_EIH_SUBKEY_CONTEXT, &key_material);\n                    let mut user_hash = Block::from([0u8; 16]);\n                    match self.method {\n                        CipherKind::AEAD2022_BLAKE3_AES_128_GCM => {\n                            let cipher = Aes128::new_from_slice(&identity_sub_key[0..16]).expect(\"AES-128\");\n                            cipher.decrypt_block_b2b(\n                                <&Block as TryFrom<&[u8]>>::try_from(eih).expect(\"EIH key length mismatch\"),\n                                &mut user_hash,\n                            );\n                        }\n                        CipherKind::AEAD2022_BLAKE3_AES_256_GCM => {\n                            let cipher = Aes256::new_from_slice(&identity_sub_key[0..32]).expect(\"AES-256\");\n                            cipher.decrypt_block_b2b(\n                                <&Block as TryFrom<&[u8]>>::try_from(eih).expect(\"EIH key length mismatch\"),\n                                &mut user_hash,\n                            );\n                        }\n                        _ => unreachable!(\"{} doesn't support EIH\", self.method),\n                    }\n\n                    let user_hash = user_hash.as_slice();\n                    trace!(\n                        \"server EIH {:?}, hash: {:?}\",\n                        ByteStr::new(eih),\n                        ByteStr::new(user_hash)","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks/src/relay/tcprelay/aead_2022.rs#L301-L337","documentation":"The EIH block passed to decrypt_block_b2b must be exactly one 16-byte AES Block; the TryFrom<&[u8]> conversion is unwrapped with expect(\"EIH key length mismatch\"). It panics when the eih slice is not exactly 16 bytes, meaning the received EIH header length did not match the expected identity-hash block size for the configured method.","triggerScenarios":"Server receives an AEAD-2022 connection whose extended identity header chunk is not 16 bytes (truncated packet, attacker-supplied malformed header, or a method/EIH-count mismatch in header parsing) with AES-128 configured.","commonSituations":"Malformed or hostile client traffic against an AEAD-2022 server; version mismatch between client and server EIH formats; proxy chaining where an intermediate strips/adds EIH bytes.","solutions":["Upgrade shadowsocks-rust: newer versions validate EIH length and return a ProtocolError instead of panicking","Ensure client and server use matching versions and the same AEAD2022 method","Validate the EIH length before decrypt_block_b2b and reject short/long headers with an io/protocol error"],"exampleFix":"// before\n<&Block as TryFrom<&[u8]>>::try_from(eih).expect(\"EIH key length mismatch\"),\n// after\nlet block = <&Block as TryFrom<&[u8]>>::try_from(eih)\n    .map_err(|_| ProtocolError::EihLengthMismatch)?;","handlingStrategy":"validation","validationCode":"if eih.len() != 16 { return Err(ProtocolError::EihLengthMismatch.into()); }","typeGuard":"fn is_valid_eih(eih: &[u8]) -> bool { eih.len() == 16 }","tryCatchPattern":"let block = <&Block as TryFrom<&[u8]>>::try_from(eih)\n    .map_err(|_| ProtocolError::EihLengthMismatch)?;","preventionTips":["Keep client and server AEAD2022 versions/methods aligned","Deploy a build where malformed EIH yields a protocol error, not a panic","Drop truncated packets at the framing layer before EIH processing"],"tags":["rust","aead-2022","panic","malformed-packet","cryptography"],"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"}