# CA测试 **Repository Path**: zwnshuai/ca-testing ## Basic Information - **Project Name**: CA测试 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-10-29 - **Last Updated**: 2026-01-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ZJCA CMT 集成项目 ## 项目简介 这是一个基于 React + TypeScript + Vite 的 ZJCA CMT (Certificate Management Tool) 集成示例项目,展示了如何在 Web 应用中集成浙江CA的密钥管理功能。 ## 主要功能 ### 1. ZJCA CMT 初始化 - 自动初始化 ZJCA CMT API - 显示客户端版本信息 - 支持重新初始化和释放资源 ### 2. 介质管理 - 枚举 Ukey 介质列表 - 显示介质详细信息(SN、标签、制造商) - 自动监听介质插拔事件 ### 3. 证书管理 - 枚举证书列表(支持按算法和用途筛选) - 显示证书详细信息(主题、SN、有效期、算法类型等) - 证书验证功能(验证有效期和签名) ### 4. 文件操作 - **文件选择**:使用 ZJCA SDK 的文件对话框选择文件 - **文件复制/备份**:将文件复制到指定位置 - **文件加密**:使用 Ukey 中的证书加密文件 - **文件解密**:使用 Ukey 中的私钥解密文件 ## 文件加密/解密功能详解 ### 加密功能 #### 实现方式 本项目使用 ZJCA SDK 的 **`encryptFile` API** 直接加密文件。 #### 加密流程 ```typescript // 1. 验证 PIN 码 const pinResp = window.g_ZjcaCMT.verifyPin(0, ''); // 2. 获取加密证书 const certResp = window.g_ZjcaCMT.getCertList(0, 0, 2); // usage=2 表示加密证书 const certBase64 = window.g_ZjcaCMT.getCertContent(0, certAlg, certUsage).res; // 3. 选择加密文件保存路径 const encryptPath = window.g_ZjcaCMT.getFileName(false, '保存加密后的文件', '*.*').res; // 4. 加密文件 const encryptResp = window.g_ZjcaCMT.encryptFile( 0, // keyIndex: 介质索引 certBase64, // base64Cert: 证书Base64 srcFile, // srcFile: 源文件路径 encryptPath, // desFile: 加密文件路径 0x20, // symmAlg: SM4_ECB(SM2证书用) 1, // cipherType: PKCS#1 1, // paddingType: PKCS5 null // callback: 同步模式 ); ``` #### 加密参数说明 - **keyIndex**: `0` - 使用第一个介质(Ukey) - **symmAlg**: `0x20` (SM4_ECB) - 对称加密算法,适用于 SM2 证书 - **cipherType**: `1` (PKCS#1) - 密文封装格式(默认,兼容性最好) - **paddingType**: `1` (PKCS5) - 填充方式 ### 解密功能 #### 实现方式 本项目使用 ZJCA SDK 的 **`decryptFileUseKey` API** 直接解密文件。 **核心特点**: - ✅ **直接使用介质中的私钥**:无需指定证书,自动使用 Ukey 中的私钥 - ✅ **强制 PIN 码验证**:每次解密都必须输入 PIN 码,确保安全性 - ✅ **自动算法识别**:自动识别 RSA 或 SM2 算法 #### 解密流程 ```typescript // 1. 验证 PIN 码(强制,弹出对话框) const pinResp = window.g_ZjcaCMT.verifyPin(0, ''); // 空字符串强制弹出PIN码输入框 // 2. 选择解密文件保存路径 const decryptPath = window.g_ZjcaCMT.getFileName(false, '保存解密后的文件', '*.*').res; // 3. 解密文件(直接使用介质中的私钥) const decryptResp = window.g_ZjcaCMT.decryptFileUseKey( 0, // keyIndex: 介质索引(直接使用介质中的私钥) 0, // asymmAlg: 0=自动识别(RSA或SM2) 0x20, // symmAlg: SM4_ECB(与加密时一致) 1, // paddingType: PKCS5(与加密时一致) cipherFile, // cipherFile: 密文文件路径 decryptPath, // desFile: 解密后文件路径 null // callback: 同步模式 ); ``` #### 解密参数说明 - **keyIndex**: `0` - 使用第一个介质(Ukey,必须与加密时相同) - **asymmAlg**: `0` - 自动识别非对称算法(RSA 或 SM2) - **symmAlg**: `0x20` (SM4_ECB) - 对称算法,必须与加密时一致 - **paddingType**: `1` (PKCS5) - 填充方式,必须与加密时一致 #### 安全机制 1. **PIN 码强制验证**:每次解密都必须输入正确的 PIN 码 2. **私钥保护**:私钥始终存储在 Ukey 中,永不导出 3. **介质绑定**:只有持有加密时使用的 Ukey 才能解密 ### 支持的算法 - **非对称算法**:RSA、SM2(国密) - **对称算法**:SM4_ECB、SM4_CBC、DES、3DES、AES - **密文格式**:PKCS#1、PKCS#7 ## 技术栈 - **前端框架**:React 18 - **开发语言**:TypeScript - **构建工具**:Vite - **CA SDK**:ZJCA CMT JavaScript SDK (WebSocket 模式) ## 项目配置 ### 连接配置 - **协议**:HTTPS - **地址**:127.0.0.1 - **端口**:5150 ### 配置代码 ```typescript const g_ZjcaCMT = new zjca_CMT(onCallbackKeyEvent, null); g_ZjcaCMT.setProtocol('https'); // 使用 HTTPS 协议 const resp = g_ZjcaCMT.init(1, 1); // 初始化 ``` ## 使用说明 ### 1. 启动项目 ```bash npm install npm run dev ``` ### 2. 确保 ZJCA 客户端运行 - 启动 ZJCA 客户端(ZJCAKeyManager.exe) - 确保客户端监听在 127.0.0.1:5150 (HTTPS) - 插入 Ukey 设备 ### 3. 信任本地证书 首次使用需要信任 ZJCA 客户端的自签名证书: 1. 在浏览器中访问:`https://127.0.0.1:5150` 2. 点击"高级" → "继续前往 127.0.0.1(不安全)" 3. 返回项目页面刷新 ### 4. 使用功能 #### 枚举介质列表 1. 点击"📋 枚举介质列表"按钮 2. 查看控制台输出的介质信息 #### 枚举证书列表 1. 点击"📜 枚举证书列表"按钮 2. 选择算法类型(RSA/SM2/全部) 3. 查看证书列表 #### 验证证书 1. 枚举证书后,每个证书卡片会显示"🔍 验证证书"按钮 2. 点击按钮验证证书有效性 #### 文件加密 1. 点击"📁 浏览本地文件"选择要加密的文件 2. 点击"🔒 加密文件"按钮 3. 输入 PIN 码(如果需要) 4. 选择加密文件的保存位置 5. 等待加密完成 #### 文件解密 1. 点击"📁 浏览本地文件"选择要解密的密文文件 2. 点击"🔓 解密文件"按钮 3. 输入 PIN 码(如果需要) 4. 系统自动建议文件名(如果是 `.enc` 文件,会自动去掉后缀) 5. 等待解密完成 **注意**:解密时必须使用与加密时相同的 Ukey! ## 常见问题 ### 1. 连接失败 (ERR_CONNECTION_REFUSED) **原因**:ZJCA 客户端未运行或端口配置不正确 **解决方案**: - 确认 ZJCA 客户端正在运行 - 检查客户端监听的端口(使用 `netstat -ano | findstr 5150`) - 确认代码中的协议配置正确 ### 2. 证书错误 (ERR_CERT_COMMON_NAME_INVALID) **原因**:浏览器不信任本地自签名证书 **解决方案**: - 直接访问 `https://127.0.0.1:5150` 并信任证书 - 或在 Edge 浏览器中启用 `edge://flags/#allow-insecure-localhost` ### 3. 文件加密失败(参数错误 -2130706428) **原因**: - ZJCA WebSocket 客户端的 `encryptFile` API 对文件路径有限制 - 某些客户端版本不完全支持 `encryptFile` **解决方案**: - 本项目已改用 `readFile` + `encryptMessage` + `writeFile` 的三步方案 - 这种方式兼容性更好,适用于所有 WebSocket 客户端 ### 4. PIN 码验证失败 **原因**:PIN 码输入错误或 Ukey 被锁定 **解决方案**: - 确认 PIN 码正确 - 如果 Ukey 被锁定,需要使用 PUK 码解锁 - 联系 CA 管理员重置 PIN 码 ### 5. 未找到证书 **原因**: - Ukey 中没有证书 - 证书已过期或被吊销 - 证书类型不匹配(签名证书 vs 加密证书) **解决方案**: - 确认 Ukey 中有有效证书 - 尝试使用"全部证书"选项枚举 - 检查证书有效期 ### 6. 解密失败 **原因**: - 使用的 Ukey 与加密时不同 - 文件不是有效的加密文件 - 加密算法参数不匹配 - PIN 码错误 **解决方案**: - 确认使用与加密时相同的 Ukey - 确认文件是通过 ZJCA 加密的 - 检查解密参数(symmAlg、paddingType)是否与加密时一致 - 确认 PIN 码正确 ## 项目结构 ``` CA示例/ ├── public/ │ └── zjca_cmt/ # ZJCA SDK 文件 │ ├── zjcacmt.js │ ├── zjcacmt_websocket.js │ ├── zjcacmt_cert.js │ └── ... ├── src/ │ ├── pages/ │ │ ├── TestPage.tsx # 主测试页面 │ │ └── TestPage.css # 样式文件 │ ├── App.tsx │ └── main.tsx ├── zjcacmt_jssdk_20211103/ # SDK 示例和文档 │ ├── test/ │ │ ├── app/ # 应用示例 │ │ └── file/ # 文件操作示例 │ └── zjca_cmt/ # SDK 源码 └── README.md ``` ## 开发建议 ### 1. 错误处理 所有 ZJCA API 调用都应该检查返回值: ```typescript const resp = window.g_ZjcaCMT.someAPI(); if (!resp || resp.code !== 0) { console.error('API 调用失败:', resp?.msg); alert(`操作失败:${resp?.msg}`); return; } // 使用 resp.res ``` ### 2. 证书对象访问 证书对象的属性必须通过 getter 方法访问: ```typescript // ✅ 正确 const certAlg = cert.getAlg(); const certSN = cert.getSN(); const certSubject = cert.getSubjectCN(); // ❌ 错误 const certAlg = cert.algorithm; // undefined const certSN = cert.sn; // undefined ``` ### 3. 异步操作 某些 API 支持异步回调: ```typescript window.g_ZjcaCMT.someAPI(param1, param2, (result, data) => { console.log('异步结果:', result, data); }); ``` ### 4. 资源释放 页面卸载时应该释放 ZJCA 资源: ```typescript useEffect(() => { return () => { if (window.g_ZjcaCMT) { window.g_ZjcaCMT.finaled(); } }; }, []); ``` ## API 参考 ### 核心 API - `init(productType, version)` - 初始化 - `finaled()` - 释放资源 - `getVersion()` - 获取版本 - `getKeyList(refresh)` - 枚举介质 - `getCertList(keyIndex, algorithm, usage)` - 枚举证书 - `getCertContent(keyIndex, algorithm, usage)` - 获取证书内容 - `verifyCert(certBase64, flags)` - 验证证书 - `verifyPin(keyIndex, pin)` - 验证 PIN 码 ### 文件操作 API - `getFileName(isOpen, caption, filter)` - 文件对话框 - `readFile(path, isBinary)` - 读取文件 - `writeFile(path, content, isBinary)` - 写入文件 ### 加密/解密 API - `encryptMessage(keyIndex, cert, plainText, symmAlg, cipherType, paddingType, desFile)` - 加密消息/内容 - `encryptFile(keyIndex, cert, srcFile, desFile, symmAlg, cipherType, paddingType, callback)` - 加密文件 - `decryptMessageUseKey(keyIndex, asymmAlg, symmAlg, paddingType, cipherText, desFile)` - 解密消息/内容 - `decryptFileUseKey(keyIndex, asymmAlg, symmAlg, paddingType, cipherFile, desFile, callback)` - 解密文件 ## 更新日志 ### 2025-01-31 - ✅ 添加文件解密功能(`decryptFileUseKey`) - ✅ 修复文件加密功能,使用正确的参数组合(cipherType=1) - ✅ 根据证书算法自动选择对称算法(SM2→SM4,RSA→DES) - ✅ 优化了错误提示和日志输出 - ✅ 更新文档,添加加密/解密完整说明 ### 2025-01-30 - ✅ 添加证书验证功能 - ✅ 添加文件上传/复制功能 - ✅ 使用 SDK 文件对话框替代浏览器文件选择 ### 2025-01-29 - ✅ 添加证书枚举功能 - ✅ 支持按算法和用途筛选证书 - ✅ 显示证书详细信息 ### 2025-01-28 - ✅ 实现介质枚举功能 - ✅ 添加介质事件监听 - ✅ 配置 HTTPS 连接 ## 许可证 MIT License ## 联系方式 如有问题或建议,请联系项目维护者。