1 回答

TA貢獻(xiàn)1875條經(jīng)驗(yàn) 獲得超3個(gè)贊
我發(fā)現(xiàn)我的 C++ 橢圓曲線庫(kù)在將公鑰(點(diǎn))壓縮(編組)為SEC 1,版本 2.0,第 2.3.3 節(jié)形式時(shí)有一個(gè)錯(cuò)誤。有些點(diǎn)第一個(gè)字節(jié)錯(cuò)誤(從奇數(shù)到偶數(shù),或從偶數(shù)到奇數(shù))。
1*G GO buffer: 0x036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296 C++ buffer: 0x026b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
2*G GO buffer: 0x037cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978 C++ buffer: 0x037cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978
3*G GO buffer: 0x025ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c C++ buffer: 0x035ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c
4*G GO buffer: 0x02e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852 C++ buffer: 0x02e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852
5*G GO buffer: 0x0251590b7a515140d2d784c85608668fdfef8c82fd1f5be52421554a0dc3d033ed C++ buffer: 0x0251590b7a515140d2d784c85608668fdfef8c82fd1f5be52421554a0dc3d033ed
6*G GO buffer: 0x02b01a172a76a4602c92d3242cb897dde3024c740debb215b4c6b0aae93c2291a9 C++ buffer: 0x03b01a172a76a4602c92d3242cb897dde3024c740debb215b4c6b0aae93c2291a9
7*G GO buffer: 0x028e533b6fa0bf7b4625bb30667c01fb607ef9f8b8a80fef5b300628703187b2a3 C++ buffer: 0x038e533b6fa0bf7b4625bb30667c01fb607ef9f8b8a80fef5b300628703187b2a3
8*G GO buffer: 0x0262d9779dbee9b0534042742d3ab54cadc1d238980fce97dbb4dd9dc1db6fb393 C++ buffer: 0x0362d9779dbee9b0534042742d3ab54cadc1d238980fce97dbb4dd9dc1db6fb393
9*G GO buffer: 0x02ea68d7b6fedf0b71878938d51d71f8729e0acb8c2c6df8b3d79e8a4b90949ee0 C++ buffer: 0x02ea68d7b6fedf0b71878938d51d71f8729e0acb8c2c6df8b3d79e8a4b90949ee0
因此,一些公鑰(點(diǎn))被導(dǎo)出為而{x,-y} 不是{x,y}
原來的
橢圓曲線 (EC) 公鑰遵循高效密碼術(shù)標(biāo)準(zhǔn) (SEC),SEC 1:橢圓曲線密碼術(shù)部分中的 2.3.3 橢圓曲線點(diǎn)到八位字節(jié)字符串轉(zhuǎn)換。
如果 y 坐標(biāo)為偶數(shù),則壓縮形式(作為字節(jié))的公鑰的第一個(gè)字節(jié)為0x02 。否則,如果 y 坐標(biāo)為奇數(shù),則為 0x03。
在數(shù)學(xué)上,只給定一個(gè) x 坐標(biāo)
y^2 = x^3 + ax + b (mod p)
上面的等式有兩個(gè)解,(x, y)和(x, -y)因?yàn)?y^2 = (-y)^2
此外,-y 等于 (p - y),因?yàn)樗钦麛?shù)模素?cái)?shù)p的字段。
由于p 是素?cái)?shù)且 p!=2,因此p 是奇數(shù)。然后,如果y是奇數(shù),則-y(或(py))是偶數(shù),反之亦然。
ECDSA 驗(yàn)證算法不需要公鑰的 y 坐標(biāo),因?yàn)樗恍枰?x 坐標(biāo)。因此,當(dāng)我檢查簽名元組{r,s}時(shí),我將使用相同 x 坐標(biāo)但不同 y 坐標(biāo)(從奇數(shù)翻轉(zhuǎn)到偶數(shù),反之亦然)的公鑰對(duì)其進(jìn)行檢查。我真的不知道為什么 GO 語(yǔ)言 ECDSA 包只允許兩個(gè) y 坐標(biāo)值之一。
下面是我的代碼示例。假設(shè)我有一個(gè)壓縮的公鑰作為緩沖區(qū)publicKeyBuffer[:]
然后我可以解組它以獲得 x 坐標(biāo)和 y 坐標(biāo)
pk := new(ecdsa.PublicKey)
pk.Curve = elliptic.P256()
pk.X, pk.Y = elliptic.UnmarshalCompressed(elliptic.P256(), publicKeyBuffer[:])
我們可以檢查簽名元組 {r,s} 是否有效
valid := ecdsa.Verify(pk, hash[:], r, s)
如果簽名無效,即valid == false嘗試將值更改pk.Y為對(duì)應(yīng)的值。您可以通過兩種簡(jiǎn)單的方式做到這一點(diǎn)。
第一種方法,您將公鑰緩沖區(qū)的第一個(gè)字節(jié)從 更改為0x02或0x03反之亦然。您可以通過XOR使用(僅 1)執(zhí)行第一個(gè)字節(jié)來實(shí)現(xiàn)此目的0x01。
valid = ecdsa.Verify(pk, hash[:], r, s)
/* The 1st way */
if !valid {
publicKeyBuffer[0] ^= 1 // change the y-coordinate by switching 0x02 to 0x03 (or vice versa) of public key buffer
pk.X, pk.Y = elliptic.UnmarshalCompressed(elliptic.P256(), publicKeyBuffer[:])
valid = ecdsa.Verify(pk, hash[:], r, s)
}
fmt.Println("signature verified:", valid)
在第二種方式中,我們將 y 坐標(biāo)更改為其 (py) 值,即,將其更改為 (-y)
valid = ecdsa.Verify(pk, hash[:], r, s)
/* The 2nd way */
if !valid {
pk.Y = new(big.Int).Sub(pk.Curve.Params().P, pk.Y) // replace y-coordinate pk.Y with (-y), Note. (-y) is equal (p - y)
valid = ecdsa.Verify(pk, hash[:], r, s)
}
fmt.Println("signature verified:", valid)
如果簽名仍然無效,那么這與公鑰 Unmarshal 無關(guān)。
PS 我不知道為什么 GO ECDSA 語(yǔ)言不允許公鑰的其他 y 坐標(biāo)值
- 1 回答
- 0 關(guān)注
- 320 瀏覽
添加回答
舉報(bào)