Signature

DSA 的 ASN.1 整數問題

  • June 9, 2022

我正在嘗試按照本網站第 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 實際簽名的困難目標的修飾符。

引用自:https://crypto.stackexchange.com/questions/100469