peass-ng/PEASS-ng · error · ArgumentException

Threefish tweak must be bytes

Error message

Threefish tweak must be  bytes

What it means

An argument validation in ThreefishEngine.Init: when a tweak byte array is supplied its length must equal TWEAK_SIZE_BYTES (16, i.e. two 64-bit words); any other length is rejected because the tweak schedule is built from exactly two words. The message interpolates the required size, so it reads with a missing number only when the constant is elided in formatting.

Source

Thrown at winPEAS/winPEASexe/winPEAS/3rdParty/BouncyCastle/crypto/engines/ThreefishEngine.cs:198

			if (keyBytes != null)
			{
				if (keyBytes.Length != this.blocksizeBytes)
				{
					throw new ArgumentException("Threefish key must be same size as block (" + blocksizeBytes
												+ " bytes)");
				}
				keyWords = new ulong[blocksizeWords];
				for (int i = 0; i < keyWords.Length; i++)
				{
					keyWords[i] = BytesToWord(keyBytes, i * 8);
				}
			}
			if (tweakBytes != null)
			{
				if (tweakBytes.Length != TWEAK_SIZE_BYTES)
				{
					throw new ArgumentException("Threefish tweak must be " + TWEAK_SIZE_BYTES + " bytes");
				}
				tweakWords = new ulong[] { BytesToWord(tweakBytes, 0), BytesToWord(tweakBytes, 8) };
			}
			Init(forEncryption, keyWords, tweakWords);
		}

		/// <summary>
		/// Initialise the engine, specifying the key and tweak directly.
		/// </summary>
		/// <param name="forEncryption">the cipher mode.</param>
		/// <param name="key">the words of the key, or <code>null</code> to use the current key.</param>
		/// <param name="tweak">the 2 word (128 bit) tweak, or <code>null</code> to use the current tweak.</param>
		internal void Init(bool forEncryption, ulong[] key, ulong[] tweak)
		{
			this.forEncryption = forEncryption;
			if (key != null)
			{
				SetKey(key);

View on GitHub (pinned to 53fb989abc)

Solutions

  1. Supply exactly 16 bytes of tweak material
  2. If the tweak source is longer/shorter, derive 16 bytes via SHA-256 truncation or a dedicated KDF
  3. Construct tweak as two 8-byte little-endian words when building it manually

Example fix

// before
byte[] tweak = new byte[8];
engine.Init(true, new ParametersWithTweak(new KeyParameter(key), tweak));
// after
byte[] tweak = new byte[16];
engine.Init(true, new ParametersWithTweak(new KeyParameter(key), tweak));
Defensive patterns

Strategy: validation

Validate before calling

const int TweakSizeBytes = 16;
if (tweak == null || tweak.Length != TweakSizeBytes)
    throw new ArgumentException("Threefish tweak must be exactly 16 bytes");
engine.Init(forEncryption, new ParametersWithTweak(new KeyParameter(key), tweak));

Type guard

bool IsValidThreefishTweak(byte[] tweak) => tweak != null && tweak.Length == 16;

Try / catch

try { engine.Init(forEnc, new ParametersWithTweak(keyParam, tweak)); }
catch (ArgumentException) { /* normalize tweak to 16 bytes and retry once */ }

Prevention

When it happens

Trigger: Calling Init with ParametersWithTweak whose tweak array is not 16 bytes (e.g. 8-byte counter, 32-byte tweak, null-padded value).

Common situations: Feeding an AES-GCM-style 12-byte IV as a Threefish tweak; hashing a tweak to 32 bytes instead of 16; forgetting that Threefish's tweak is 128 bits.

Related errors


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