shadowsocks/shadowsocks-rust · error

AES-128 init

Error message

AES-128 init

What it means

Panic from `Aes128::new_from_slice(ipsk).expect("AES-128 init")` in the UDP AEAD-2022 `encrypt_message`. The `[SessionID + PacketID]` header is ECB-encrypted with the identity PSK; `Aes128::new_from_slice` requires exactly 16 bytes, so the panic means the ipsk supplied is not 16 bytes long for `AEAD2022_BLAKE3_AES_128_GCM`.

Source

Thrown at crates/shadowsocks/src/relay/udprelay/aead_2022.rs:227

            // AES-*-GCM uses derived key, and part of the packet header as nonce

            let cipher = get_cipher(method, key, session_id);

            // Encrypt the rest of the packet with AEAD cipher (AES-*-GCM)
            let (packet_header, mut message) = packet.split_at_mut(16);
            let nonce = &packet_header[4..16];

            if eih_len > 0 {
                message = &mut message[eih_len..];
            }

            cipher.encrypt_packet(nonce, message);

            // [SessionID + PacketID] is encrypted with AES-ECB with PSK
            // No padding is required because these 2 fields are 128-bits, which is exactly the same as AES's block size
            match method {
                CipherKind::AEAD2022_BLAKE3_AES_128_GCM => {
                    let cipher = Aes128::new_from_slice(ipsk).expect("AES-128 init");
                    let block = <&mut Block as TryFrom<&mut [u8]>>::try_from(packet_header)
                        .expect("Packet header length mismatch");
                    cipher.encrypt_block(block);
                }
                CipherKind::AEAD2022_BLAKE3_AES_256_GCM => {
                    let cipher = Aes256::new_from_slice(ipsk).expect("AES-256 init");
                    let block = <&mut Block as TryFrom<&mut [u8]>>::try_from(packet_header)
                        .expect("Packet header length mismatch");
                    cipher.encrypt_block(block);
                }
                _ => unreachable!("{} is not an AES-*-GCM cipher", method),
            }
        }
        _ => unreachable!("{} is not an AEAD 2022 cipher", method),
    }
}

fn decrypt_message(

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Provide an identity PSK of exactly 16 raw bytes when the method is `AEAD2022_BLAKE3_AES_128_GCM` (base64 of 16 bytes = 24 chars).
  2. Match the cipher kind to the key: use the 256-bit branch (`AES-256 init` path) with 32-byte keys instead of forcing a 128-bit method.
  3. Decode base64 keys and assert length before calling the payload encryption API.
  4. Align identity-key length expectations between client and server configs.

Example fix

// before
let cipher = Aes128::new_from_slice(ipsk).expect("AES-128 init");
// after
assert_eq!(ipsk.len(), 16, "AEAD2022_AES_128_GCM identity PSK must be 16 bytes, got {}", ipsk.len());
let cipher = Aes128::new_from_slice(ipsk).expect("AES-128 init");
Defensive patterns

Strategy: validation

Validate before calling

// before UDP payload encryption
if matches!(method, CipherKind::AEAD2022_BLAKE3_AES_128_GCM) && ipsk.len() != 16 {
    return Err(format!("identity PSK must be 16 bytes for AES-128-GCM, got {}", ipsk.len()));
}

Type guard

fn is_valid_ipsk(kind: CipherKind, ipsk: &[u8]) -> bool {
    match kind {
        CipherKind::AEAD2022_BLAKE3_AES_128_GCM => ipsk.len() == 16,
        CipherKind::AEAD2022_BLAKE3_AES_256_GCM => ipsk.len() == 32,
        _ => false,
    }
}

Prevention

When it happens

Trigger: Calling `encrypt_message` (directly or via `encrypt_client_payload_aead_2022` / `encrypt_server_payload_aead_2022`) with `method = AEAD2022_BLAKE3_AES_128_GCM` and an `ipsk` that is not exactly 16 bytes — e.g. a 32-byte identity key or a raw password.

Common situations: Using the main PSK (32 bytes for AES-256) as the identity PSK while the method is 128-bit; misreading the spec and passing a password instead of the raw 16-byte additional PSK; configs where client and server identity-key lengths differ.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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