-
Notifications
You must be signed in to change notification settings - Fork 21k
crypto: improve error messages in LoadECDSA #20718
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f39afd5
0a22d23
745f0fd
ae3c77b
a66d88e
fe0bc49
3db06e4
969c671
3d3d5bb
b4916e6
b68c0f5
0d574ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
package crypto | ||
|
||
import ( | ||
"bufio" | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/rand" | ||
|
@@ -158,29 +159,67 @@ func FromECDSAPub(pub *ecdsa.PublicKey) []byte { | |
// HexToECDSA parses a secp256k1 private key. | ||
func HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) { | ||
b, err := hex.DecodeString(hexkey) | ||
if err != nil { | ||
return nil, errors.New("invalid hex string") | ||
if byteErr, ok := err.(hex.InvalidByteError); ok { | ||
return nil, fmt.Errorf("invalid hex character %q in private key", byte(byteErr)) | ||
} else if err != nil { | ||
return nil, errors.New("invalid hex data for private key") | ||
} | ||
return ToECDSA(b) | ||
} | ||
|
||
// LoadECDSA loads a secp256k1 private key from the given file. | ||
func LoadECDSA(file string) (*ecdsa.PrivateKey, error) { | ||
buf := make([]byte, 64) | ||
fd, err := os.Open(file) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer fd.Close() | ||
if _, err := io.ReadFull(fd, buf); err != nil { | ||
return nil, err | ||
} | ||
|
||
key, err := hex.DecodeString(string(buf)) | ||
r := bufio.NewReader(fd) | ||
buf := make([]byte, 64) | ||
n, err := readASCII(buf, r) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of reading any ascii char, why not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The change in HexToECDSA is good to have on its own. It didn't report the offending character before, now it does. |
||
if err != nil { | ||
return nil, err | ||
} else if n != len(buf) { | ||
return nil, fmt.Errorf("key file too short, want 64 hex characters") | ||
} | ||
if err := checkKeyFileEnd(r); err != nil { | ||
return nil, err | ||
} | ||
|
||
return HexToECDSA(string(buf)) | ||
} | ||
|
||
// readASCII reads into 'buf', stopping when the buffer is full or | ||
// when a non-printable control character is encountered. | ||
func readASCII(buf []byte, r *bufio.Reader) (n int, err error) { | ||
for ; n < len(buf); n++ { | ||
buf[n], err = r.ReadByte() | ||
switch { | ||
case err == io.EOF || buf[n] < '!': | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't there a less hacky way to check a char, along the lines of Python's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no better way to do this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you could use unicode.IsPrint(rune r) https://golang.org/pkg/unicode/#IsPrint There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could, but don't want to import "unicode" just for checking if something is ASCII. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thats fair |
||
return n, nil | ||
case err != nil: | ||
return n, err | ||
} | ||
} | ||
return n, nil | ||
} | ||
|
||
// checkKeyFileEnd skips over additional newlines at the end of a key file. | ||
func checkKeyFileEnd(r *bufio.Reader) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know if the distinction between There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added this because Adam's original added support for trailing newlines. These can happen if you paste the key into a file using a text editor. So we want to allow newlines, but not too many of them. That's why this function is so complicated. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah okay, then the PR looks good to me |
||
for i := 0; ; i++ { | ||
b, err := r.ReadByte() | ||
switch { | ||
case err == io.EOF: | ||
return nil | ||
case err != nil: | ||
return err | ||
case b != '\n' && b != '\r': | ||
return fmt.Errorf("invalid character %q at end of key file", b) | ||
case i >= 2: | ||
return errors.New("key file too long, want 64 hex characters") | ||
} | ||
} | ||
return ToECDSA(key) | ||
} | ||
|
||
// SaveECDSA saves a secp256k1 private key to the given file with | ||
|
@@ -190,6 +229,7 @@ func SaveECDSA(file string, key *ecdsa.PrivateKey) error { | |
return ioutil.WriteFile(file, []byte(k), 0600) | ||
} | ||
|
||
// GenerateKey generates a new private key. | ||
func GenerateKey() (*ecdsa.PrivateKey, error) { | ||
return ecdsa.GenerateKey(S256(), rand.Reader) | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.