siyuan-note/siyuan · error
unsupported encrypted envelope algorithm
Error message
unsupported encrypted envelope algorithm
What it means
EncryptionNonce validates the envelope's algorithm byte (offset 5). Only AES-256-GCM (0x01) is implemented; any other algorithm identifier means the envelope was written with an unsupported cipher and cannot be processed.
Solutions
- Use the kernel version that wrote the envelope (matching algorithm support) to decrypt it
- Restore the blob from backup if the header is corrupted (compare spec byte at offset 4 — if that is also wrong it is likely corruption)
- Do not attempt to force-decrypt; GCM authentication would fail anyway with a wrong-key/wrong-algorithm combination
Defensive patterns
Strategy: validation
Validate before calling
if len(data) >= 6 && data[5] != 0x01 {
return fmt.Errorf("envelope algorithm %d unsupported (AES-256-GCM=1 expected)", data[5])
} Type guard
func isAESGCMEnvelope(b []byte) bool {
return len(b) >= 6 && string(b[:4]) == "SENC" && b[4] == 0x01 && b[5] == 0x01
} Try / catch
nonce, err := util.EncryptionNonce(ciphertext)
if err != nil {
return fmt.Errorf("unsupported envelope algorithm: %w", err)
} Prevention
- Only read envelopes produced by the same kernel build family
- Restore from backup if header bytes look corrupted (spec and algorithm both unexpected)
- Never edit envelope header bytes by hand
When it happens
Trigger: Calling EncryptionNonce on an envelope whose byte at offset 5 is not 0x01 — data written by a build supporting a different algorithm (e.g. ChaCha20-Poly1305 marker) or corrupted/tampered header bytes.
Common situations: Reading encrypted data produced by a different or newer kernel build, header corruption during storage/sync, or bit-flip tampering of the stored blob.
Related errors
- encrypted envelope too short
- invalid encrypted envelope magic
- Decryption failed: incorrect key or corrupted data
- invalid encrypted envelope nonce length
- unsupported encrypted envelope spec
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/85b6b0831e70f33c.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/util/kdf.go:113
// 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 {
// HKDF info 用 purpose 字节;salt 为 nil(DEK 本身已是高熵随机密钥,无需额外 salt)
r := hkdf.New(sha256.New, dek, nil, []byte(purpose))
out := make([]byte, 32) // AES-256
if _, err := io.ReadFull(r, out); err != nil {
// hkdf.Read 不应出错(除非 dek 为空);防御性 panic 避免静默返回弱密钥
panic("hkdf derive failed: " + err.Error())View on GitHub (pinned to 9f775e8a12)