encryption-rust 1.3.0

可插拔密码学组件库的 Rust 实现:在统一契约下提供对称加密、非对称加密、哈希、密钥派生(HKDF / PBKDF2 / Argon2 / scrypt)、签名(SM2 / ECDSA / Ed25519)、密钥协商(ECDH / X25519)与后量子密钥封装(ML-KEM),包含 AES/Sodium 与国密 SM2/SM3/SM4/ZUC 等实现
Documentation
// Copyright (c) 2026 erik <erik@erik.xyz> — https://erik.xyz

//! 统一错误类型:对应 PHP 版的 `EncryptionException` 与
//! `UnsupportedNationalAlgorithmException`。
//!
//! 错误消息与 PHP 版保持同指:解密失败一律是「密钥不对或密文被改」,
//! 不区分原因,不向前端泄露细节。

use std::fmt;

/// 库统一错误。
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
    /// 长度不符合算法要求(密钥、盐、密文等;单位由调用点语境决定,如字节或位)。
    InvalidKeyLength {
        label: &'static str,
        expected: usize,
        got: usize,
    },
    /// 密文前缀不是本算法 / 本格式版本的标识。
    InvalidPrefix { label: &'static str },
    /// 密文长度不足(缺少 IV / MAC / tag)。
    TooShort { label: &'static str },
    /// encrypt-then-MAC 的 MAC 校验失败:密钥不对或密文被改,没有第三种解释。
    MacVerificationFailed { label: &'static str },
    /// 认证加密(GCM / XChaCha20-Poly1305)解密失败:密钥不对或密文被改。
    DecryptionFailed { label: &'static str },
    /// 加密失败(一般不应发生)。
    EncryptionFailed { label: &'static str },
    /// 签名失败(一般不应发生)。
    SignFailed { label: &'static str },
    /// 验签失败:签名不对或消息被改,没有第三种解释。
    VerificationFailed { label: &'static str },
    /// 标识未注册到注册表。
    UnknownIdentifier {
        kind: &'static str,
        identifier: String,
    },
    /// 主密钥必须是 32 字节。
    InvalidMasterKey { got: usize },
    /// 密钥材质非法(十六进制、长度或曲线点校验失败)。
    InvalidKey { label: &'static str },
    /// PBKDF2 迭代次数必须为正。
    InvalidIterations,
    /// KDF 的成本参数非法(如 Argon2 的 m / t / p、scrypt 的 log_n / r / p)。
    InvalidKdfParams { label: &'static str },
    /// 请求的输出长度非法(为 0 或超过算法上限)。
    InvalidOutputLength { requested: usize, max: usize },
    /// 十六进制字符串非法(奇数长度或含非十六进制字符)。
    InvalidHex,
    /// 国密算法(SM1 / SM7 / SM9)本库不提供实现。
    UnsupportedNationalAlgorithm {
        name: &'static str,
        hint: &'static str,
    },
    /// 必需配置缺失(如环境变量未设置)。
    MissingConfig { key: &'static str },
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::InvalidKeyLength {
                label,
                expected,
                got,
            } => write!(f, "{label} length must be {expected} (got {got})."),
            Error::InvalidPrefix { label } => write!(f, "Invalid {label} ciphertext prefix."),
            Error::TooShort { label } => write!(f, "{label} ciphertext too short."),
            Error::MacVerificationFailed { label } => write!(f, "{label} MAC verification failed."),
            Error::DecryptionFailed { label } => write!(f, "{label} decryption failed."),
            Error::EncryptionFailed { label } => write!(f, "{label} encryption failed."),
            Error::SignFailed { label } => write!(f, "{label} signing failed."),
            Error::VerificationFailed { label } => {
                write!(f, "{label} signature verification failed.")
            }
            Error::UnknownIdentifier { kind, identifier } => {
                write!(f, "Unknown {kind} identifier \"{identifier}\".")
            }
            Error::InvalidMasterKey { got } => {
                write!(f, "Master key must be exactly 32 bytes (got {got}).")
            }
            Error::InvalidKey { label } => write!(f, "Invalid {label} key."),
            Error::InvalidIterations => write!(f, "PBKDF2 iterations must be positive."),
            Error::InvalidKdfParams { label } => write!(f, "Invalid {label} parameters."),
            Error::InvalidOutputLength { requested, max } => {
                if *requested == 0 {
                    write!(f, "Output length must be positive.")
                } else {
                    write!(f, "Output length {requested} exceeds the maximum of {max}.")
                }
            }
            Error::InvalidHex => write!(f, "Invalid hex string."),
            Error::UnsupportedNationalAlgorithm { name, hint } => {
                write!(f, "{name} is not provided by this library: {hint}")
            }
            Error::MissingConfig { key } => {
                write!(f, "Required configuration \"{key}\" was not found.")
            }
        }
    }
}

impl std::error::Error for Error {}

/// 库统一 Result。
pub type Result<T> = std::result::Result<T, Error>;