nilaoda/N_m3u8DL-RE · error · Exception

Key must be 12 or 8 bytes!

Error message

Key must be 12 or 8 bytes!

What it means

DecryptPer1024Bytes decrypts a buffer with ChaCha20 in 1024-byte blocks and validates key/nonce sizes up front. It throws when the nonce is neither 12 bytes (RFC 7539) nor 8 bytes (original DJB variant). Note the message misleadingly says 'Key' but the check is on the nonce.

Solutions

  1. Ensure the nonce bytes are exactly 12 bytes for IETF ChaCha20 or 8 bytes for the original variant; pad an 8-byte nonce yourself or let the method prepend {0,0,0,0}
  2. Verify how you decoded the nonce: hex 'DecodeData' vs base64 'Convert.FromBase64String' — decoding with the wrong scheme changes the length
  3. Log nonceBytes.Length before the call to confirm the actual size
  4. If the key (not nonce) is the wrong size, fix it to exactly 32 bytes to avoid the sibling 'Key must be 32 bytes!' exception

Example fix

// before
var nonce = Encoding.UTF8.GetBytes(keyInfo.IV); // wrong: variable length
var dec = ChaCha20Util.DecryptPer1024Bytes(seg, key, nonce);
// after
var nonce = GetBytesFromHex(keyInfo.IV.TrimStart("0x"));
if (nonce.Length != 12 && nonce.Length != 8) nonce = nonce.Take(12).ToArray();
var dec = ChaCha20Util.DecryptPer1024Bytes(seg, key, nonce);
Defensive patterns

Strategy: validation

Validate before calling

if (keyBytes.Length != 32) throw new ArgumentException("key must be 32 bytes");
if (nonceBytes.Length != 12 && nonceBytes.Length != 8) throw new ArgumentException($"nonce must be 12 or 8 bytes, got {nonceBytes.Length}");

Type guard

static bool IsValidChaCha20Params(byte[] key, byte[] nonce) => key.Length == 32 && (nonce.Length == 12 || nonce.Length == 8);

Prevention

When it happens

Trigger: Passing a nonce of any length other than 12 or 8 (e.g. a 16-byte IV, a hex string decoded to an odd length, or a truncated/empty byte array) to DecryptPer1024Bytes while decrypting AES-128 SAMPLE-AES-free ChaCha20-encrypted HLS segments.

Common situations: Hardcoding a nonce parsed incorrectly from an EXT-X-KEY attribute; base64-decoding a nonce that was actually hex; passing a UTF-8-encoded nonce string instead of raw bytes.

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 nilaoda/N_m3u8DL-RE@e113dee70c (2026-09-13). Data as JSON: /api/errors/e57d7f555a1b42e4. Report an issue: GitHub.

Appendix: source

Thrown at src/N_m3u8DL-RE/Crypto/ChaCha20Util.cs:12

using CSChaCha20;

namespace N_m3u8DL_RE.Crypto;

internal static class ChaCha20Util
{
    public static byte[] DecryptPer1024Bytes(byte[] encryptedBuff, byte[] keyBytes, byte[] nonceBytes)
    {
        if (keyBytes.Length != 32)
            throw new Exception("Key must be 32 bytes!");
        if (nonceBytes.Length != 12 && nonceBytes.Length != 8)
            throw new Exception("Key must be 12 or 8 bytes!");
        if (nonceBytes.Length == 8)
            nonceBytes = (new byte[4] { 0, 0, 0, 0 }).Concat(nonceBytes).ToArray();

        var decStream = new MemoryStream();
        using BinaryReader reader = new BinaryReader(new MemoryStream(encryptedBuff));
        using (BinaryWriter writer = new BinaryWriter(decStream))
            while (true)
            {
                var buffer = reader.ReadBytes(1024);
                byte[] dec = new byte[buffer.Length];
                if (buffer.Length > 0)
                {
                    ChaCha20 forDecrypting = new ChaCha20(keyBytes, nonceBytes, 0);
                    forDecrypting.DecryptBytes(dec, buffer);
                    writer.Write(dec, 0, dec.Length);
                }
                else
                {

View on GitHub (pinned to e113dee70c)