1 回答

TA貢獻1875條經驗 獲得超3個贊
我發現我的 C++ 橢圓曲線庫在將公鑰(點)壓縮(編組)為SEC 1,版本 2.0,第 2.3.3 節形式時有一個錯誤。有些點第一個字節錯誤(從奇數到偶數,或從偶數到奇數)。
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
因此,一些公鑰(點)被導出為而{x,-y} 不是{x,y}
原來的
橢圓曲線 (EC) 公鑰遵循高效密碼術標準 (SEC),SEC 1:橢圓曲線密碼術部分中的 2.3.3 橢圓曲線點到八位字節字符串轉換。
如果 y 坐標為偶數,則壓縮形式(作為字節)的公鑰的第一個字節為0x02 。否則,如果 y 坐標為奇數,則為 0x03。
在數學上,只給定一個 x 坐標
y^2 = x^3 + ax + b (mod p)
上面的等式有兩個解,(x, y)和(x, -y)因為 y^2 = (-y)^2
此外,-y 等于 (p - y),因為它是整數模素數p的字段。
由于p 是素數且 p!=2,因此p 是奇數。然后,如果y是奇數,則-y(或(py))是偶數,反之亦然。
ECDSA 驗證算法不需要公鑰的 y 坐標,因為它只需要它的 x 坐標。因此,當我檢查簽名元組{r,s}時,我將使用相同 x 坐標但不同 y 坐標(從奇數翻轉到偶數,反之亦然)的公鑰對其進行檢查。我真的不知道為什么 GO 語言 ECDSA 包只允許兩個 y 坐標值之一。
下面是我的代碼示例。假設我有一個壓縮的公鑰作為緩沖區publicKeyBuffer[:]
然后我可以解組它以獲得 x 坐標和 y 坐標
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為對應的值。您可以通過兩種簡單的方式做到這一點。
第一種方法,您將公鑰緩沖區的第一個字節從 更改為0x02或0x03反之亦然。您可以通過XOR使用(僅 1)執行第一個字節來實現此目的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 坐標更改為其 (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 無關。
PS 我不知道為什么 GO ECDSA 語言不允許公鑰的其他 y 坐標值
- 1 回答
- 0 關注
- 325 瀏覽
添加回答
舉報