nilaoda/N_m3u8DL-RE · error · ArgumentNullException

Key is null

Error message

Key is null

What it means

CSChaCha20.KeySetup validates the ChaCha20 key before initializing the cipher state. A null key is rejected with ArgumentNullException("Key is null"). This runs during ChaCha20 construction for every decryption using this class.

Solutions

  1. Check key != null before constructing the ChaCha20 cipher.
  2. Ensure the key-extraction/parse step succeeded and produced a byte[].
  3. Fail fast with a clear message upstream if the key is unavailable instead of passing null.
  4. In tests, assert keys are non-null before invoking decryption paths.

Example fix

// before
var cipher = new CSChaCha20(keyBytes, nonce, counter);
// after
if (keyBytes == null) throw new InvalidOperationException("decryption key missing");
var cipher = new CSChaCha20(keyBytes, nonce, counter);
Defensive patterns

Strategy: type-guard

Validate before calling

if (keyBytes == null || keyBytes.Length == 0) throw new InvalidOperationException("no decryption key available");

Type guard

bool HasKey(byte[] k) => k is { Length: 32 };

Try / catch

try { new CSChaCha20(key, nonce, 0); }
catch (ArgumentNullException) { /* key missing — abort decryption */ }

Prevention

When it happens

Trigger: Constructing CSChaCha20 (via the ChaCha20 entry) with key == null, typically when a key extraction step returned null (failed base64/hex decode, missing DRM key) and the null was passed through unchecked.

Common situations: A earlier parse step failed silently and returned null key bytes; config where the key option was omitted but decryption was still requested; tests passing null deliberately.

Related errors


AI-assisted analysis of nilaoda/N_m3u8DL-RE@e113dee70c (2026-09-13). Data as JSON: /api/errors/a1c7dbf9817c4239. Report an issue: GitHub.

Appendix: source

Thrown at src/N_m3u8DL-RE/Crypto/CSChaCha20.cs:125

        }


        // These are the same constants defined in the reference implementation.
        // http://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c
        private static readonly byte[] sigma = Encoding.ASCII.GetBytes("expand 32-byte k");
        private static readonly byte[] tau = Encoding.ASCII.GetBytes("expand 16-byte k");

        /// <summary>
        /// Set up the ChaCha state with the given key. A 32-byte key is required and enforced.
        /// </summary>
        /// <param name="key">
        /// A 32-byte (256-bit) key, treated as a concatenation of eight 32-bit little-endian integers
        /// </param>
        private void KeySetup(byte[] key)
        {
            if (key == null)
            {
                throw new ArgumentNullException("Key is null");
            }

            if (key.Length != allowedKeyLength)
            {
                throw new ArgumentException($"Key length must be {allowedKeyLength}. Actual: {key.Length}");
            }

            state[4] = Util.U8To32Little(key, 0);
            state[5] = Util.U8To32Little(key, 4);
            state[6] = Util.U8To32Little(key, 8);
            state[7] = Util.U8To32Little(key, 12);

            byte[] constants = (key.Length == allowedKeyLength) ? sigma : tau;
            int keyIndex = key.Length - 16;

            state[8] = Util.U8To32Little(key, keyIndex + 0);
            state[9] = Util.U8To32Little(key, keyIndex + 4);
            state[10] = Util.U8To32Little(key, keyIndex + 8);

View on GitHub (pinned to e113dee70c)