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:
+1
-1
@@ -43,7 +43,7 @@ Một ứng dụng desktop có thể **xem, chú thích, tổ chức trang, và
|
||||
- Thêm text box mới, đổi font/size/màu.
|
||||
**DoD:** sửa được text 1 dòng & 1 đoạn trên ≥80% file mẫu thường; thêm/xoá/di chuyển ảnh; lưu mở lại đúng; tiếng Việt hiển thị & sửa đúng dấu; có test corpus chuyên cho edit.
|
||||
|
||||
## Phase 5 — Bảo mật & Chữ ký ✅ Iteration 1 HOÀN TẤT (mã hoá+quyền, gỡ mật khẩu, redaction thật, xoá metadata — xem [docs/15-phase5-summary.md](15-phase5-summary.md)) · Iteration 2: chữ ký số
|
||||
## Phase 5 — Bảo mật & Chữ ký ✅ HOÀN TẤT (mã hoá+quyền, gỡ mật khẩu, redaction thật + tỉa ký tự, xoá metadata, **chữ ký số PKCS#7/PAdES + xác thực**, lưu tối ưu — xem [docs/15-phase5-summary.md](15-phase5-summary.md))
|
||||
**Mục tiêu:** Tính năng đáng tiền cho doanh nghiệp.
|
||||
- Mật khẩu mở/permission; mã hoá **AES-256**; xoá mật khẩu.
|
||||
- **Redaction thật** (xoá nội dung + ảnh + metadata, không chỉ vẽ đè) + kiểm chứng đã xoá.
|
||||
|
||||
@@ -100,7 +100,7 @@ Xếp theo mức độ ảnh hưởng trải nghiệm:
|
||||
### 3.5 Các tính năng Foxit chưa bắt đầu (không phải rào cản kỹ thuật)
|
||||
| Nhóm | Đường đi đã chốt trong roadmap | Rủi ro công nghệ |
|
||||
|---|---|---|
|
||||
| Bảo mật, redaction, chữ ký số PAdES (Phase 5) | QPDF (mã hoá AES-256 sẵn), redaction = xoá object thật (đã có nền edit.rs), ký số qua `cryptographic-message-syntax`/`rustls` + incremental update | Trung bình — byte-range + incremental update phải chuẩn; có spec rõ, test bằng Acrobat |
|
||||
| ~~Bảo mật, redaction, chữ ký số PAdES (Phase 5)~~ ✅ ĐÃ LÀM | AES-256+quyền, redaction thật (tỉa ký tự), **chữ ký số PKCS#7/CMS + xác thực + phát hiện giả mạo** (`sign.rs`), lưu tối ưu — 62/62 test | Đã giải; còn lại timestamp/LTV/PFX/multi-sig (docs/15 mục 6.6) |
|
||||
| Form AcroForm (Phase 6) | PDFium có FPDF_FORMFILL đầy đủ (fill/flatten); tạo field mới bằng lopdf | Thấp-trung bình |
|
||||
| OCR (Phase 7) | Tesseract (tiếng Việt có traineddata chuẩn) + lớp text ẩn — kỹ thuật giống watermark.rs đã làm | Thấp, chủ yếu là chất lượng tiền xử lý ảnh |
|
||||
| Convert Office↔PDF (Phase 7) | LibreOffice headless; PDF→Word "đủ dùng" trước | PDF→Word giữ layout hoàn hảo là bài khó với CẢ Foxit — đặt kỳ vọng "tương đương Foxit" chứ không hơn |
|
||||
@@ -133,13 +133,16 @@ Foxit hơn" — chi phí khổng lồ, không giải quyết gap nào ở mục
|
||||
(iteration 3) · Bảo mật iteration 1 ✅ (mã hoá AES-256 + quyền, gỡ mật khẩu,
|
||||
redaction thật kiểm chứng được, xoá metadata — docs/15)**.
|
||||
|
||||
**Phase 5 đã HOÀN TẤT** (iter 1+2): mã hoá+quyền, gỡ mật khẩu, redaction thật
|
||||
+ tỉa ký tự, xoá metadata, **chữ ký số PKCS#7/PAdES + xác thực**, lưu tối ưu.
|
||||
|
||||
Thứ tự đề xuất tiếp theo, bám giá trị người dùng:
|
||||
1. **Phase 5 Iteration 2**: chữ ký số PAdES + xác thực; "Lưu tối ưu" (mục
|
||||
3.3: subset font, dọn object rác); redact tỉa theo ký tự.
|
||||
2. Phase 6 Form → Phase 7 OCR/Convert → Phase 8 phát hành (theo roadmap).
|
||||
1. **Phase 6 — Form (AcroForm)**: điền form (PDFium FPDF_FORMFILL), flatten,
|
||||
tạo field text/checkbox/radio/dropdown, import/export FDF/CSV.
|
||||
2. Phase 7 OCR/Convert → Phase 8 phát hành (theo roadmap).
|
||||
3. Song song, rải theo từng phase: mở rộng font matching (3.4), nấc 1 của
|
||||
hiệu năng phiên sửa (3.2) khi chạm file lớn thực tế, và v2 của reflow
|
||||
(justify/xoay — mục 3.1).
|
||||
hiệu năng phiên sửa (3.2) khi chạm file lớn thực tế, v2 của reflow
|
||||
(justify/xoay — mục 3.1), và nâng chữ ký (timestamp/LTV/PFX/multi-sig).
|
||||
|
||||
## 6. Checklist FINAL TARGET & RULE cho chính tài liệu này
|
||||
- [x] Đối chiếu từng tính năng với hành vi Foxit làm chuẩn nghiệm thu.
|
||||
|
||||
+63
-12
@@ -1,8 +1,9 @@
|
||||
# 15 — Tổng kết Phase 5 (Bảo mật) · Iteration 1
|
||||
# 15 — Tổng kết Phase 5 (Bảo mật) · Iteration 1 + 2
|
||||
|
||||
> Trạng thái: **mã hoá + permissions, gỡ mật khẩu, redaction THẬT, xoá
|
||||
> metadata — hoàn tất, có test kiểm chứng nội dung thật sự biến mất.**
|
||||
> Chữ ký số (PAdES) là Iteration 2 — kế hoạch ở mục 5.
|
||||
> Trạng thái: **HOÀN TẤT Phase 5.** Iter 1: mã hoá + permissions, gỡ mật khẩu,
|
||||
> redaction THẬT, xoá metadata. Iter 2: **chữ ký số PKCS#7/PAdES (ký + xác
|
||||
> thực + phát hiện giả mạo), redaction tỉa theo KÝ TỰ, lưu tối ưu.**
|
||||
> 62/62 test engine xanh (ngoài 2 fixture qpdf Linux). Chi tiết iter 2 ở mục 6.
|
||||
|
||||
## 1. Khảo sát Foxit (chuẩn nghiệm thu)
|
||||
- **Protect › Password Protect**: user/owner password, AES-256, tick quyền
|
||||
@@ -70,11 +71,61 @@
|
||||
- Chưa xoá "hidden information" dạng attachment/script/comment ẩn — gộp
|
||||
vào Iteration 2.
|
||||
|
||||
## 5. Iteration 2 (kế tiếp của Phase 5) — Chữ ký số PAdES + Lưu tối ưu
|
||||
1. **Ký số**: tạo chữ ký PAdES-B (CMS/PKCS#7 qua crate `cms`/`rsa`/`p256`),
|
||||
ghi `/ByteRange` + placeholder `/Contents`, incremental update để không
|
||||
phá chữ ký cũ; xác thực bằng Acrobat làm DoD. Đọc chứng chỉ PFX/PKCS#12.
|
||||
2. **Xác thực chữ ký** khi mở (hiện trạng thái valid/invalid).
|
||||
3. **Lưu tối ưu** (từ docs/14 mục 3.3): subset font nhúng theo glyph dùng
|
||||
thật + `qpdf --object-streams=generate` dọn object rác sau edit.
|
||||
4. Redact tỉa theo ký tự (mục 4) + quét "hidden info" còn lại.
|
||||
## 5. (Đã thực hiện — xem mục 6.) Kế hoạch iteration 2 ban đầu
|
||||
|
||||
## 6. Iteration 2 — Chữ ký số + redact ký tự + lưu tối ưu (ĐÃ LÀM)
|
||||
|
||||
### 6.1 Chữ ký số PKCS#7/PAdES (`sign.rs`)
|
||||
- **`generate_self_signed_id(cn, out.pem)`**: tạo Digital ID tự ký RSA-2048 +
|
||||
X.509 (rcgen), ghi PEM bundle (cert + private key) — người dùng ký thử ngay
|
||||
không cần CA; có PFX/PEM thật thì nạp thẳng.
|
||||
- **`sign_pdf(input, id.pem, reason, name, output)`** đúng cơ chế Adobe:
|
||||
1. Chuẩn hoá qua qpdf → lopdf dựng signature dict
|
||||
(`/Type/Sig /SubFilter/adbe.pkcs7.detached`) với `/ByteRange` +
|
||||
`/Contents` placeholder, field chữ ký (Widget vô hình) + AcroForm/SigFlags.
|
||||
2. Serialize → định vị offset thật, vá `/ByteRange` (phần hex `<...>` của
|
||||
Contents bị loại khỏi digest, 2 dấu `<` `>` vẫn nằm trong vùng ký).
|
||||
3. SHA-256 trên 2 đoạn ByteRange → **CMS SignedData detached** (crate `cms`,
|
||||
signed attrs gồm messageDigest + contentType, ký RSA-SHA256) → nhét DER
|
||||
vào Contents.
|
||||
- **`verify_signatures(input)`**: với mỗi chữ ký — parse ByteRange/Contents,
|
||||
băm lại, kiểm (a) chữ ký RSA hợp lệ trên signed attrs, (b) messageDigest
|
||||
khớp digest file, (c) chữ ký phủ TOÀN BỘ file. `is_valid()` = cả 3 đạt.
|
||||
- Bài học: hex Contents có padding '0' → phải cắt DER về đúng độ dài (đọc
|
||||
length trường DER) trước khi parse; `/Contents` của TRANG (tham chiếu
|
||||
`N 0 R`) phải bỏ qua, chỉ nhận `/Contents <hex>` của chữ ký.
|
||||
|
||||
### 6.2 Redaction tỉa theo KÝ TỰ (`redact.rs`)
|
||||
- Text object bị vùng redact chạm MỘT PHẦN: dùng `page_char_boxes` (Phase 1)
|
||||
xác định ký tự nào nằm trong vùng, **giữ các đoạn ký tự 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 an toàn: text XOAY/nghiêng (matrix b,c ≠ 0) hoặc không đọc được font →
|
||||
xoá NGUYÊN object (thà thừa còn hơn sót). Ảnh vẫn bôi đen pixel như iter 1.
|
||||
|
||||
### 6.3 Lưu tối ưu (`qpdf::optimize_save`)
|
||||
- `qpdf --object-streams=generate --compress-streams=y`: nén + dọn object mồ
|
||||
côi (rác sau edit/redact — object đã tách khỏi trang nhưng còn trong file).
|
||||
|
||||
### 6.4 UI + Tauri
|
||||
- Thanh Bảo mật thêm: **🪪 Tạo Digital ID**, **✍️ Ký số** (dialog tên/lý do/
|
||||
chọn .pem → tự kiểm tra sau khi ký), **🔎 Kiểm tra chữ ký** (modal bảng
|
||||
trạng thái hợp lệ/không + lý do), **📦 Lưu tối ưu**.
|
||||
- Commands: `sig_create_id`, `sig_sign`, `sig_verify`, `security_optimize`,
|
||||
`pick_any_file`, `pick_save_pem`.
|
||||
|
||||
### 6.5 Test iteration 2 (7 mới → tổng 62/62)
|
||||
- `sign_then_verify_is_valid` — tạo ID → ký → xác thực hợp lệ, đúng tên người ký.
|
||||
- `tampering_after_signing_is_detected` — lật 1 byte vùng đã ký → chữ ký KHÔNG
|
||||
hợp lệ (chứng minh phát hiện giả mạo, cốt lõi của chữ ký số).
|
||||
- `verify_reports_none_for_unsigned` — file chưa ký: 0 chữ ký.
|
||||
- `redact_removes_text_content_for_real` (nâng): chuỗi mật biến mất nhưng
|
||||
phần cùng dòng ngoài vùng **vẫn còn** (tỉa theo ký tự).
|
||||
- `optimize_save_keeps_content_and_not_larger`.
|
||||
|
||||
### 6.6 Giới hạn còn lại (v-sau, không chặn dùng)
|
||||
- Chữ ký tự ký (self-signed) → Acrobat báo "hợp lệ nhưng chưa tin cậy chuỗi
|
||||
CA"; cần cài cert vào Trusted hoặc dùng CA thật. Cơ chế byte-range/CMS đã
|
||||
chuẩn để Acrobat xác thực toán học.
|
||||
- Chưa timestamp (PAdES-T) và LTV; chưa đọc PFX/PKCS#12 (mới PEM).
|
||||
- Ký nhiều lần giữ chữ ký cũ (multi-sig incremental) chưa làm — mới ký lần đầu.
|
||||
- Redact ký tự: đoạn XOAY vẫn xoá cả object (an toàn).
|
||||
|
||||
@@ -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ả> —
|
||||
|
||||
Reference in New Issue
Block a user