siyuan-note/siyuan · error

encrypted envelope too short

Error message

encrypted envelope too short

What it means

Raised by EncryptionNonce when the blob passes the magic check but is shorter than encryptionEnvelopeHeaderSize (7 bytes: 4 magic + spec + algorithm + nonce-length). A blob that is exactly the magic or magic-plus-a-few-bytes hits this. It means the envelope is truncated below the minimum header.

Source

Thrown at kernel/util/kdf.go:107

// Encrypt 用 AES-256-GCM 加密。每次调用生成随机 nonce,因此同一明文多次加密结果不同。
// 返回格式:magic(4B) || spec(1B) || algorithm(1B) || nonceLength(1B) || nonce || ciphertext || GCM tag(16B)。
func Encrypt(key, plaintext []byte) ([]byte, error) {
	return encryptGCM(key, plaintext, nil, "Encrypt")
}

// Decrypt 对应 Encrypt 的解密。密钥错误、格式无效或密文被篡改时返回错误。
func Decrypt(key, ciphertext []byte) ([]byte, error) {
	return decryptGCM(key, ciphertext, nil, "Decrypt")
}

// EncryptionNonce 从 AES-GCM 密文信封中提取 nonce。
func EncryptionNonce(ciphertext []byte) ([]byte, error) {
	if !hasEncryptionMagic(ciphertext) {
		return nil, errors.New("invalid encrypted envelope magic")
	}
	if len(ciphertext) < encryptionEnvelopeHeaderSize {
		return nil, errors.New("encrypted envelope too short")
	}
	if ciphertext[len(encryptionMagic)] != EncryptionSpec {
		return nil, errors.New("unsupported encrypted envelope spec")
	}
	if ciphertext[len(encryptionMagic)+1] != encryptionAlgorithmAES256GCM {
		return nil, errors.New("unsupported encrypted envelope algorithm")
	}
	nonceLength := int(ciphertext[len(encryptionMagic)+2])
	if nonceLength == 0 || len(ciphertext) < encryptionEnvelopeHeaderSize+nonceLength {
		return nil, errors.New("invalid encrypted envelope nonce length")
	}
	return append([]byte(nil), ciphertext[encryptionEnvelopeHeaderSize:encryptionEnvelopeHeaderSize+nonceLength]...), nil
}

// DeriveSubKey 用 HKDF-SHA256 从主 DEK 派生用途隔离的子密钥。
// 同一 (dek, purpose) 多次调用结果一致;不同 purpose 派生出相互独立的子密钥,
// 实现用途分离——.sy/assets/AV 各用独立子密钥,互不可替代,限制单点密钥泄漏的影响面。
func DeriveSubKey(dek []byte, purpose string) []byte {

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Restore the affected blob from a known-good backup.
  2. Validate blob length against the envelope minimum before calling EncryptionNonce.
  3. Investigate the writer: ensure encryptGCM's full output (header+nonce+ct+tag) is persisted atomically.

Example fix

// before
nonce, err := util.EncryptionNonce(blob)

// after: reject obviously truncated envelopes early
if len(blob) < 7 {
    return errors.New("ciphertext blob too short to be an envelope")
}
nonce, err := util.EncryptionNonce(blob)
Defensive patterns

Strategy: validation

Validate before calling

if len(blob) < 7 { // encryptionEnvelopeHeaderSize
    return errors.New("ciphertext too short to contain an envelope header")
}

Prevention

When it happens

Trigger: EncryptionNonce receives a buffer that starts with 'SENC' but has fewer than 7 total bytes. Occurs with truncated/corrupted ciphertext blobs read from conf or asset files.

Common situations: A write was interrupted leaving a partial envelope; storage corruption truncated the blob; a bug elsewhere produced a too-short buffer; reading past end-of-file in a chunked asset.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/336ce7e953f0e6f7. Report an issue: GitHub.