OpenNHP/opennhp · error

cipherText too short: need at least

Error message

cipherText too short: need at least %d bytes, got %d

What it means

AESDecrypt expects output of AESEncrypt: a random 16-byte IV prepended to the CBC ciphertext. It requires at least 32 bytes total (IV + at least one encrypted block); anything shorter cannot contain both the IV and data and is rejected before decryption. This is a framing/length guard on the input buffer.

Solutions

  1. Check len(cipherText) >= 32 before calling AESDecrypt and treat shorter inputs as corrupt data.
  2. Confirm the input is full AESEncrypt output (IV prefix + ciphertext), not a truncated or different encoding.
  3. Verify storage/serialization preserves the full byte slice (e.g. BLOB/[]byte columns, not fixed char buffers).
  4. If the data is truly shorter, it was not produced by AESEncrypt — re-encrypt at the source.

Example fix

// before
plain, err := core.AESDecrypt(token, key) // token is 16 bytes
// after
if len(token) < 32 {
    return nil, fmt.Errorf("stored value too short to be AES-CBC blob: %d", len(token))
}
plain, err := core.AESDecrypt(token, key)
Defensive patterns

Strategy: validation

Validate before calling

if len(blob) < 32 {
    return fmt.Errorf("blob too short for IV+ciphertext: %d", len(blob))
}

Try / catch

plain, err := core.AESDecrypt(blob, key)
if err != nil {
    return fmt.Errorf("AES decrypt failed (corrupt/truncated blob): %w", err)
}

Prevention

When it happens

Trigger: Calling AESDecrypt with ciphertext shorter than 32 bytes: empty input, only the 16-byte IV, a truncated buffer, or plaintext/other encoding passed instead of AESEncrypt output.

Common situations: Decrypting a value stored/serialized with its leading bytes lost (DB column truncation, fixed-size buffer copy); passing a raw-key-hash or short token to AESDecrypt by mistake; reading a partially-written file.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/7a2b6ca5011d73be. Report an issue: GitHub.

Appendix: source

Thrown at nhp/core/crypto.go:372

	mode.CryptBlocks(cipherText[aes.BlockSize:], plainText)
	return cipherText, nil
}

// pad adds PKCS#7 padding to data. Uses shared implementation from utils.
func pad(data []byte, blockSize int) []byte {
	return utils.PKCS7Pad(data, blockSize)
}

func AESDecrypt(cipherText []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	// Validate ciphertext length:
	// - Must have at least IV (16 bytes) + one encrypted block (16 bytes)
	// - After IV extraction, remaining must be a multiple of block size
	if len(cipherText) < aes.BlockSize*2 {
		return nil, fmt.Errorf("cipherText too short: need at least %d bytes, got %d", aes.BlockSize*2, len(cipherText))
	}
	if (len(cipherText)-aes.BlockSize)%aes.BlockSize != 0 {
		return nil, fmt.Errorf("cipherText length invalid: must be IV + multiple of block size")
	}
	iv := cipherText[:aes.BlockSize]
	cipherText = cipherText[aes.BlockSize:]

	// Decrypt
	mode := cipher.NewCBCDecrypter(block, iv)
	decrypted := make([]byte, len(cipherText))
	mode.CryptBlocks(decrypted, cipherText)

	// Remove padding
	decrypted = unpad(decrypted, aes.BlockSize)

	return decrypted, nil
}

View on GitHub (pinned to 6e04ca5ff0)