Phase 5 Iteration 2: chữ ký số PKCS#7/PAdES + redact tỉa ký tự + lưu tối ưu

Engine — chữ ký số (sign.rs MỚI):
- generate_self_signed_id: Digital ID tự ký RSA-2048 + X.509 (rcgen), ghi PEM
- sign_pdf: đúng cơ chế Adobe — lopdf dựng sig dict (/SubFilter
  adbe.pkcs7.detached) + Widget field + AcroForm/SigFlags, ByteRange/Contents
  placeholder; serialize → vá ByteRange theo offset thật → SHA-256 trên 2 đoạn
  → CMS SignedData detached (crate cms, signed attrs messageDigest+contentType,
  RSA-SHA256) nhét DER vào Contents
- verify_signatures: parse ByteRange/Contents, băm lại, kiểm chữ ký RSA trên
  signed attrs + messageDigest khớp + phủ toàn bộ file → phát hiện GIẢ MẠO
- Bài học: cắt DER về đúng độ dài (bỏ padding hex '0'); bỏ qua /Contents của
  trang (tham chiếu), chỉ nhận /Contents <hex> của chữ ký

Engine — redact tỉa theo KÝ TỰ (redact.rs):
- Text chạm một phần: page_char_boxes xác định ký tự trong vùng, GIỮ các đoạn
  ngoài vùng, dựng lại đúng vị trí/baseline/màu (font nhúng gốc → cùng họ →
  mặc định). Guard: text xoay/không đọc được font → xoá nguyên (an toàn)
- qpdf::optimize_save: --object-streams=generate + nén, dọn object rác

Tauri + UI:
- Commands: sig_create_id, sig_sign, sig_verify, security_optimize,
  pick_any_file, pick_save_pem
- Thanh Bảo mật thêm: Tạo Digital ID, Ký số (dialog + tự kiểm tra sau khi ký),
  Kiểm tra chữ ký (modal bảng trạng thái + lý do), Lưu tối ưu

Test (7 mới → 62/62 engine xanh ngoài 2 fixture qpdf Linux):
- sign_then_verify_is_valid; tampering_after_signing_is_detected (phát hiện
  sửa sau khi ký); verify_reports_none_for_unsigned
- redact tỉa ký tự: cụm mật biến mất, phần cùng dòng ngoài vùng vẫn còn
- optimize_save không phình + giữ nội dung

Deps: rsa, sha2, cms, x509-cert, rcgen, pkcs8, der, spki, const-oid.
Docs: 15 mục 6 (iter 2 + giới hạn), 16 (S13–S19), README, roadmap (Phase 5
HOÀN TẤT), 14 (kế tiếp: Phase 6 Form).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgnbPwSoRGNH7LHsDUmRpk
This commit is contained in:
2026-07-15 09:14:51 +00:00
co-authored by Claude Fable 5
parent 8d9076f60c
commit f62cded997
19 changed files with 2194 additions and 97 deletions
+11
View File
@@ -25,6 +25,17 @@ cargo run
| S11 | Gỡ mật khẩu với mật khẩu SAI | Báo lỗi rõ ràng, không tạo file hỏng | |
| S12 | **🧹 Xoá metadata** → lưu → mở file kết quả ở Foxit: File › Properties | Author/Producer/Created… trống; app vẫn mở đọc bình thường | |
## Bổ sung Iteration 2 — Chữ ký số + redact ký tự + lưu tối ưu
| # | Thao tác | Kỳ vọng | KQ |
|---|----------|---------|----|
| S13 | **🪪 Tạo Digital ID** → nhập tên → lưu .pem | Tạo file .pem thành công | |
| S14 | **✍️ Ký số** → nhập tên/lý do → chọn .pem vừa tạo → lưu | File mới được ký; tự hiện bảng kiểm tra: **Hợp lệ** ✓ | |
| S15 | Mở file đã ký ở **Foxit/Adobe** | Hiện có chữ ký; xác thực toán học hợp lệ (có thể cảnh báo "chưa tin cậy CA" vì tự ký — bình thường) | |
| S16 | Sửa 1 chữ trong file đã ký (chế độ Sửa nội dung) rồi lưu, sau đó **🔎 Kiểm tra chữ ký** | Chữ ký chuyển **KHÔNG hợp lệ** (nội dung đã bị sửa) | |
| S17 | **🔎 Kiểm tra chữ ký** trên file chưa ký | Báo "chưa có chữ ký số nào" | |
| S18 | Redact 1 CỤM TỪ ở giữa dòng (không phải cả dòng) → Áp dụng | Chỉ cụm đó bị đen/biến mất; phần còn lại của dòng **vẫn hiển thị và copy được** | |
| S19 | **📦 Lưu tối ưu** file lớn → so dung lượng | File kết quả nhỏ hơn/không phình, mở đọc bình thường | |
## Mẫu phản hồi
```
[Mã] (vd S5) — Phần mềm mở: <Foxit/Adobe/Chrome> — Hiện tượng: <mô tả> —