
有一次,在libgcrypt库中实现国内加密算法给我很大的启发。 通常,可以在Kleopatra中以及在Kmail和GnuPg中使用
这些算法 ,以将libgcrypt库考虑为具有GOST引擎的
openssl的
替代方法 。 直到上周五,一切都很棒。
我被要求验证在MS Windows上的Microsoft Office中创建的文档的GOST R 34.10-2012-256的电子签名。 我决定在Kleopatra(我有Linux)中进行检查。 您怎么看,签名证明是错误的。 怀疑逐渐蔓延。 我决定
使用GOST引擎检查
openssl 。 签名已成功验证。 紧急在Kleopatra中重新签名了文件,但该文件未通过MS Windows上的检查。 我们尝试签名并验证其他文件,一切都很好。 问题是出了什么问题? 由于文档哈希涉及签名,因此决定由其他程序检查哈希的计算。 首先,
涉及stribog的开源实现 :
然后发生了震惊! “著名的Degtyarev实现”计算出的哈希值与带有GOST端点的openssl中计算出的哈希值一致,但与使用libgcrypt和libressl计算出的哈希值不匹配。
ru_crypt在
文章开头写的
内容是多么正确:
我立即警告您,我没有检查实现的正确性。
顺便说一句,关于GOST R 34.10-2012的标准还规定,控制示例仅供参考。 必须清楚地理解,测试用例并不能保证在所有情况下不同的实现都给出相同的结果。
要计算哈希值,使用了以下实用程序:
1)openssl
$ openssl dgst [–md_gost12_256|-md_gost12_512] <file>
2)libressl
$libressl dgst [–streebog256|streebog512] <file>
3)libgcrypt
$gchash [stribog256|stribog512] <file>
4)Degtyarev的著名实现
$gost3411-2012 [-2|-5] <file>
这也是一件很有趣的事情:在拉丁语转录中,频闪笔写的是stribog或streebog。 达到统一会很好。 因此,这些似乎是不同的功能。 就个人而言,我更喜欢第一个选项-stribog。
我需要一名仲裁员。
作为仲裁员,决定使用PKCS#11令牌RUTOKEN EDS-2.0,该令牌支持俄罗斯密码标准GOST R 34.10-2012,GOST R 34.11-2012,VKO GOST R 34.10-2012(RFC 7836),密钥长度分别为256位和512位已获得俄罗斯FSB的认证,可作为加密信息保护(CPSI)和电子签名的手段。
此外,RUTOKEN EDS-2.0令牌已广泛分发,并且在其上
存储了许多
证书 ,以访问
国家服务和其他门户。
要计算令牌上的哈希值,我们将在
Tcl中使用test_digest.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
这种差异何时出现? 到目前为止,在计算在MS Office中创建的doc文件的哈希值时,可以确定出现这种差异。 此外,前143个字节的哈希被认为是相同的,并且从144个字节计算哈希时,值是不同的。
十六进制的前143个字节如下所示:
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000002400000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
将它们保存在文件Doc1_143_hex.txt中。
十六进制的前144个字节如下所示:
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000002400000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
将它们保存在文件Doc1_144_hex.txt中。
使用hex2bin.tcl脚本将十六进制转换为二进制形式很方便:
#!/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
将十六进制代码转换为二进制:
$./hex2bin Doc1_143_hex.txt Doc1_143.bin $./hex2bin Doc1_144_hex.txt Doc1_144.bin $
现在,您可以检查各种实现如何计算哈希值:
首先,考虑文件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 $
最重要的时刻已经到来,即在经过认证的密码信息保护系统上进行验证的时刻:
$ ./test_digest.tcl stribog256 Doc1_143.bin Connect the Token and press Enter Loading file for digest: Doc1_143.bin digest_hex= e63bd3edc44f9a03fece4198b690a8ae291b973ae61b2a0f512a9a7479431a63 $
如您所见,一切都结束了。
让我们看看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 $
就是这样,哈希值不匹配。 为了实验的纯洁,我们检查其余的实现:
$ ./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 $
“著名的Degtyarev实现”计算出的哈希值与使用GOST引擎在openssl中计算出的哈希值匹配,但与使用libgcrypt和libressl计算出的哈希值不匹配。
如果考虑散列stribog512,我们将得到类似的结果。
有一个结论。 如果您希望由libressl和libgcrypt(或其他厂商)生成的GOST R 34.10-2012电子签名与openssl实现兼容,并且最重要的是,与俄罗斯FSB认证系统中CIPF认证的实现兼容,请使用经过验证的计算哈希的实现。 我希望该出版物能够避免许多误解,并且在libressl,libgrypt和其他可能的版本中实现stribog的作者将有助于消除这些差异。 今天,我必须承认,在上述产品中,实现的实际上不是GOST R 34.10-2012,而是其他一些东西。 这是一种不同的算法。 给定的测试示例可能会很好地包含在GOST R 34.10-2012的测试示例中。 我将为Kleopatra和KMail编辑libgcrypt。 Cleopart和俄罗斯加密术的传说尚未完成。
PS当我的同事说当遇到足够长的0xFF序列时,实现之间的差异就出现了,这篇文章已经准备好了。 顺便说一下,她的顺序是出现在MS Office的doc文件的开头。 我按原样检查。 该文件包含189个字节。