Skip to main content

encryption/
error.rs

1// Copyright (c) 2026 erik <erik@erik.xyz> — https://erik.xyz
2
3//! 统一错误类型:对应 PHP 版的 `EncryptionException` 与
4//! `UnsupportedNationalAlgorithmException`。
5//!
6//! 错误消息与 PHP 版保持同指:解密失败一律是「密钥不对或密文被改」,
7//! 不区分原因,不向前端泄露细节。
8
9use std::fmt;
10
11/// 库统一错误。
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum Error {
14    /// 密钥长度不符合算法要求。
15    InvalidKeyLength {
16        label: &'static str,
17        expected: usize,
18        got: usize,
19    },
20    /// 密文前缀不是本算法 / 本格式版本的标识。
21    InvalidPrefix { label: &'static str },
22    /// 密文长度不足(缺少 IV / MAC / tag)。
23    TooShort { label: &'static str },
24    /// encrypt-then-MAC 的 MAC 校验失败:密钥不对或密文被改,没有第三种解释。
25    MacVerificationFailed { label: &'static str },
26    /// 认证加密(GCM / XChaCha20-Poly1305)解密失败:密钥不对或密文被改。
27    DecryptionFailed { label: &'static str },
28    /// 加密失败(一般不应发生)。
29    EncryptionFailed { label: &'static str },
30    /// 标识未注册到注册表。
31    UnknownIdentifier {
32        kind: &'static str,
33        identifier: String,
34    },
35    /// 主密钥必须是 32 字节。
36    InvalidMasterKey { got: usize },
37    /// 密钥材质非法(十六进制、长度或曲线点校验失败)。
38    InvalidKey { label: &'static str },
39    /// PBKDF2 迭代次数必须为正。
40    InvalidIterations,
41    /// 请求的输出长度非法(为 0 或超过算法上限)。
42    InvalidOutputLength { requested: usize, max: usize },
43    /// 十六进制字符串非法(奇数长度或含非十六进制字符)。
44    InvalidHex,
45    /// 国密算法(SM1 / SM7 / SM9)本库不提供实现。
46    UnsupportedNationalAlgorithm {
47        name: &'static str,
48        hint: &'static str,
49    },
50}
51
52impl fmt::Display for Error {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        match self {
55            Error::InvalidKeyLength {
56                label,
57                expected,
58                got,
59            } => write!(
60                f,
61                "{label} key must be exactly {expected} bytes (got {got})."
62            ),
63            Error::InvalidPrefix { label } => write!(f, "Invalid {label} ciphertext prefix."),
64            Error::TooShort { label } => write!(f, "{label} ciphertext too short."),
65            Error::MacVerificationFailed { label } => write!(f, "{label} MAC verification failed."),
66            Error::DecryptionFailed { label } => write!(f, "{label} decryption failed."),
67            Error::EncryptionFailed { label } => write!(f, "{label} encryption failed."),
68            Error::UnknownIdentifier { kind, identifier } => {
69                write!(f, "Unknown {kind} identifier \"{identifier}\".")
70            }
71            Error::InvalidMasterKey { got } => {
72                write!(f, "Master key must be exactly 32 bytes (got {got}).")
73            }
74            Error::InvalidKey { label } => write!(f, "Invalid {label} key."),
75            Error::InvalidIterations => write!(f, "PBKDF2 iterations must be positive."),
76            Error::InvalidOutputLength { requested, max } => {
77                if *requested == 0 {
78                    write!(f, "Output length must be positive.")
79                } else {
80                    write!(f, "Output length {requested} exceeds the maximum of {max}.")
81                }
82            }
83            Error::InvalidHex => write!(f, "Invalid hex string."),
84            Error::UnsupportedNationalAlgorithm { name, hint } => {
85                write!(f, "{name} is not provided by this library: {hint}")
86            }
87        }
88    }
89}
90
91impl std::error::Error for Error {}
92
93/// 库统一 Result。
94pub type Result<T> = std::result::Result<T, Error>;