- 密码学
【免费下载链接】cryptography
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers.
cryptography是 Python 生态中最主流的密码学工具库之一,为开发者提供加密原语(primitives)与开箱即用的配方(recipes)。本篇指南以官方 docs/faq.rst 为骨架,系统梳理安装失败、警告抑制、OpenSSL 版本、Rust 构建、InternalError、PEM 导入等高频问题,并结合仓库源码与测试给出可复现的排查路径与最佳实践。
读完本文,你将掌握:如何快速解决pip install cryptography失败、如何正确抑制 import 时的弃用警告、如何应对 OpenSSL 版本过低与缺失 Rust 编译器、如何定位InternalError的根因、如何规范 PEM 文件使其可被顺利加载,以及如何理解backend参数的历史演进与当前现状。
问题追踪的原则:先分清是不是 cryptography 的锅
官方 FAQ 明确指出,issue tracker 的首要目的是定位并修复cryptography自身的 bug 与功能请求。因此每当用户报障时,项目组首先会问一个问题:这是 cryptography 的 bug,还是其他环节的 bug?
项目组会尽力帮助用户排查代码或环境层面的问题,但也坦诚存在边界:当问题与用户特定环境强相关、且无法复现时,协助能力有限;同时项目组不提供通用 Python 或 Python 打包(packaging)问题的支持。这一原则决定了你提 bug 时的预期管理:尽量提供最小可复现示例,并先排除自身代码与环境因素。
无法抑制的 import 弃用警告:为什么 filterwarnings 不生效
警告类型:不是 DeprecationWarning,而是 UserWarning
FAQ 特别用 hint 强调:cryptography在 import 时发出的弃用警告并不继承DeprecationWarning,而是继承UserWarning。这一设计在源码中有明确注释:src/cryptography/utils.py:
# We use a UserWarning subclass, instead of DeprecationWarning, because CPython # decided deprecation warnings should be invisible by default. class CryptographyDeprecationWarning(UserWarning): passCPython 自 2.7 起默认隐藏DeprecationWarning(仅开发者可见),为了确保弃用提示真正被用户看到,cryptography刻意选择继承UserWarning。
pytest 场景下的抑制方法
如果你的 pytest 遵循最佳实践、把警告视为错误(filterwarnings = error),import 时弹出的弃用警告会导致测试直接失败。官方给出的解决方案是在filterwarnings列表末尾追加一条 ignore 规则:
ignore:Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in a future release.:UserWarning为什么不能用 CryptographyDeprecationWarning 类名来过滤
FAQ 特别强调了一个容易踩的坑:不要试图用cryptography.utils.CryptographyDeprecationWarning作为 ignore 的类别参数。原因在于:指定该类别时,pytest/过滤器解析过程会内部触发import cryptography,而这会在 ignore 规则生效之前就把警告发射出来,规则形同虚设。
同样的规则适用于 warnings.filterwarnings 与 -W 参数
除了 pytest,FAQ 指出同样的原理适用于代码内调用warnings.filterwarnings,或者用 CPython 的-W命令行选项启动解释器。示例:
import warnings warnings.filterwarnings("ignore", message=r"Python 2 is no longer supported.*")命令行方式:
$ python -W "ignore:Python 2 is no longer supported.*:UserWarning" your_script.py从源码看,CryptographyDeprecationWarning同时是多个版本系列的弃用别名(DeprecatedIn36~DeprecatedIn51),见 src/cryptography/utils.py,这意味着未来仍会有同类警告出现,掌握上述匹配模式比记住某条具体消息更有价值。
cryptography 安装失败的通用排错路径
第一步:升级 pip 再试
安装失败的第一排查步骤永远是升级 pip 后重装。FAQ 给出的命令:
$ pip install -U pipWindows 平台则建议使用:
$ python -m pip install -U pip绝大多数安装问题(尤其是旧 pip 无法识别新格式 wheel)都能在这一步解决。升级后重新执行pip install cryptography,若仍报错,再参考完整的 docs/installation.rst 文档按平台逐项排查。
第二步:区分报错类型定位根因
常见报错可归为三类,对应 FAQ 中三个独立条目:
| 报错现象 | 根因 | 处理方向 |
|---|---|---|
Can not find Rust compiler | 本地无 Rust 工具链,需从源码构建 | 升级 pip 获取预编译 wheel,或安装 Rust(见下文) |
| 安装时因 OpenSSL 过旧失败 | 系统 OpenSSL 低于 3.0.0 | 升级到 OpenSSL 3.0.0+(可能需要升级操作系统) |
构建时报错error: Can not find Rust compiler | 源码构建缺少 Rust | 参照 docs/installation.rst 的 Rust 章节安装 |
为什么 cryptography 需要 Rust:内存安全与性能的取舍
FAQ 明确回答了"为什么需要 Rust"这一高频疑问:
cryptography的密码学运算依赖 OpenSSL(详见 docs/openssl.rst)——OpenSSL 是事实上的密码学标准实现,性能高、附带多种对开发者有价值的认证。但它是 C 语言编写,缺乏内存安全性。项目组的策略是:保留 OpenSSL 的高性能优势,同时把非密码学运算(例如 ASN.1 解析)重写为高性能、内存安全的 Rust。
这一架构决策在仓库中清晰可见:src/rust/下存在多个 Rust crate,如负责 ASN.1 解析与编解码的src/rust/declarative_asn1/、负责密钥解析的 src/rust/cryptography-key-parsing/,以及cryptography-openssl、cryptography-x509、cryptography-x509-verification等模块化 crate(见 src/rust/Cargo.toml 及各 crate 的 Cargo.toml)。
Rust 只在构建期需要
FAQ 特别澄清:Rust 仅在 cryptography 的构建阶段需要,构建完成后使用 cryptography 无需 Rust 环境。这与 C 编译器工具链的情况完全一致——都是"构建需要、运行不需要"。当前最低支持的 Rust 版本为 1.83.0(见 docs/installation.rst 的 Rust 章节),部分发行版(如 Alpine < 3.21、Debian 早于 Trixie 的版本、RHEL/CentOS 9.6 之前的版本)自带的 Rust 过旧,需要按官方指引安装较新版本。
在 Docker 等部署场景中,推荐多阶段构建:构建阶段安装 Rust 和 C 工具链,运行镜像中则不包含它们。
遇到 InternalError 该怎么办
InternalError 从哪来
InternalError的定义位于 src/cryptography/exceptions.py,其抛出点在 OpenSSL 绑定层。核心逻辑在 src/cryptography/hazmat/bindings/openssl/binding.py:
def _openssl_assert(ok: bool) -> None: if not ok: errors = openssl.capture_error_stack() raise InternalError( "Unknown OpenSSL error. This error is commonly encountered when " "another library is not cleaning up the OpenSSL error stack. ...", errors, )最常见的根因:OpenSSL 错误栈被"污染"
FAQ 明确指出:InternalError最常见的原因是同一进程内其他也使用 OpenSSL 的库把错误留在了 OpenSSL 错误栈上。排查步骤:
- 逐个移除进程中的其他 OpenSSL 使用方(如 PyOpenSSL、requests 的某些后端、其他加密库),看问题是否消失;
- 若移除后仍有问题,或确认其他库无责,则可能是 cryptography 自身 bug,请携带可复现步骤到项目 issue 区提交。
OpenSSL 版本过低导致安装失败
OpenSSL 项目已停止维护 0.9.8、1.0.0、1.0.1、1.0.2、1.1.0、1.1.1 这些发布系列,这些版本不再获得上游安全补丁,cryptography也随之放弃对它们的支持。因此安装或构建 cryptography 时遇到 OpenSSL 相关失败,处理方式就是升级到 OpenSSL 3.0.0 或更高版本——这可能意味着需要升级到更新的操作系统发行版。
从 docs/installation.rst 可以看到,项目当前测试覆盖OpenSSL 3.0-latest、3.4-latest、3.5-latest、3.6-latest、4.0-latest,以及 BoringSSL、aws-lc 与仍在安全支持期的 LibreSSL。多数主流平台通过manylinux/musllinux静态链接 wheel 即可获得最新 OpenSSL,无需关心系统自带版本。
构建报错 "Can not find Rust compiler"
若从源码构建 cryptography 时出现该错误,说明环境中没有 Rust 工具链。两条解决路径:
- 升级 pip:新版 pip 会优先安装预编译的
abi3wheel,多数用户升级 pip 后即可跳过源码构建、不再需要 Rust; - 安装 Rust:按 docs/installation.rst 中的指引安装较新版本的 Rust(推荐用 rustup,最低 1.83.0),并确保
rustc/cargo在PATH中。
同样强调:Rust 只在构建阶段需要。Linux 下常见发行版安装命令(取自 docs/installation.rst):
# Alpine $ sudo apk add gcc musl-dev python3-dev libffi-dev openssl-dev cargo pkgconfig # Debian/Ubuntu $ sudo apt-get install build-essential libssl-dev libffi-dev \ python3-dev cargo pkg-config # Fedora/RHEL/CentOS(需 9.6+) $ sudo dnf install redhat-rpm-config gcc libffi-devel python3-devel \ openssl-devel cargo pkg-config强制从源码构建(不使用 manylinux wheel)时可加--no-binary:
$ pip install cryptography --no-binary cryptographyAWS Lambda 上的安装/导入错误
在 AWS Lambda 上遇到安装或导入错误时,FAQ 建议严格遵循 AWS 官方文档来构建部署包:
- 构建 Lambda 的 .zip 归档时,按 AWS 的 Python 打包文档操作;
- 使用容器镜像时,按 AWS 的容器镜像构建文档操作。
核心要点是:Lambda 环境精简且架构可能非 x86-64,依赖需随包带上或打进镜像,且要注意为对应架构(如 ARM64 Graviton)获取正确的 wheel。
abi3 wheel:为什么你的 Python 版本没有专属 wheel
FAQ 解释了一个常见疑惑:"为什么没有针对我的 Python 3.x 版本的 wheel?"
答案在于 cryptography 的 Python 3 wheel 是abi3wheel(即 CPython ABI 稳定 ABI)。这类 wheel 标注了一个最低 Python 版本,并可在大于或等于该版本的任何 Python 版本上使用。新版 pip 会自动选择并安装 abi3 wheel,因此不需要为每个 Python 3 小版本单独发布 wheel。
这意味着:即使 PyPI 页面上没有与你 Python 3.x 精确匹配的 wheel 文件,只要你的 Python 版本不低于 abi3 wheel 声明的基线(例如 cp39),安装也能正常进行。
PEM 文件无法导入:格式校验清单
PEM 是什么
PEM 是一种将密钥、证书等密码学数据编码为普通文本的格式(最初定义于 RFC 1421,后被多个 RFC 沿用)。数据先做 base64 编码,再用头尾行包裹。
可导入的 PEM 必须满足三条规则
FAQ 给出明确校验清单:
- 头行必须为单行,形如
-----BEGIN [FILE TYPE]-----,其中[FILE TYPE]为CERTIFICATE、PUBLIC KEY、PRIVATE KEY等; - 尾行必须为单行,形如
-----END [FILE TYPE]-----; - 除最后一行外,所有行必须恰好为 64 个字符(base64 编码的 64 字符折行标准)。
合法 PEM 示例(RSA 公钥)
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7CsKFSzq20NLb2VQDXma 9DsDXtKADv0ziI5hT1KG6Bex5seE9pUoEcUxNv4uXo2jzAUgyRweRl/DLU8SoN8+ WWd6YWik4GZvNv7j0z28h9Q5jRySxy4dmElFtIRHGiKhqd1Z06z4AzrmKEzgxkOk LJjY9cvwD+iXjpK2oJwNNyavvjb5YZq6V60RhpyNtKpMh2+zRLgIk9sROEPQeYfK 22zj2CnGBMg5Gm2uPOsGDltl/I/Fdh1aO3X4i1GXwCuPf1kSAg6lPJD0batftkSG v0X0heUaV0j1HSNlBWamT4IR9+iJfKJHekOqvHQBcaCu7Ja4kXzx6GZ3M2j/Ja3A 2QIDAQAB -----END PUBLIC KEY-----若你的 PEM 导入失败,对照上述三条规则逐一检查:头尾行是否有额外空格或换行、中间行长度是否严格 64 字符、文件是否混入了不可见字符或非 base64 字符。
对应加载 API
PEM 加载入口集中在 src/cryptography/hazmat/primitives/serialization/base.py,例如:
from cryptography.hazmat.primitives import serialization private_key = serialization.load_pem_private_key(data, password=None) public_key = serialization.load_pem_public_key(data)其中load_pem_private_key、load_pem_public_key直接映射到 Rust 侧的密钥解析实现(rust_openssl.keys.load_pem_private_key等),而load_pem_parameters(DH 参数)映射到rust_openssl.dh.from_pem_parameters。这正是 FAQ"为什么需要 Rust"一节所述架构的具体体现:PEM/ASN.1 解析已由 Rust 实现。
backend 参数去哪了:一个历史演进问题
FAQ 记录了一次重要的 API 演进:
- 版本 3.1 起,
cryptography不再要求提供backend参数; - 版本 36.0 起,正式弃用
backend参数; - 如果你仍在使用旧版本且依赖该参数,请查看对应版本的文档或直接升级到最新版。
FAQ 特别说明:出于向前兼容考虑,backend仍会被静默接受——传了也不会报错,但会被忽略且不再出现在文档中。因此在新代码中无需(也不应)再传递backend。
非 x86 非 ARM64 架构:为什么没有你的 CPU 的 wheel
FAQ 坦诚回应了"为什么不为我的 CPU 架构上传 wheel"的问题:
- 上传到 PyPI 的 wheel 必须经过该架构上的完整 CI 测试(每个 commit 都跑),因为 cryptography 大量使用按架构优化的汇编代码;
- 将某架构纳入 CI 需要满足:有能提供该架构构建、能集成进现有 workflow、容量足够且性能不拖累贡献者体验的 CI 提供方。
FAQ 认为这不是不可逾越的门槛,但也不轻松。若你希望支持新 CPU 架构,欢迎联系项目组讨论并贡献支持——项目组会尽量配合,但无法承诺亲自完成这项工作。
总结:FAQ 中的通用排错方法论
纵观 docs/faq.rst,可以提炼出一条通用的排错方法论:
- 先升级 pip 再重装——解决大多数 wheel 识别与源码构建误判问题;
- 区分"项目 bug"与"环境问题"——
InternalError优先排查 OpenSSL 错误栈是否被其他库污染; - 理解构建期依赖(Rust、C 工具链、OpenSSL)与运行期依赖的区别——构建时缺什么补什么,运行时不需要 Rust;
- 校验输入格式——PEM 导入失败按 64 字符折行与头尾行规则逐条核对;
- 跟紧 API 演进——
backend参数已弃用但可静默兼容,新代码不要传; - 遵循官方文档——Lambda、各发行版、Windows 编译等场景均有对应章节指引,详见 docs/installation.rst。
这套方法论配合仓库内的源码(绑定层、Rust 解析器、序列化 API)与测试(如 tests/test_warnings.py 中对deprecated机制的验证),足以应对绝大多数 cryptography 的日常使用与排障场景。
- 密码学
【免费下载链接】cryptography
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers.
相关推荐
Umi FAQ 实战指南:从 polyfill、ESLint 到部署排错的常见问题全解
Umi FAQ 实战指南:从 polyfill、ESLint 到部署排错的常见问题全解 本文基于 docs/guide/faq.md https://link.
前端开发工具Codex-X的自动故障转移是如何实现的:本地127.0.0.1监听服务解析
Codex X的自动故障转移是如何实现的:本地127.0.0.1监听服务解析 📌 Codex X 是 OpenAI Codex 桌面端/CLI 的可视化管理工
桌面应用开发者工具AI 应用xLua 常见问题(FAQ)实战指南:从安装部署、代码生成到热更新排错的全方位解答
xLua 常见问题(FAQ)实战指南:从安装部署、代码生成到热更新排错的全方位解答 xLua 是腾讯开源的一套基于 C (Unity、.Net、Mono)的 L
游戏开发脚本语言集成
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考