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    SignFailed { label: &'static str },
32    /// 验签失败:签名不对或消息被改,没有第三种解释。
33    VerificationFailed { label: &'static str },
34    /// 标识未注册到注册表。
35    UnknownIdentifier {
36        kind: &'static str,
37        identifier: String,
38    },
39    /// 主密钥必须是 32 字节。
40    InvalidMasterKey { got: usize },
41    /// 密钥材质非法(十六进制、长度或曲线点校验失败)。
42    InvalidKey { label: &'static str },
43    /// PBKDF2 迭代次数必须为正。
44    InvalidIterations,
45    /// KDF 的成本参数非法(如 Argon2 的 m / t / p、scrypt 的 log_n / r / p)。
46    InvalidKdfParams { label: &'static str },
47    /// 请求的输出长度非法(为 0 或超过算法上限)。
48    InvalidOutputLength { requested: usize, max: usize },
49    /// 十六进制字符串非法(奇数长度或含非十六进制字符)。
50    InvalidHex,
51    /// 国密算法(SM1 / SM7 / SM9)本库不提供实现。
52    UnsupportedNationalAlgorithm {
53        name: &'static str,
54        hint: &'static str,
55    },
56    /// 必需配置缺失(如环境变量未设置)。
57    MissingConfig { key: &'static str },
58}
59
60impl fmt::Display for Error {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        match self {
63            Error::InvalidKeyLength {
64                label,
65                expected,
66                got,
67            } => write!(f, "{label} length must be {expected} (got {got})."),
68            Error::InvalidPrefix { label } => write!(f, "Invalid {label} ciphertext prefix."),
69            Error::TooShort { label } => write!(f, "{label} ciphertext too short."),
70            Error::MacVerificationFailed { label } => write!(f, "{label} MAC verification failed."),
71            Error::DecryptionFailed { label } => write!(f, "{label} decryption failed."),
72            Error::EncryptionFailed { label } => write!(f, "{label} encryption failed."),
73            Error::SignFailed { label } => write!(f, "{label} signing failed."),
74            Error::VerificationFailed { label } => {
75                write!(f, "{label} signature verification failed.")
76            }
77            Error::UnknownIdentifier { kind, identifier } => {
78                write!(f, "Unknown {kind} identifier \"{identifier}\".")
79            }
80            Error::InvalidMasterKey { got } => {
81                write!(f, "Master key must be exactly 32 bytes (got {got}).")
82            }
83            Error::InvalidKey { label } => write!(f, "Invalid {label} key."),
84            Error::InvalidIterations => write!(f, "PBKDF2 iterations must be positive."),
85            Error::InvalidKdfParams { label } => write!(f, "Invalid {label} parameters."),
86            Error::InvalidOutputLength { requested, max } => {
87                if *requested == 0 {
88                    write!(f, "Output length must be positive.")
89                } else {
90                    write!(f, "Output length {requested} exceeds the maximum of {max}.")
91                }
92            }
93            Error::InvalidHex => write!(f, "Invalid hex string."),
94            Error::UnsupportedNationalAlgorithm { name, hint } => {
95                write!(f, "{name} is not provided by this library: {hint}")
96            }
97            Error::MissingConfig { key } => {
98                write!(f, "Required configuration \"{key}\" was not found.")
99            }
100        }
101    }
102}
103
104impl std::error::Error for Error {}
105
106/// 库统一 Result。
107pub type Result<T> = std::result::Result<T, Error>;