mirror of
https://github.com/btcsuite/btcd.git
synced 2026-08-13 12:32:51 +02:00
btcutil: reject out-of-range private keys in DecodeWIF
DecodeWIF did not validate that the decoded private key falls within the valid range [1, N-1] for a secp256k1 private key. The raw 32-byte key material was passed straight to btcec.PrivKeyFromBytes, which reduces the scalar modulo the group order N and clamps to zero, returning no error. As a result, a WIF encoding a private key of zero, the group order N, or any value >= N was silently accepted. For keys >= N this is particularly dangerous: DecodeWIF returned a private key that differs from the one actually encoded in the WIF (e.g. a WIF for N+5 decoded to the key 5), so an application importing such a WIF would obtain a valid-looking but wrong key pair, with no indication that anything was off. This is also inconsistent with hdkeychain.NewKeyFromString in the same package, which already rejects private keys outside [1, N-1]. Validate the range using a ModNScalar (constant time): SetByteSlice reports an overflow when the value is >= N, and IsZero covers the zero key. Out-of-range keys now return ErrMalformedPrivateKey. Add regression test cases (zero, N, and N+5) to TestEncodeDecodeWIF. Signed-off-by: Lrifton92 <Lrifton92@users.noreply.github.com>
This commit is contained in:
parent
1966c38453
commit
b23f560a91
2 changed files with 39 additions and 0 deletions
|
|
@ -118,6 +118,21 @@ func DecodeWIF(wif string) (*WIF, error) {
|
|||
|
||||
netID := decoded[0]
|
||||
privKeyBytes := decoded[1 : 1+btcec.PrivKeyBytesLen]
|
||||
|
||||
// Ensure the private key is within the valid range for a secp256k1
|
||||
// private key, that is [1, N-1]. Without this check, a WIF encoding a
|
||||
// key of zero or one greater than or equal to the group order N is
|
||||
// silently accepted: btcec.PrivKeyFromBytes reduces the scalar modulo
|
||||
// N, so DecodeWIF would otherwise return a private key that differs from
|
||||
// the one actually encoded in the WIF (or the all-zero key) without
|
||||
// reporting an error.
|
||||
var keyScalar btcec.ModNScalar
|
||||
if overflow := keyScalar.SetByteSlice(privKeyBytes); overflow ||
|
||||
keyScalar.IsZero() {
|
||||
|
||||
return nil, ErrMalformedPrivateKey
|
||||
}
|
||||
|
||||
privKey, _ := btcec.PrivKeyFromBytes(privKeyBytes)
|
||||
return &WIF{privKey, compress, netID}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,30 @@ func TestEncodeDecodeWIF(t *testing.T) {
|
|||
wif: "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTj",
|
||||
err: address.ErrChecksumMismatch,
|
||||
},
|
||||
{
|
||||
// A WIF encoding a private key of zero, which is
|
||||
// outside the valid range [1, N-1] for a secp256k1
|
||||
// private key.
|
||||
name: "decodeZeroPrivKeyWif",
|
||||
wif: "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAbuatmU",
|
||||
err: ErrMalformedPrivateKey,
|
||||
},
|
||||
{
|
||||
// A WIF encoding a private key equal to the group order
|
||||
// N, which is outside the valid range [1, N-1].
|
||||
name: "decodeOrderNPrivKeyWif",
|
||||
wif: "5Km2kuu7vtFDPpxywn4u3NLpbr5jKpTB3jsuDU2KYEqetwr388P",
|
||||
err: ErrMalformedPrivateKey,
|
||||
},
|
||||
{
|
||||
// A WIF encoding a private key of N+5, which is outside
|
||||
// the valid range [1, N-1]. Before validation was
|
||||
// added, this was silently reduced modulo N and decoded
|
||||
// to a different private key (5) without any error.
|
||||
name: "decodeAboveOrderNPrivKeyWif",
|
||||
wif: "5Km2kuu7vtFDPpxywn4u3NLpbr5jKpTB3jsuDU2KYEqeuVhzTbv",
|
||||
err: ErrMalformedPrivateKey,
|
||||
},
|
||||
}
|
||||
|
||||
for _, invalidCase := range invalidDecodeCases {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue