Signature
DSA 的 ASN.1 整數問題
我正在嘗試按照本網站第 20 頁的指南在 python 中實現自己的 DSA 簽名檢查。
kp = 0x8df2a494492276aa3d25759bb06869cbeac0d83afb8d0cf7cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac49693dfbf83724c2ec0736ee31c80291 kq = 0xc773218c737ec8ee993b4f2ded30f48edace915f kg = 0x626d027839ea0a13413163a55b4cb500299d5522956cefcb3bff10f399ce2c2e71cb9de5fa24babf58e5b79521925c9cc42e9f6f464b088cc572af53e6d78802 ky = 0x19131871d75b1612a819f29d78d1b0d7346f7aa77bb62a859bfd6c5675da9d212d3a36ef1672ef660b8c7c255cc0ec74858fba33f44c06699630a76b030ee333 sh = 0xa9993e364706816aba3e25717850c26c9cd0d89d sr = 0x8bac1ab66410435cb7181f95b16ab97c92b341c0 ss = 0x41e2345f1f56df2458f426d155b4ba2db6dcd8c8 w = pow(ss, -1, kq) u1 = (sh * w ) % kq u2 = (sr * w ) % kq v = ((pow(kg, u1, kp) * pow(ky, u2, kp)) % kp) % kq print("v", hex(v), v) print("signature is (r = v):", sr == v)
它給出了真實的並按預期工作。然後知道私鑰,我決定將密鑰導出到 OpenSSL
key = DSA.construct((ky, kg, kp, kq, kx)) print(key.exportKey())
然後從範例中獲取公鑰、生成的證書和簽名的“abc”,並且在 OpenSSL 中的驗證也是有效的。我還使用 openssl asn1parse 嘗試從新簽名中獲取 r 和 s 。
929:d=5 hl=2 l= 9 cons: 序列
931:d=6 hl=2 l= 7 prim: 對象 :dsaWithSHA1 940:d=5 hl=2 l= 46 prim: OCTET STRING
$$ HEX DUMP $$:302C0214 0977C4B483B4C9E9620BA2679EBB7A03D020FB3B 0214 3E6E3616A1034D4D24E387A5FDC5FB77DD8362A4 我嘗試使用 0x0977C4B483B4C9E9620BA2679EBB7A03D020FB3B 作為 r 和 0x3E6E3616A1034D4D24E387A5FDC5FB77DD8362A4 作為 s 並且它不起作用。應該怎麼做才能從這個八位字節字元串中獲取 r 和 s?
先感謝您。
更新 1:什麼不起作用
kp = 0x8df2a494492276aa3d25759bb06869cbeac0d83afb8d0cf7cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac49693dfbf83724c2ec0736ee31c80291 kq = 0xc773218c737ec8ee993b4f2ded30f48edace915f kg = 0x626d027839ea0a13413163a55b4cb500299d5522956cefcb3bff10f399ce2c2e71cb9de5fa24babf58e5b79521925c9cc42e9f6f464b088cc572af53e6d78802 ky = 0x19131871d75b1612a819f29d78d1b0d7346f7aa77bb62a859bfd6c5675da9d212d3a36ef1672ef660b8c7c255cc0ec74858fba33f44c06699630a76b030ee333 sh = 0xa9993e364706816aba3e25717850c26c9cd0d89d sr = 0x0977C4B483B4C9E9620BA2679EBB7A03D020FB3B ss = 0x3E6E3616A1034D4D24E387A5FDC5FB77DD8362A4 w = pow(ss, -1, kq) u1 = ( sh * w ) % kq u2 = ( sr * w ) % kq v = ((pow(kg, u1, kp) * pow(ky, u2, kp)) % kp) % kq print("v", hex(v), v) print("signature is (r = v):", sr == v)
我檢查了簽名中的sha1摘要,它是一樣的
662:d=5 hl=4 l= 263 cons: cont [ 0 ] 666:d=6 hl=2 l= 24 cons: SEQUENCE 668:d=7 hl=2 l= 9 prim: OBJECT :contentType 679:d=7 hl=2 l= 11 cons: SET 681:d=8 hl=2 l= 9 prim: OBJECT :pkcs7-data 692:d=6 hl=2 l= 28 cons: SEQUENCE 694:d=7 hl=2 l= 9 prim: OBJECT :signingTime 705:d=7 hl=2 l= 15 cons: SET 707:d=8 hl=2 l= 13 prim: UTCTIME :220606200747Z 722:d=6 hl=2 l= 35 cons: SEQUENCE 724:d=7 hl=2 l= 9 prim: OBJECT :messageDigest 735:d=7 hl=2 l= 22 cons: SET 737:d=8 hl=2 l= 20 prim: OCTET STRING [HEX DUMP]:A9993E364706816ABA3E25717850C26C9CD0D89D ... 929:d=5 hl=2 l= 9 cons: SEQUENCE 931:d=6 hl=2 l= 7 prim: OBJECT :dsaWithSHA1 940:d=5 hl=2 l= 46 prim: OCTET STRING [HEX DUMP]:302C02140977C4B483B4C9E9620BA2679EBB7A03D020FB3B02143E6E3616A1034D4D24E387A5FDC5FB77DD8362A4
鑰匙似乎也一樣
0:d=0 hl=3 l= 240 cons: SEQUENCE 3:d=1 hl=3 l= 168 cons: SEQUENCE 6:d=2 hl=2 l= 7 prim: OBJECT :dsaEncryption 15:d=2 hl=3 l= 156 cons: SEQUENCE 18:d=3 hl=2 l= 65 prim: INTEGER :8DF2A494492276AA3D25759BB06869CBEAC0D83AFB8D0CF7CBB8324F0D7882E5D0762FC5B7210EAFC2E9ADAC32AB7AAC49693DFBF83724C2EC0736EE31C80291 85:d=3 hl=2 l= 21 prim: INTEGER :C773218C737EC8EE993B4F2DED30F48EDACE915F 108:d=3 hl=2 l= 64 prim: INTEGER :626D027839EA0A13413163A55B4CB500299D5522956CEFCB3BFF10F399CE2C2E71CB9DE5FA24BABF58E5B79521925C9CC42E9F6F464B088CC572AF53E6D78802 174:d=1 hl=2 l= 67 prim: BIT STRING 0000 - 00 02 40 19 13 18 71 d7-5b 16 12 a8 19 f2 9d 78 ..@...q.[......x 0010 - d1 b0 d7 34 6f 7a a7 7b-b6 2a 85 9b fd 6c 56 75 ...4oz.{.*...lVu 0020 - da 9d 21 2d 3a 36 ef 16-72 ef 66 0b 8c 7c 25 5c ..!-:6..r.f..|%\ 0030 - c0 ec 74 85 8f ba 33 f4-4c 06 69 96 30 a7 6b 03 ..t...3.L.i.0.k. 0040 - 0e e3 33
和私人的
0:d=0 hl=3 l= 198 cons: SEQUENCE 3:d=1 hl=2 l= 1 prim: INTEGER :00 6:d=1 hl=3 l= 168 cons: SEQUENCE 9:d=2 hl=2 l= 7 prim: OBJECT :dsaEncryption 18:d=2 hl=3 l= 156 cons: SEQUENCE 21:d=3 hl=2 l= 65 prim: INTEGER :8DF2A494492276AA3D25759BB06869CBEAC0D83AFB8D0CF7CBB8324F0D7882E5D0762FC5B7210EAFC2E9ADAC32AB7AAC49693DFBF83724C2EC0736EE31C80291 88:d=3 hl=2 l= 21 prim: INTEGER :C773218C737EC8EE993B4F2DED30F48EDACE915F 111:d=3 hl=2 l= 64 prim: INTEGER :626D027839EA0A13413163A55B4CB500299D5522956CEFCB3BFF10F399CE2C2E71CB9DE5FA24BABF58E5B79521925C9CC42E9F6F464B088CC572AF53E6D78802 177:d=1 hl=2 l= 22 prim: OCTET STRING [HEX DUMP]:02142070B3223DBA372FDE1C0FFC7B2E3B498B260614
該問題有以下正確之處:
- $ (p,q,g) $ = (
0x8df2…0291
,0xc773…915f
,0x626d…8802
) 是一組一致的 DSA-1024 參數: $ |p|=1024, $ , $ |q|=160, $ , $ p $ 和 $ q $ 是素數, $ p\bmod q=1, $ , $ 1<g<p, $ , $ g^q\bmod p=1, $ .- $ y $ =
0x1913…e333
是這些參數的一致公鑰值: $ 1<y<p, $ , $ y^q\bmod p=1 $ .- $ y $ 與私鑰值一致 $ x $ =
0x2070…0614
: $ g^x\bmod p=y, $ .- $ h $ =
0xa999…d89d
是 3 字節字節串的 SHA-1 雜湊,編碼abc
每個 UTF-8 的三個字元(或 ASCII 通過在零處添加一個高位來擴展為 8 位,或與兼容的許多 8 位字元集ASCII)。- $ (r,s) $ = (
0x0977…FB3B
,0x3E6E…62A4
) 是字節串中的一對 ASN.1 修飾的整數,302C02140977…62A4
並且與根據上述參數作為 DSA 簽名一致: $ 0<r<q $ 和 $ 0<s<q $ .- 除了缺少範圍檢查 $ r $ 和 $ s $ ,簽名驗證的python程式碼是正確的。
簽名的原因 $ (r,s) $ 不檢查的是它不是編碼
abc
每個 UTF-8 三個字元的 3 字節字節串的簽名,而是更複雜的消息的簽名,包括signingTime
欄位。請參閱 dave_thompson_085 的評論,該評論解釋了原因,並提出了一個可能有助於實現控制 OpenSSL 實際簽名的困難目標的修飾符。