
Pada suatu waktu, implementasi algoritma kriptografi domestik di perpustakaan libgcrypt sangat menginspirasi saya. Menjadi mungkin untuk menggunakan
algoritma ini di Kleopatra dan di Kmail dan GnuPg secara umum, untuk mempertimbangkan perpustakaan libgcrypt sebagai
alternatif untuk openssl dengan mesin GOST. Dan semuanya hebat sampai Jumat lalu.
Saya diminta untuk memverifikasi tanda tangan elektronik GOST R 34.10-2012-256 untuk dokumen yang dibuat di Microsoft Office di MS Windows. Dan saya memutuskan untuk memeriksanya di Kleopatra (Saya punya Linux). Dan bagaimana menurut Anda, tanda tangannya ternyata salah. Keraguan merayap masuk. Saya memutuskan untuk memeriksa
openssl dengan mesin
GOST . Tanda tangan telah berhasil diverifikasi. Segera menandatangani ulang file di Kleopatra dan tidak lulus tes pada MS Windows. Kami mencoba masuk dan memverifikasi file lain, semuanya baik-baik saja. Pertanyaannya adalah apa masalahnya? Karena hash dokumen terlibat dalam penandatanganan, diputuskan untuk memeriksa perhitungan hash oleh berbagai program. Pertama-tama,
implementasi open-source untuk stribog terlibat :
Dan kemudian ada kejutan! Hash yang dihitung oleh "implementasi Degtyarev yang terkenal" bertepatan dengan hash yang dihitung dalam openssl dengan GOST dari endine, tetapi tidak cocok dengan nilai hash yang dihitung menggunakan libgcrypt dan libressl.
Betapa
ru_crypt benar ketika ia menulis di awal
artikelnya :
Saya segera memperingatkan Anda bahwa saya tidak memeriksa kebenaran implementasi.
Omong-omong, standar pada GOST R 34.10-2012 juga mengatakan bahwa contoh kontrol hanya untuk referensi. Harus dipahami dengan jelas bahwa kasus uji tidak menjamin bahwa implementasi yang berbeda memberikan hasil yang sama untuk semua kesempatan.
Untuk menghitung nilai hash, utilitas berikut digunakan:
1) openssl
$ openssl dgst [βmd_gost12_256|-md_gost12_512] <file>
2) Libresl
$libressl dgst [βstreebog256|streebog512] <file>
3) libgcrypt
$gchash [stribog256|stribog512] <file>
4) Implementasi Degtyarev yang terkenal
$gost3411-2012 [-2|-5] <file>
Berikut ini juga hal yang menarik: dalam transkripsi stribogs Latin menulis baik stribog atau streebog. Akan menyenangkan untuk datang ke keseragaman. Dan sepertinya ini adalah fungsi yang berbeda. Secara pribadi, saya lebih suka opsi pertama - stribog.
Saya membutuhkan arbiter.
Sebagai arbiter, diputuskan untuk menggunakan token PKCS # 11 RUTOKEN EDS-2.0, yang mendukung standar kriptografi Rusia GOST R 34.10-2012, GOST R 34.11-2012, VKO GOST R 34.10-2012 (RFC 7836) dengan panjang kunci 256 dan 512 bit , dan disertifikasi oleh FSB Rusia sebagai sarana perlindungan informasi kriptografi (CPSI) dan sarana tanda tangan elektronik.
Selain itu, token RUTOKEN EDS-2.0 didistribusikan secara luas dan banyak
sertifikat toko untuk akses ke layanan
Negara dan portal lainnya.
Untuk menghitung nilai hash pada token, kita akan menggunakan skrip test_digest.tcl di
Tcl :
test_digest.tcl #! /usr/bin/env tclsh package require pki lappend auto_path . package require pki::pkcs11 # PKCS#11 set pkcs11_module "/usr/local/lib64/librtpkcs11ecp_2.0.so" #set pkcs11_module "/usr/local/lib64/libls11sw2016.so" puts "Connect the Token and press Enter" gets stdin yes set handle [pki::pkcs11::loadmodule $pkcs11_module] set slots [pki::pkcs11::listslots $handle] foreach slotinfo $slots { set slotid [lindex $slotinfo 0] set slotlabel [lindex $slotinfo 1] set slotflags [lindex $slotinfo 2] if {[lsearch -exact $slotflags TOKEN_PRESENT] != -1} { set token_slotlabel $slotlabel set token_slotid $slotid # break } } proc usage {use error} { puts "Copyright(C) Orlov Vladimir (http://soft.lissi.ru) 2019" if {$use == 1} { puts $error puts "Usage:\ndigest <stribog256|stribog512> <file for digest>\n" } } set countcert [llength $argv] if { $countcert != 2 } { usage 1 "Bad usage!" exit } set digest_algo [lindex $argv 0] if {$digest_algo != "stribog256" && $digest_algo != "stribog512"} { usage 1 "Bad usage!" exit } set file [lindex $argv 1] if {![file exists $file]} { usage 1 "File $file not exist" exit } puts "Loading file for digest: $file" set fd [open $file] chan configure $fd -translation binary set cert_user [read $fd] close $fd if {$cert_user == "" } { usage 1 "Bad file: $file" exit } set aa [dict create pkcs11_handle $handle pkcs11_slotid $token_slotid] set digest_hex [pki::pkcs11::digest $digest_algo $cert_user $aa] puts "digest_hex=\n$digest_hex" exit
Kapan perbedaan implementasi ini muncul? Sejauh ini, telah dimungkinkan untuk menentukan bahwa perbedaan ini terjadi ketika menghitung hash file doc yang dibuat di MS Office. Selain itu, hash dari 143 byte pertama dianggap sama, dan ketika menghitung hash dari 144 byte, nilainya berbeda.
143 byte pertama dalam tampilan heksadesimal seperti ini:
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000002400000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Simpan di file Doc1_143_hex.txt.
144 byte pertama dalam tampilan heksadesimal seperti ini:
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000002400000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Simpan di file Doc1_144_hex.txt.
Lebih mudah menggunakan skrip hex2bin.tcl untuk menerjemahkan dari bentuk heksadesimal ke biner:
#!/usr/bin/tclsh proc usage {use error} { if {$use == 1} { puts $error puts "Usage:\nhex2bin <file with hex> <file for bin>\n" } } set countcert [llength $argv] if { $countcert != 2 } { usage 1 "Bad usage!" exit } set file [lindex $argv 0] if {![file exists $file]} { usage 1 "File $file not exist" exit } set fd [open $file] chan configure $fd -translation binary set cert_user [read $fd] close $fd if {$cert_user == "" } { usage 1 "Bad file with hex: $file" exit } set cert_user [binary format H* $cert_user] set fd [open [lindex $argv 1] w] chan configure $fd -translation binary puts -nonewline $fd $cert_user close $fd
Ubah kode heksadesimal menjadi biner:
$./hex2bin Doc1_143_hex.txt Doc1_143.bin $./hex2bin Doc1_144_hex.txt Doc1_144.bin $
Sekarang Anda dapat memeriksa bagaimana hash dihitung dengan berbagai implementasi:
Pertama, pertimbangkan hash untuk file Doc1_143, bin:
$ ./openssl dgst -md_gost12_256 Doc1_143.bin md_gost12_256(Doc1_143.bin)= e63bd3edc44f9a03fece4198b690a8ae291b973ae61b2a0f512a9a7479431a63 $ ./libressl dgst -streebog256 Doc1_143.bin streebog256(Doc1_143.bin)= e63bd3edc44f9a03fece4198b690a8ae291b973ae61b2a0f512a9a7479431a63 $ ./gchash stribog256 Doc1_143.bin e63bd3edc44f9a03fece4198b690a8ae291b973ae61b2a0f512a9a7479431a63 Doc1_143.bin $ ./gost3411-2012 -2 Doc1_143.bin GOST R 34.11-2012 (Doc1_143.bin) = e63bd3edc44f9a03fece4198b690a8ae291b973ae61b2a0f512a9a7479431a63 $
Momen paling penting telah tiba, momen verifikasi pada sistem perlindungan informasi kriptografi bersertifikat:
$ ./test_digest.tcl stribog256 Doc1_143.bin Connect the Token and press Enter Loading file for digest: Doc1_143.bin digest_hex= e63bd3edc44f9a03fece4198b690a8ae291b973ae61b2a0f512a9a7479431a63 $
Seperti yang Anda lihat, semuanya berakhir untuk selamanya.
Mari kita lihat apa yang terjadi pada file Doc1_144.bin:
$ ./openssl dgst -md_gost12_256 Doc1_144.bin md_gost12_256(Doc1_144.bin)= c766085540caaa8953bfcf7a1ba220619cee50d65dc242f82f23ba4b180b18e0 $ ./libressl dgst -streebog256 Doc1_144.bin streebog256(Doc1_144.bin)= 3965c99777eb1b64c783496fe950aa6540bc7baa399a3889995145afbdd76250 $
Itu saja, nilai-nilai hash tidak cocok. Untuk kemurnian percobaan, kami memeriksa implementasi yang tersisa:
$ ./gchash_1.7.10 stribog256 Doc1_144.bin 3965c99777eb1b64c783496fe950aa6540bc7baa399a3889995145afbdd76250 Doc1_144.bin $ ./gost3411-2012 -2 Doc1_144.bin GOST R 34.11-2012 (Doc1_144.bin) = c766085540caaa8953bfcf7a1ba220619cee50d65dc242f82f23ba4b180b18e0 $ ./test_digest.tcl stribog256 Doc1_144.bin Connect the Token and press Enter Loading file for digest: Doc1_144.bin digest_hex= c766085540caaa8953bfcf7a1ba220619cee50d65dc242f82f23ba4b180b18e0 $
Hash yang dihitung oleh "implementasi Degtyarev yang terkenal" cocok dengan hash yang dihitung dalam openssl dengan mesin GOST, tetapi tidak cocok dengan nilai hash yang dihitung menggunakan libgcrypt dan libressl.
Kami mendapatkan hasil yang serupa jika kami mempertimbangkan hash stribog512.
Ada satu kesimpulan. Jika Anda ingin tanda tangan elektronik GOST R 34.10-2012 yang dihasilkan oleh libressl dan libgcrypt (atau mungkin yang lain) kompatibel dengan openssl dan, yang paling penting, dengan perlindungan informasi kriptografi yang disertifikasi dalam sistem sertifikasi FSB Rusia, gunakan yang terverifikasi implementasi untuk komputasi hash. Saya berharap publikasi ini akan menghindari banyak kesalahpahaman, dan penulis penerapan stribog di libressl, libgrypt dan mungkin orang lain akan membantu menghilangkan perbedaan ini. Hari ini, saya harus mengakui, dalam produk di atas, sebenarnya bukan GOST R 34.10-2012 yang diterapkan, tetapi sesuatu yang lain. Ini adalah algoritma yang berbeda. Contoh uji yang diberikan mungkin akan baik untuk dimasukkan sebagai contoh uji untuk GOST R 34.10-2012. Dan saya akan mengedit libgcrypt untuk Kleopatra dan KMail. Legenda Cleopart dan kriptografi Rusia belum selesai.
PS Artikel sudah siap ketika kolega saya mengatakan bahwa perbedaan antara implementasi muncul ketika urutan 0xFF yang cukup panjang ditemukan. Dia, urutan ini, by the way, hadir di awal file doc dari MS Office. Saya memeriksa, apa adanya. File tersebut mengandung 189 byte.