💡 Contoh kerja penuh tersedia di GitHub:
sign-docx-dengan-sertifikat-mldsa-python
Pendahuluan
Tandatangani sebuah kontrak sore ini dengan RSA-2048 dan Anda telah membuat janji yang harus bertahan selama kontrak tersebut relevan. Jika itu dua puluh atau tiga puluh tahun — dan untuk akta, formulir persetujuan, serta persetujuan teknik seringkali memang demikian — janji tersebut harus melampaui masa pakai algoritma. Serangan tidak perlu ada hari ini. Serangan harus ada sebelum dokumen berhenti relevan, dan kemudian siapa pun yang memegang kunci publik dapat menurunkan kunci privat dan menandatangani atas nama Anda.
Penandatanganan dokumen pasca-kuantum adalah fitur GroupDocs.Signature untuk Python yang menggantikan janji tersebut dengan yang dibangun di atas ML-DSA, algoritma tanda tangan yang distandarisasi NIST sebagai FIPS 204 pada tahun 2024. Dukungan format Word hadir di GroupDocs.Signature 26.9, dan ia menggunakan API yang sudah Anda miliki: sebuah kunci ML-DSA berada dalam PFX dan dimasukkan ke DigitalSignOptions persis seperti kunci RSA.
Panduan ini menandatangani sebuah DOCX dalam empat langkah, membandingkan tiga tingkat keamanan pada output yang diukur, memverifikasi tanda tangan hanya dengan sertifikat publik, dan mengakhiri dengan dua batasan yang penting diketahui sebelum Anda berkomitmen.
Mengapa Ini Lebih Penting Daripada Migrasi Biasa
Migrasi tanda tangan berbeda dengan migrasi enkripsi dalam satu hal yang membuatnya lebih mudah ditunda dan lebih canggung untuk diperbaiki.
Dengan enkripsi, masalah “panen‑sekarang‑dekripsi‑nanti” bersifat langsung: apa pun yang disadap hari ini dapat disimpan dan dibuka nanti. Dengan tanda tangan, tidak ada apa pun yang sudah Anda tandatangani menjadi dapat dipalsukan secara retroaktif — tetapi tidak ada apa pun yang Anda tandatangani tetap terbukti milik Anda juga, begitu kunci dapat diturunkan dari sertifikat yang dimiliki semua orang. Menandatangani ulang satu dekade dokumen arsip dengan kunci baru memang memungkinkan dan tidak ada yang ingin menjadi orang yang merencanakannya.
Itulah mengapa saran praktisnya bersifat sempit, bukan menyeluruh: migrasikan dokumen yang masa retensinya lama, sisakan yang lainnya. Beberapa profil sudah menetapkan standar — CNSA 2.0 mengharuskan ML-DSA-87 untuk sistem keamanan nasional — dan bagi semua orang lainnya faktor penentu adalah berapa lama file harus tetap dapat dipertahankan.
Prasyarat
- Python 3.9 atau lebih baru pada interpreter 64‑bit — paket ini menyertakan runtime .NET yang dibundel dan tidak memiliki wheel 32‑bit
- GroupDocs.Signature untuk Python via .NET 26.10.0, dengan lisensi sementara gratis untuk menghapus batas evaluasi
- Sebuah sertifikat ML-DSA berupa PFX yang dilindungi kata sandi, serta dokumen Word yang akan ditandatangani
Instalasi
pip install groupdocs-signature-net
Langkah 1 - Menandatangani dengan sertifikat ML-DSA
Sertifikat melakukan semua pekerjaan. Panggilan yang dibuat sama seperti yang Anda tulis untuk RSA:
with signature.Signature(source_path) as sign:
options = DigitalSignOptions(pfx_path)
options.password = CERTIFICATE_PASSWORD
result = sign.sign(output_path, options)
Itulah seluruh cerita adopsi untuk kode yang sudah menandatangani: arahkan DigitalSignOptions ke PFX yang berbeda. Tidak ada opsi baru, tidak ada parameter algoritma terpisah, tidak ada cabang untuk pasca‑kuantum.
Membaca penanda tangan kembali memerlukan satu langkah lagi, dan berisi satu perangkap khusus Python dalam seluruh latihan ini:
for created in result.succeeded:
certificate = getattr(created, "certificate", None)
subject = getattr(certificate, "subject", None)
if subject:
return str(subject)
Sertifikat pada sebuah DigitalSignature adalah objek jembatan yang menyelesaikan atribut secara dinamis. certificate.subject mengembalikan CN=GroupDocs.Signature MLDSA65 test, sementara dir() pada objek yang sama tidak menampilkan apa‑apa. Saya memeriksanya dengan dir() terlebih dahulu, menyimpulkan subjek tidak terekspos, dan itu ternyata salah — jadi jika Anda melakukan introspeksi sebelum membaca, Anda akan melewatkan nilai yang ada.
Langkah 2 - Membandingkan tiga tingkat keamanan
ML-DSA hadir dalam tiga set parameter, dan dipilih dengan menyerahkan sertifikat yang berbeda:
levels = (
("ML-DSA-44", MLDSA44_PFX),
("ML-DSA-65", MLDSA65_PFX),
("ML-DSA-87", MLDSA87_PFX),
)
for level, pfx_path in levels:
with signature.Signature(source_path) as sign:
options = DigitalSignOptions(pfx_path)
options.password = CERTIFICATE_PASSWORD
sign.sign(output_path, options)
sizes[f"{level} -> {file_name}"] = os.path.getsize(output_path)
Ini adalah langkah yang layak dijalankan, karena trade‑off biasanya dijelaskan tetapi jarang diukur. Dari kontrak sumber berukuran 132 KB:
| Level | Kategori keamanan NIST | File yang ditandatangani | Lebih besar dari yang terkecil |
|---|---|---|---|
| ML-DSA-44 | 2 | 138,202 bytes | - |
| ML-DSA-65 | 3 | 140,650 bytes | +2,448 bytes |
| ML-DSA-87 | 5 | 143,971 bytes | +5,769 bytes |
Kurang dari 6 KB memisahkan tingkat terlemah dari yang terkuat. Pada kontrak, perbedaan itu tidak berarti apa‑apa, yang menyederhanakan keputusan: gunakan ML-DSA-65 sebagai default, ML-DSA-87 bila sebuah profil menuntut kategori 5 atau bila ukuran tidak relevan, dan ML-DSA-44 hanya ketika Anda menandatangani begitu banyak file sehingga kilobyte terakumulasi menjadi sesuatu yang nyata.
Langkah 3 - Memverifikasi dengan sertifikat publik
Seorang penerima hanya membutuhkan sertifikat publik penanda tangan dan tidak ada yang rahasia:
with signature.Signature(signed_path) as sign:
options = DigitalVerifyOptions(certificate_path)
if password is not None:
options.password = password
return sign.verify(options).is_valid
Contoh memanggil ini dua kali pada file yang sama: sekali dengan mldsa65.cer, setengah publik dari kunci penandatangan, dan sekali dengan PFX penanda tangan yang berbeda. Yang pertama mengembalikan True, yang kedua False. Perhatikan bahwa sertifikat yang salah menghasilkan False alih‑alih melempar pengecualian — “ditandatangani oleh orang lain” adalah jawaban yang harus ditangani kode Anda, bukan sebuah exception. Pemeriksaan mencakup konten dokumen bersama nomor seri dan sidik jari sertifikat, sehingga file yang diedit setelah penandatanganan juga gagal.
Langkah 4 - Membaca tanda tangan dari dokumen
Ketika sebuah dokumen yang ditandatangani tiba dan Anda tidak tahu sertifikat apa yang diharapkan:
with signature.Signature(signed_path) as sign:
found = sign.search(SignatureType.DIGITAL)
for item in found:
print(item.sign_time, item.is_valid)
search dengan SignatureType.DIGITAL mengembalikan objek DigitalSignature yang membawa sertifikat, waktu penandatanganan, dan flag validitas. Sebuah dokumen Word dapat memuat beberapa tanda tangan, termasuk campuran RSA dan ML-DSA, dan masing‑masing dilaporkan dengan sertifikat dan validitasnya sendiri.
Apakah ini mengubah cara penerima memverifikasi?
Tidak dalam cara apa pun yang akan mereka perhatikan. Seorang penerima masih hanya membutuhkan sertifikat publik penanda tangan, masih melewatkannya ke DigitalVerifyOptions yang sama, dan masih menerima nilai boolean kembali. Tidak ada bagian dari jalur verifikasi yang khusus untuk ML-DSA. Satu‑satunya tempat algoritma terlihat adalah indikator tanda tangan Microsoft Word sendiri, yang mungkin belum mengenali ML-DSA karena formatnya belum memiliki pengidentifikasi standar.
Aplikasi Dunia Nyata
Kontrak dengan Retensi Panjang
Kasus paling jelas. Sebuah dokumen yang harus tetap dapat diverifikasi selama dekade ditandatangani sekali, sekarang, dengan ML-DSA-65 atau ML-DSA-87, dan tidak pernah perlu ditandatangani ulang karena algoritmanya sudah usang.
Lingkungan yang diatur dengan profil bernama
Di mana CNSA 2.0 atau profil serupa berlaku, tingkatnya bukan keputusan subjektif — ML-DSA-87 adalah keharusan, dan satu‑satunya pertanyaan teknik adalah apakah formatnya didukung.
Jalur campuran selama migrasi
Menandatangani dokumen baru pasca‑kuantum sambil membiarkan arsip tetap tidak berubah adalah keadaan menengah yang sangat masuk akal, dan pelaporan search tiap tanda tangan secara terpisahlah yang membuatnya dapat dikelola.
Praktik Terbaik dan Tips
- Migrasikan berdasarkan retensi, bukan volume. Dokumen yang membutuhkan ini adalah yang berumur lama; kwitansi yang hanya penting selama 90 hari tidak termasuk.
- Gunakan ML-DSA-65 secara default kecuali sebuah profil menyebutkan tingkat tertentu, dan jangan terlalu khawatir tentang perbedaan ukuran — kurang dari 6 KB per tanda tangan.
- Pertahankan RSA bila penerima memverifikasi di Word. Tanda tangan yang benar namun ditandai sebagai masalah oleh pembaca lebih buruk daripada migrasi yang lebih lambat.
- Ganti sertifikat contoh. File PFX contoh bersifat self‑signed dengan kata sandi yang dipublikasikan, sehingga apa pun yang ditandatangani dengan mereka tidak membuktikan apa‑apa.
- Verifikasi setelah menandatangani di setiap jalur, menggunakan sertifikat publik yang akan dimiliki penerima.
Memecahkan Masalah Umum
Microsoft Word tidak menampilkan tanda tangan sebagai valid. Diharapkan untuk saat ini: belum ada pengidentifikasi XML‑DSig standar untuk ML-DSA, sehingga Word mungkin tidak mengenalinya meskipun tanda tangan benar dan GroupDocs.Signature memverifikasinya. Verifikasi di jalur Anda sendiri, dan pertahankan RSA untuk dokumen yang penerimanya mengandalkan indikator Word.
Pemanggilan penandatanganan menolak PDF atau spreadsheet. Penandatanganan ML-DSA mencakup format Word — DOCX, DOC, ODT, dan sejenisnya. PDF, spreadsheet, dan presentasi belum didukung, dan masih harus ditandatangani dengan RSA atau ECDSA seperti sebelumnya.
Subjek sertifikat kembali kosong. Hampir selalu perangkap dir() dari Langkah 1: atribut diselesaikan secara dinamis, jadi bacalah alih‑alih menguji keberadaannya terlebih dahulu.
Kesimpulan
Perubahan kode hanyalah perubahan sertifikat, yang merupakan bagian yang membuatnya layak dilakukan sebelum menjadi mendesak. Tandatangani dokumen Word yang berumur lama dengan ML-DSA-65, gunakan ML-DSA-87 bila sebuah profil memerlukannya, verifikasi dengan sertifikat publik, dan pertahankan RSA bila format atau pembaca memerlukannya.
Jalankan contoh terhadap salah satu kontrak Anda sendiri dan tiga ukuran akan memberi tahu Anda, dalam byte, persis berapa biaya tingkat terkuat yang tersedia. Pada file yang saya uji, biaya tambahan adalah 5,769 byte.