nilaoda/N_m3u8DL-RE · error · ArgumentNullException

Nonce is null

Error message

Nonce is null

What it means

IvSetup validates the ChaCha20 nonce. A null nonce is rejected with ArgumentNullException("Nonce is null"), and because some cipher state may already be set, the instance is Dispose()d before throwing to avoid a half-initialized cipher.

Solutions

  1. Check nonce != null before constructing the cipher.
  2. Default to an all-zero 12-byte nonce when the stream provides none, if protocol-appropriate.
  3. Fix the IV extraction code to return an empty/zero buffer rather than null.
  4. Since state is disposed on failure, always construct a fresh cipher instance after fixing the input.

Example fix

// before
var cipher = new CSChaCha20(key, nonceBytes, 0); // nonceBytes null
// after
nonceBytes ??= new byte[12];
var cipher = new CSChaCha20(key, nonceBytes, 0);
Defensive patterns

Strategy: type-guard

Validate before calling

if (nonceBytes == null) nonceBytes = new byte[12]; // or abort

Type guard

bool HasNonce(byte[] n) => n is { Length: 12 };

Try / catch

try { cipher = new CSChaCha20(key, nonce, 0); }
catch (ArgumentNullException) { /* nonce missing — supply default or abort */ }

Prevention

When it happens

Trigger: Calling the ChaCha20 constructor/entry with nonce == null — e.g. the manifest omitted the IV, or the code path that derives the nonce returned null.

Common situations: Streams without an explicit IV where the caller forgot to supply the default/zero nonce; failed Base64 decode of the IV attribute yielding null.

Related errors


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

Appendix: source

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

            state[3] = Util.U8To32Little(constants, 12);
        }

        /// <summary>
        /// Set up the ChaCha state with the given nonce (aka Initialization Vector or IV) and block counter. A 12-byte nonce and a 4-byte counter are required.
        /// </summary>
        /// <param name="nonce">
        /// A 12-byte (96-bit) nonce, treated as a concatenation of three 32-bit little-endian integers
        /// </param>
        /// <param name="counter">
        /// A 4-byte (32-bit) block counter, treated as a 32-bit little-endian integer
        /// </param>
        private void IvSetup(byte[] nonce, uint counter)
        {
            if (nonce == null)
            {
                // There has already been some state set up. Clear it before exiting.
                Dispose();
                throw new ArgumentNullException("Nonce is null");
            }

            if (nonce.Length != allowedNonceLength)
            {
                // There has already been some state set up. Clear it before exiting.
                Dispose();
                throw new ArgumentException($"Nonce length must be {allowedNonceLength}. Actual: {nonce.Length}");
            }

            state[12] = counter;
            state[13] = Util.U8To32Little(nonce, 0);
            state[14] = Util.U8To32Little(nonce, 4);
            state[15] = Util.U8To32Little(nonce, 8);
        }


        #region Encryption methods

View on GitHub (pinned to e113dee70c)