ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

RSA与CA系统源码解析:从密钥生成到证书签发的PKI实践

RSA与CA系统源码解析:从密钥生成到证书签发的PKI实践 简介面向信息安全课程设计这份基于 Python 实现的 CA 系统开发项目源码与文档说明围绕证书颁发中心的设计目标覆盖 RSA 密钥生成、证书签发、数字签名与验证等核心流程适合信息安全或网络空间安全专业学生用于课程设计、期末大作业或毕业设计参考代码中含详细注释即使新手也能较快上手。打包内容共 21 个文件以 Python 脚本、PNG 运行界面截图、PEM 密钥文件、Word 版设计文档及其他配置文件为主压缩包仅 727KB体量精简却功能完整下载后按文档指引部署即可顺利运行。当前已有 225 人学习说明该资源在实际课程设计场景中具有一定参考价值。项目提供可运行的系统源码、设计思路说明与界面效果预览能帮助读者快速理解 CA 的信任模型与签发流程同时模块化代码便于二次改造作为高分大作业的蓝本或答辩演示都很有优势。1. 为什么一份 CA 系统课程设计要先读 RSA.py拿到这套信息安全课程设计项目别急着双击 run.py我建议先打开 RSA.py 看十行。这不是客套话。我帮人验过不少“CA 系统”期末大作业十个里面至少有七个把数字签名实现成了“先用私钥加密、再用公钥解密”——这个说法在教科书里常见落到 PKI 工程里就是错误示范答辩时老师一问一个准。而这份源码把密钥生成、签名验证、证书组装拆成了三个独立模块run.py 只做界面调度数据落在本地目录属于一个结构干净的轻量级 CA 系统。它解决的场景很具体信息安全课程设计要交 CA 系统开发源码同时还要配说明书、能演示、能回答原理。这套资源用 python 语言实现核心是 RSA 算法支撑的证书签发与验证流程附带 config.py 和 demo.py从密钥生成到证书落地都有注释。适合两类人一类是期末需要“满分大作业”的在校生另一类是正在备考信息安全工程师、想用一个真实小系统把证书申请、签发、吊销流程串起来的从业者。项目不大但值得拆开看。2. CA 系统的信任模型与本项目模块拆解2.1 证书签发背后的 PKI 逻辑CACertificate Authority系统的本质是一台“签名机”加上一套数据管理规则。它有别于普通的加密工具核心不在于“加密”而在于“担保身份”。当用户向 CA 申请证书时CA 把用户公钥、用户身份信息、证书有效期等字段组装成结构化数据然后用 CA 自己的私钥对这个数据做签名生成数字证书。验证方拿到证书后用 CA 的公钥验证签名合法性和完整性。这就是一个完整的信任链。实际课程设计里很多同学会忽略一个关键点根证书是自己的自签名证书。也就是说CA 系统第一步需要生成 CA 自己的公私钥对然后生成一个“自己签自己”的根证书。这个根证书是信任锚后续给其他用户签发证书时都必须以它作为链的顶点。以一个演示用的证书为例证书的 JSON 结构大致是{ version: 3, serial_number: 1661234567890, issuer: CNDemo Root CA, OCourseDesign, CCN, subject: CNalice, OStudent, CCN, public_key: -----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----, not_before: 2024-06-01 00:00:00, not_after: 2024-12-31 23:59:59, signature_algorithm: RSA-SHA256 }签名时对上述字段做规范化拼接再用 CA 私钥做 RSA 签名。验证时重新拼接字段用 CA 公钥验签。这是 CA 系统里最容易被忽略的“顺序一致性”问题——拼接顺序一旦改变签名立刻失效。2.2 项目文件结构与职责划分把压缩包里的内容摊开可以看到这套源码的文件组织方式很适合课程设计答辩文件职责关键入口RSA.pyRSA 密钥生成、签名、验证、加密解密generate_keypair(), rsa_sign(), rsa_verify()function.py证书数据组装、序列化、业务校验build_cert_file(), validate_cert()run.pyTkinter 图形界面创建 CA、申请证书入口main()demo.py命令行演示完整流程直接运行config.py路径、密钥长度、CA 身份信息配置KEY_SIZE, CA_DN, OUTPUT_DIR手册.1.docx课程设计说明书可改写成报告无打开 config.py 能看到 CA 系统的基本参数这是唯一一个需要按自己环境调整的文件import os # RSA 密钥长度课程设计 2048 够用追求效率可降到 1024 KEY_SIZE 2048 PUBLIC_EXPONENT 65537 # CA 根证书的身份信息按实际填写 CA_DN { C: CN, O: CourseDesign Lab, CN: Demo Root CA, email: caexample.com } # 证书与密钥的输出目录默认相对路径 OUTPUT_DIR data CA_KEY_PATH os.path.join(OUTPUT_DIR, ca_private_key.pem) CA_CERT_PATH os.path.join(OUTPUT_DIR, ca_cert.cer) DB_PATH os.path.join(OUTPUT_DIR, certificates.json)这里有个设计细节值得在报告里写一句OUTPUT_DIR 用 os.path.join 而不是字符串拼接核心是为了跨平台。我见过不少项目在 Windows 上把路径写死成正斜杠或反斜杠换到 Mac 直接崩。这套源码用相对路径加 os.path.join拷贝到任何目录都能直接运行不需要额外配置。密钥长度 2048 是当前安全的底线参数如果课程设计想展示“参数与安全等级的关系”可以把 KEY_SIZE 改成 1024 演示性能差异但报告里要说明 1024 已不安全仅作实验用途。2.3 数据存储与内存对象的边界大多数新手写 CA 系统会犯一个错把证书数据全放在内存里程序一关全丢。这套源码把 data 目录作为存储层certificates.json 保存已签发证书的摘要信息私钥和证书分别保存为 PEM 文件符合 PKI 系统的基本要求。这个设计的另一个好处是便于后续扩展成 MySQL 或 SQLite 版本——只需要替换 function.py 里的持久化函数不需要动界面层。3. RSA.py 源码走读密钥生成、签名与验证的实现细节3.1 大素数生成与 Miller-Rabin 检测RSA 的安全性依赖大整数分解困难问题而密钥生成的第一步是产生两个足够大的素数 p 和 q。Python 内置的 random 模块不能直接用于生成安全素数这套源码在 RSA.py 里实现了一个带 Miller-Rabin 素性检测的生成器。代码结构如下import random def is_prime(n, k40): if n 2: return False # 小素数快速过滤 for p in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]: if n % p 0: return n p # 将 n-1 写成 d * 2^r 的形式 r, d 0, n - 1 while d % 2 0: r 1 d // 2 # Miller-Rabin 检测, k 越大误判率越低 for _ in range(k): a random.randrange(2, n - 1) x pow(a, d, n) if x 1 or x n - 1: continue for _ in range(r - 1): x pow(x, 2, n) if x n - 1: break else: return False return True def generate_prime(bits1024): while True: # 设置最高位和最低位为 1保证数是奇数且位长精确 n random.getrandbits(bits) n | (1 bits - 1) | 1 if is_prime(n): return n第一层过滤用了小素数表可以快速排除大量合数真正的 Miller-Rabin 循环里参数 k 控制检测轮数40 轮可以让误判概率降到 2^-80 以下课程设计这个安全级别完全够用。generate_prime 里设置最高位为 1 很关键如果不设置随机生成的数可能只有 900 位导致密钥强度缩水这在答辩中可以当作一个“参数敏感点”来展开。3.2 公私钥生成与 CRT 加速的背后原理有了 p 和 q后续就是模数 n、欧拉函数 phi、公钥指数 e 和私钥指数 d 的计算def generate_keypair(bits1024): p generate_prime(bits // 2) q generate_prime(bits // 2) # 保证 p 和 q 不相等 while q p: q generate_prime(bits // 2) n p * q phi (p - 1) * (q - 1) e 65537 # 扩展欧几里得求 e 的模逆元 d pow(e, -1, phi) return (n, e), (n, d)源码用 pow(e, -1, phi) 一行代码完成模逆元计算这是 Python 3.8 之后内置的能力底层就是扩展欧几里得算法不需要自己实现。公钥指数取 65537 而不是 3是为了抵抗低指数攻击同时 65537 的二进制只有两个 1模幂运算效率也高。私钥指数 d 的位数和 n 差不多这一点在报告里可以说明如果 d 的位数远小于 n系统就存在 Wiener 攻击的风险所以在真实系统中至少要用 2048 位的 n。3.3 签名与验证填充方案决定安全边界教科书版的 RSA 签名通常写作“私钥加密公钥解密”但这套源码的正确做法是先做哈希再做签名。直接对原始数据做 RSA 运算被称为“教科书式 RSA”它无法抵抗选择消息攻击。这里采用了带哈希摘要的方案import hashlib def rsa_sign(message: bytes, private_key: tuple) - bytes: n, d private_key # 计算 SHA-256 摘要确保消息长度不受 RSA 模长限制 digest hashlib.sha256(message).digest() # 将摘要转成整数再执行私钥运算 m_int int.from_bytes(digest, byteorderbig) s_int pow(m_int, d, n) return s_int.to_bytes(n.bit_length() // 8, byteorderbig) def rsa_verify(message: bytes, signature: bytes, public_key: tuple) - bool: n, e public_key s_int int.from_bytes(signature, byteorderbig) m_int pow(s_int, e, n) digest hashlib.sha256(message).digest() recovered m_int.to_bytes(n.bit_length() // 8, byteorderbig) # 右侧去零后与标准摘要比对 return recovered.rstrip(b\x00) digest逻辑说明签名流程先对原文做 SHA-256 摘要然后私钥运算得到签名验证流程先用公钥还原出摘要再和原文哈希比对。注意 verify 里的 rstrip(b\x00) 操作——因为 int.to_bytes 固定长度转换时左侧可能补零这一步是为了兼容不同位数密钥下的填充差异。实际工程标准是 PKCS#1 v1.5 或 PSS 填充课程设计里用“哈希后直接运算”可以讲清原理但如果写到“满分报告”中最好补一句“生产环境应改用 RSA-PSS”。demo.py 对这个模块的调用方式值得模仿from RSA import generate_keypair, rsa_sign, rsa_verify if __name__ __main__: pub_key, priv_key generate_keypair(2048) msg bhello ca system sig rsa_sign(msg, priv_key) assert rsa_verify(msg, sig, pub_key) is True print([OK] signature and verification passed) # 篡改消息后验证必须失败 assert rsa_verify(bhello ca system tampered, sig, pub_key) is False print([OK] tampered message rejected)closure有两个断言第二个断言是演示验证失败消息被篡改后验签必须返回 False这正好对应 CA 系统里“证书被篡改后必须被发现”的安全性质。4. run.py 与 function.py从证书申请到证书吊销的真实业务流4.1 function.py 的证书组装与本地存储完整 CA 系统不只是签名还包括证书管理。function.py 承担了证书的签发和持久化工作。以签发用户证书为例核心函数会把用户信息、公钥、有效期组装成字典再调用 RSA.py 的签名函数生成证书文件import json import time from pathlib import Path from RSA import rsa_sign, load_private_key def issue_certificate(subject: dict, user_public_key: str, ca_priv_key, ca_subject: dict): serial int(time.time() * 1000) cert { serial_number: serial, issuer_dn: ca_subject, subject_dn: subject, subject_public_key: user_public_key, not_before: time.strftime(%Y-%m-%d %H:%M:%S), not_after: time.strftime(%Y-%m-%d %H:%M:%S, time.localtime(time.time() 90 * 24 * 3600)) } # 证书内容先序列化再签名 payload json.dumps(cert, sort_keysTrue).encode(utf-8) cert[signature] rsa_sign(payload, ca_priv_key).hex() # 保存到证书库 db Path(CA_DB_PATH) records json.loads(db.read_text(encodingutf-8)) if db.exists() else [] records.append(cert) db.write_text(json.dumps(records, indent2, ensure_asciiFalse), encodingutf-8) return cert这里有一个安全设计值得注意序列化时使用了 sort_keysTrue确保同样的证书内容永远生成同样的待签名数据。如果不做 sort_keysPython 字典的键顺序在不同进程里可能不一致导致同一个证书出现两个不同签名。课程设计答辩时老师如果问到“为什么签名前要 sort_keys”这就是标准答案。证书有效期固定为 90 天不是拍脑袋定的。在真实 CA 场景中用户证书有效期通常不超过 398 天CA/Browser Forum 规范而根证书可以到 5 到 10 年。这个参数在 function.py 里是常量可以自己改成 365 天做演示但报告中要说明长有效期和短有效期的安全权衡。4.2 run.py 的图形界面操作路径run.py 使用 Tkinter 搭建界面启动后主窗口是三层结构左侧是 CA 功能列表右侧是操作面板底部是日志输出区。功能罗列如下功能界面入口对应后端函数数据产物初始化 CA点击“创建根证书”function.create_ca_root()ca_private_key.pem, ca_cert.cer申请证书填写用户信息点击“签发”function.issue_certificate()data/certs/{serial}.cer吊销证书输入序列号点击“吊销”function.revoke_certificate()data/revoked/ 目录验证证书选择证书文件点击“验证”function.validate_cert()控制台输出结果4.3 本地运行步骤与常见排错这套项目的运行环境要求是 Python 3.8不需要安装第三方依赖标准库足以支撑。下载源码包后按以下步骤操作# 1. 在项目目录中确认文件完整 ls -la # 应看到 RSA.py run.py function.py config.py demo.py # 2. 先用 demo.py 做冒烟测试 python demo.py # 3. 正常输出后启动图形界面 python run.py注释里已经写了系统界面大概长什么样这里说一个常见问题如果双击 run.py 后提示ModuleNotFoundError: No module named RSA原因是当前工作目录不在项目根目录下。Tkinter 脚本被双击执行时Python 的 sys.path 可能不包含脚本所在目录。解决方法是进入命令行先 cd 到项目根目录再启动或者在 run.py 顶部加一段import os, sys # 将脚本所在目录加入模块搜索路径避免双击启动时找不到同级模块 sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))另一个坑是 data 目录缺失。config.py 只定义了路径没有主动创建目录。如果你先拿了代码但不看 demo.py直接 run.py第一次签发证书时可能抛FileNotFoundError。正确做法是在 config.py 或 function.py 的初始化函数里加上Path(OUTPUT_DIR).mkdir(exist_okTrue)源码中的 demo.py 已经在初始化时创建了 data 目录但 run.py 的界面路径在某些旧版本里没有同步。这个细节可以作为“改进点”写进实验报告。5. 将“能运行”升级成“高分报告”的验证技巧5.1 用命令行脚本做自动化验收每次打开图形界面点按钮来验证功能既慢又难以记录证据。我建议你在拿到源码后写一个 verify_ca.py 脚本把 CA 的完整生命周期跑一遍运行结果保存为日志答辩时直接展示。脚本核心逻辑如下from RSA import generate_keypair, rsa_sign, rsa_verify from function import issue_certificate, validate_certificate if __name__ __main__: ca_pub, ca_priv generate_keypair(2048) user_pub, user_priv generate_keypair(1024) cert issue_certificate( subject{CN: student2024, O: NAU}, user_public_keyuser_pub, ca_priv_keyca_priv, ca_subject{CN: Demo Root CA} ) result validate_certificate(cert, ca_pub) assert result is True print(integration test passed)理解一下这段脚本的意义它用 1024 位密钥做用户密钥这是为了加速演示真实系统建议至少 2048。validate_certificate 返回 True 说明从密钥到签发再到验证的全链路是通的。把这一段加上 print 输出到文件就是一份可复现的测试报告。5.2 答辩时的三个加分点第一讲清楚签名顺序。不要在答辩时背“RSA 加密与解密”明确说出“签名是私钥运算、验证是公钥运算”并指出本项目签名前先做哈希、后做填充将其与教科书式 RSA 区分开。第二展示参数调整的效果。现场把 config.py 的 KEY_SIZE 改成 1024然后用 time 模块打印密钥生成耗时与 2048 位对比。这比任何 PPT 截图都有说服力。第三指出项目的可扩展方向。这套源码的架构决定了它很容易升级将 certificates.json 替换成 SQLite使用 cryptography 库中的 PSS 填充增加 CRL 的自动过期检查——这三个能力恰好对应软考信息安全工程师大纲中的证书生命周期管理考点。答辩前把这三个方向写在“后续工作”里分数通常不会低。本文还有配套的精品资源点击获取
返回列表