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    MissingConfig { key: &'static str },
52}
53
54impl fmt::Display for Error {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        match self {
57            Error::InvalidKeyLength {
58                label,
59                expected,
60                got,
61            } => write!(
62                f,
63                "{label} key must be exactly {expected} bytes (got {got})."
64            ),
65            Error::InvalidPrefix { label } => write!(f, "Invalid {label} ciphertext prefix."),
66            Error::TooShort { label } => write!(f, "{label} ciphertext too short."),
67            Error::MacVerificationFailed { label } => write!(f, "{label} MAC verification failed."),
68            Error::DecryptionFailed { label } => write!(f, "{label} decryption failed."),
69            Error::EncryptionFailed { label } => write!(f, "{label} encryption failed."),
70            Error::UnknownIdentifier { kind, identifier } => {
71                write!(f, "Unknown {kind} identifier \"{identifier}\".")
72            }
73            Error::InvalidMasterKey { got } => {
74                write!(f, "Master key must be exactly 32 bytes (got {got}).")
75            }
76            Error::InvalidKey { label } => write!(f, "Invalid {label} key."),
77            Error::InvalidIterations => write!(f, "PBKDF2 iterations must be positive."),
78            Error::InvalidOutputLength { requested, max } => {
79                if *requested == 0 {
80                    write!(f, "Output length must be positive.")
81                } else {
82                    write!(f, "Output length {requested} exceeds the maximum of {max}.")
83                }
84            }
85            Error::InvalidHex => write!(f, "Invalid hex string."),
86            Error::UnsupportedNationalAlgorithm { name, hint } => {
87                write!(f, "{name} is not provided by this library: {hint}")
88            }
89            Error::MissingConfig { key } => {
90                write!(f, "Required configuration \"{key}\" was not found.")
91            }
92        }
93    }
94}
95
96impl std::error::Error for Error {}
97
98/// 库统一 Result。
99pub type Result<T> = std::result::Result<T, Error>;