peass-ng/PEASS-ng · error · System.ArgumentException

Invalid encryption version prefix.

Error message

Invalid encryption version prefix.

What it means

DecryptWithAESGCM expects Google Chrome app-bound encrypted tokens to start with a known ASCII version prefix (e.g. 'v10'/'v20'). If the ciphertext is shorter than the prefix or does not begin with it, decryption cannot proceed and ArgumentException is thrown. This prevents attempting AES-GCM decryption on data in an unexpected format.

Source

Thrown at winPEAS/winPEASexe/winPEAS/Info/CloudInfo/GWorkspaceInfo.cs:263

                Beaprint.PrintException("Error extracting refresh tokens (If Chrome is running the DB is probably locked but you could dump Chrome's procs and search it there or go around this lock): " + ex.Message);
                return refreshTokens.ToArray();
            }
        }
        public static string DecryptWithAESGCM(byte[] ciphertext, byte[] key)
        {
            // Constants
            int nonceLength = 12; // GCM standard nonce length
            int macLength = 16;   // GCM authentication mac length
            string versionPrefix = "v10"; // Matching kEncryptionVersionPrefix

            // Convert prefix to byte array
            byte[] versionPrefixBytes = Encoding.ASCII.GetBytes(versionPrefix);

            // Check the prefix
            if (ciphertext.Length < versionPrefixBytes.Length ||
                !IsPrefixMatch(ciphertext, versionPrefixBytes))
            {
                throw new ArgumentException("Invalid encryption version prefix.");
            }

            // Extract the nonce from the ciphertext (after the prefix)
            byte[] nonce = new byte[nonceLength];
            Array.Copy(ciphertext, versionPrefixBytes.Length, nonce, 0, nonceLength);

            // Extract the actual encrypted data (after the prefix and nonce)
            int encryptedDataStartIndex = versionPrefixBytes.Length + nonceLength;
            byte[] encryptedData = new byte[ciphertext.Length - encryptedDataStartIndex];
            Array.Copy(ciphertext, encryptedDataStartIndex, encryptedData, 0, encryptedData.Length);

            // Split the mac and actual ciphertext
            byte[] mac = new byte[macLength];
            Array.Copy(encryptedData, encryptedData.Length - macLength, mac, 0, macLength);

            byte[] actualCiphertext = new byte[encryptedData.Length - macLength];
            Array.Copy(encryptedData, 0, actualCiphertext, 0, actualCiphertext.Length);

View on GitHub (pinned to 53fb989abc)

Solutions

  1. Inspect the first bytes of the ciphertext (hex dump) and confirm they match the expected versionPrefix
  2. Re-read the correct source: the app-bound encrypted key from the right registry key/value for the installed browser version
  3. Update the versionPrefix constant to match the browser version's actual format (e.g. v20 for newer Chrome app-bound encryption)
  4. Add a length/format check and log a descriptive error distinguishing 'no prefix' from 'corrupt data'

Example fix

// before
byte[] plain = DecryptWithAESGCM(blob, key, "v10");
// after
if (blob == null || blob.Length < 3 || Encoding.ASCII.GetString(blob, 0, 3) != "v20")
    throw new InvalidOperationException("Token blob does not carry v20 app-bound prefix; check browser version/source.");
byte[] plain = DecryptWithAESGCM(blob, key, "v20");
Defensive patterns

Strategy: validation

Validate before calling

static bool HasVersionPrefix(byte[] ct, string prefix)
{
    var p = Encoding.ASCII.GetBytes(prefix);
    return ct != null && ct.Length >= p.Length &&
           ct.AsSpan(0, p.Length).SequenceEqual(p);
}

Try / catch

try { return DecryptWithAESGCM(ct, key, prefix); }
catch (ArgumentException) { log.Error("Token blob missing expected version prefix; wrong source or browser format changed."); return null; }

Prevention

When it happens

Trigger: Calling decryptedToken with ciphertext whose first bytes are not the expected version prefix: the value was read from the wrong registry value/file, the prefix constant was changed, or the byte array was sliced incorrectly (e.g. off-by-one or including a BOM).

Common situations: Chrome changed its app-bound encryption format in newer versions; copying the wrong registry blob (DPAPI-encrypted instead of app-bound); reading the value with wrong offsets so the prefix is missing; handling Firefox or non-Chromium data with this routine.

Related errors


AI-assisted analysis of peass-ng/PEASS-ng@53fb989abc (2026-09-02). Data as JSON: /api/errors/b9d0df28b7a6bdc2. Report an issue: GitHub.