shadowsocks/shadowsocks-rust · error

ipsk length mismatch

Error message

ipsk length mismatch

What it means

Panic from `<&Block as TryFrom<&[u8]>>::try_from(ipsk_plain_text).expect("ipsk length mismatch")` in `make_eih`. The input is `blake3::hash(ipsk).as_bytes()[0..16]`, so it only fails if the sliced hash is not 16 bytes — which happens when the slice bounds are wrong or, practically, when the code path is fed an unexpected buffer; the slice here is hard-coded to 16 bytes, so a panic indicates a corrupted/short ipsk source or a modified slice length.

Source

Thrown at crates/shadowsocks/src/relay/tcprelay/aead_2022.rs:570

    ) -> Self {
        // nonce should be sent with the first packet
        let mut buffer = BytesMut::with_capacity(nonce.len() + identity_keys.len() * 16);
        buffer.put(nonce);

        // Extensible Identity Headers
        // https://github.com/Shadowsocks-NET/shadowsocks-specs/blob/main/2022-2-shadowsocks-2022-extensible-identity-headers.md
        #[inline]
        fn make_eih(method: CipherKind, sub_key: &[u8], ipsk: &[u8], buffer: &mut BytesMut) {
            let ipsk_hash = blake3::hash(ipsk);
            let ipsk_plain_text = &ipsk_hash.as_bytes()[0..16];

            match method {
                CipherKind::AEAD2022_BLAKE3_AES_128_GCM => {
                    let enc_key = &sub_key[0..16];
                    let cipher = Aes128::new_from_slice(enc_key).expect("AES-128");

                    let ipsk_plain_text =
                        <&Block as TryFrom<&[u8]>>::try_from(ipsk_plain_text).expect("ipsk length mismatch");
                    let mut block = Block::from([0u8; 16]);
                    cipher.encrypt_block_b2b(ipsk_plain_text, &mut block);

                    trace!(
                        "client EIH {:?}, hash: {:?}",
                        ByteStr::new(block.as_slice()),
                        ByteStr::new(ipsk_plain_text)
                    );
                    buffer.put(block.as_slice());
                }
                CipherKind::AEAD2022_BLAKE3_AES_256_GCM => {
                    let enc_key = &sub_key[0..32];
                    let cipher = Aes256::new_from_slice(enc_key).expect("AES-256");

                    let ipsk_plain_text =
                        <&Block as TryFrom<&[u8]>>::try_from(ipsk_plain_text).expect("ipsk length mismatch");
                    let mut block = Block::from([0u8; 16]);
                    cipher.encrypt_block_b2b(ipsk_plain_text, &mut block);

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Use the standard library code path: hash the ipsk with blake3 and slice `[0..16]` exactly as upstream does.
  2. Verify the ipsk bytes passed to `with_identity` are the full pre-shared key (raw 16/32 bytes), not a truncated or base64-string slice.
  3. Remove local patches that change the slice bounds of `ipsk_plain_text`.
  4. If writing your own block conversion, check `ipsk_plain_text.len() == 16` before `try_from` and return an error instead of panicking.

Example fix

// before
let ipsk_plain_text = <&Block as TryFrom<&[u8]>>::try_from(ipsk_plain_text).expect("ipsk length mismatch");
// after
let ipsk_plain_text = <&Block as TryFrom<&[u8]>>::try_from(ipsk_plain_text)
    .expect("ipsk plain text must be 16 bytes (blake3 hash slice)");
Defensive patterns

Strategy: validation

Validate before calling

let hash = blake3::hash(ipsk).as_bytes()[0..16].to_vec();
if hash.len() != 16 { return Err("ipsk plain text must be 16 bytes".into()); }

Type guard

fn is_block_sized(b: &[u8]) -> bool { b.len() == 16 }

Prevention

When it happens

Trigger: Calling `make_eih` (via `with_identity`) where the blake3 hash slice used as `ipsk_plain_text` is not exactly 16 bytes — practically only when the slice expression was changed, or `ipsk` handling produced a non-standard buffer in a patched/forked build.

Common situations: Custom forks or vendored patches altering the `[0..16]` slice; misuse of a lower-level helper expecting a 16-byte block but handed the raw ipsk; upstream/downstream version mismatch in the EIH construction API.

Related errors


AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09). Data as JSON: /api/errors/de489f276665c87a. Report an issue: GitHub.