ecdsa: avoid some big.Int conversion
This commit is contained in:
37
crypto/internal/asn1.go
Normal file
37
crypto/internal/asn1.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/cryptobyte"
|
||||||
|
"golang.org/x/crypto/cryptobyte/asn1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Taken from crypto/ecdsa
|
||||||
|
|
||||||
|
func EncodeSignatureToASN1(r, s []byte) ([]byte, error) {
|
||||||
|
var b cryptobyte.Builder
|
||||||
|
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||||
|
addASN1IntBytes(b, r)
|
||||||
|
addASN1IntBytes(b, s)
|
||||||
|
})
|
||||||
|
return b.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// addASN1IntBytes encodes in ASN.1 a positive integer represented as
|
||||||
|
// a big-endian byte slice with zero or more leading zeroes.
|
||||||
|
func addASN1IntBytes(b *cryptobyte.Builder, bytes []byte) {
|
||||||
|
for len(bytes) > 0 && bytes[0] == 0 {
|
||||||
|
bytes = bytes[1:]
|
||||||
|
}
|
||||||
|
if len(bytes) == 0 {
|
||||||
|
b.SetError(errors.New("invalid integer"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.AddASN1(asn1.INTEGER, func(c *cryptobyte.Builder) {
|
||||||
|
if bytes[0]&0x80 != 0 {
|
||||||
|
c.AddUint8(0)
|
||||||
|
}
|
||||||
|
c.AddBytes(bytes)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -34,11 +34,17 @@ func PublicKeyFromBytes(b []byte) (*PublicKey, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PublicKeyFromXY converts x and y coordinates into a PublicKey.
|
// PublicKeyFromXY converts x and y coordinates into a PublicKey.
|
||||||
func PublicKeyFromXY(x, y *big.Int) (*PublicKey, error) {
|
func PublicKeyFromXY(x, y []byte) (*PublicKey, error) {
|
||||||
if !elliptic.P256().IsOnCurve(x, y) {
|
pub := &PublicKey{k: &ecdsa.PublicKey{
|
||||||
|
Curve: elliptic.P256(),
|
||||||
|
X: new(big.Int).SetBytes(x),
|
||||||
|
Y: new(big.Int).SetBytes(y),
|
||||||
|
}}
|
||||||
|
|
||||||
|
if !elliptic.P256().IsOnCurve(pub.k.X, pub.k.Y) {
|
||||||
return nil, fmt.Errorf("invalid P-256 public key")
|
return nil, fmt.Errorf("invalid P-256 public key")
|
||||||
}
|
}
|
||||||
return &PublicKey{k: &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}}, nil
|
return pub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicKeyFromPublicKeyMultibase decodes the public key from its Multibase form
|
// PublicKeyFromPublicKeyMultibase decodes the public key from its Multibase form
|
||||||
@@ -128,13 +134,14 @@ func (p *PublicKey) VerifyBytes(message, signature []byte) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash the message with SHA-256
|
// For some reason, the go crypto library in ecdsa.Verify() encodes the signature as ASN.1 to then decode it.
|
||||||
hash := sha256.Sum256(message)
|
// This means it's actually more efficient to encode the signature as ASN.1 here.
|
||||||
|
sigAsn1, err := helpers.EncodeSignatureToASN1(signature[:SignatureBytesSize/2], signature[SignatureBytesSize/2:])
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
r := new(big.Int).SetBytes(signature[:SignatureBytesSize/2])
|
return p.VerifyASN1(message, sigAsn1)
|
||||||
s := new(big.Int).SetBytes(signature[SignatureBytesSize/2:])
|
|
||||||
|
|
||||||
return ecdsa.Verify(p.k, hash[:], r, s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicKey) VerifyASN1(message, signature []byte) bool {
|
func (p *PublicKey) VerifyASN1(message, signature []byte) bool {
|
||||||
|
|||||||
@@ -34,11 +34,17 @@ func PublicKeyFromBytes(b []byte) (*PublicKey, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PublicKeyFromXY converts x and y coordinates into a PublicKey.
|
// PublicKeyFromXY converts x and y coordinates into a PublicKey.
|
||||||
func PublicKeyFromXY(x, y *big.Int) (*PublicKey, error) {
|
func PublicKeyFromXY(x, y []byte) (*PublicKey, error) {
|
||||||
if !elliptic.P384().IsOnCurve(x, y) {
|
pub := &PublicKey{k: &ecdsa.PublicKey{
|
||||||
|
Curve: elliptic.P384(),
|
||||||
|
X: new(big.Int).SetBytes(x),
|
||||||
|
Y: new(big.Int).SetBytes(y),
|
||||||
|
}}
|
||||||
|
|
||||||
|
if !elliptic.P384().IsOnCurve(pub.k.X, pub.k.Y) {
|
||||||
return nil, fmt.Errorf("invalid P-384 public key")
|
return nil, fmt.Errorf("invalid P-384 public key")
|
||||||
}
|
}
|
||||||
return &PublicKey{k: &ecdsa.PublicKey{Curve: elliptic.P384(), X: x, Y: y}}, nil
|
return pub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicKeyFromPublicKeyMultibase decodes the public key from its Multibase form
|
// PublicKeyFromPublicKeyMultibase decodes the public key from its Multibase form
|
||||||
@@ -128,13 +134,14 @@ func (p *PublicKey) VerifyBytes(message, signature []byte) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash the message with SHA-384
|
// For some reason, the go crypto library in ecdsa.Verify() encodes the signature as ASN.1 to then decode it.
|
||||||
hash := sha512.Sum384(message)
|
// This means it's actually more efficient to encode the signature as ASN.1 here.
|
||||||
|
sigAsn1, err := helpers.EncodeSignatureToASN1(signature[:SignatureBytesSize/2], signature[SignatureBytesSize/2:])
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
r := new(big.Int).SetBytes(signature[:SignatureBytesSize/2])
|
return p.VerifyASN1(message, sigAsn1)
|
||||||
s := new(big.Int).SetBytes(signature[SignatureBytesSize/2:])
|
|
||||||
|
|
||||||
return ecdsa.Verify(p.k, hash[:], r, s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicKey) VerifyASN1(message, signature []byte) bool {
|
func (p *PublicKey) VerifyASN1(message, signature []byte) bool {
|
||||||
|
|||||||
@@ -34,11 +34,17 @@ func PublicKeyFromBytes(b []byte) (*PublicKey, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PublicKeyFromXY converts x and y coordinates into a PublicKey.
|
// PublicKeyFromXY converts x and y coordinates into a PublicKey.
|
||||||
func PublicKeyFromXY(x, y *big.Int) (*PublicKey, error) {
|
func PublicKeyFromXY(x, y []byte) (*PublicKey, error) {
|
||||||
if !elliptic.P521().IsOnCurve(x, y) {
|
pub := &PublicKey{k: &ecdsa.PublicKey{
|
||||||
|
Curve: elliptic.P521(),
|
||||||
|
X: new(big.Int).SetBytes(x),
|
||||||
|
Y: new(big.Int).SetBytes(y),
|
||||||
|
}}
|
||||||
|
|
||||||
|
if !elliptic.P521().IsOnCurve(pub.k.X, pub.k.Y) {
|
||||||
return nil, fmt.Errorf("invalid P-521 public key")
|
return nil, fmt.Errorf("invalid P-521 public key")
|
||||||
}
|
}
|
||||||
return &PublicKey{k: &ecdsa.PublicKey{Curve: elliptic.P521(), X: x, Y: y}}, nil
|
return pub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicKeyFromPublicKeyMultibase decodes the public key from its Multibase form
|
// PublicKeyFromPublicKeyMultibase decodes the public key from its Multibase form
|
||||||
@@ -128,13 +134,14 @@ func (p *PublicKey) VerifyBytes(message, signature []byte) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash the message with SHA-512
|
// For some reason, the go crypto library in ecdsa.Verify() encodes the signature as ASN.1 to then decode it.
|
||||||
hash := sha512.Sum512(message)
|
// This means it's actually more efficient to encode the signature as ASN.1 here.
|
||||||
|
sigAsn1, err := helpers.EncodeSignatureToASN1(signature[:SignatureBytesSize/2], signature[SignatureBytesSize/2:])
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
r := new(big.Int).SetBytes(signature[:SignatureBytesSize/2])
|
return p.VerifyASN1(message, sigAsn1)
|
||||||
s := new(big.Int).SetBytes(signature[SignatureBytesSize/2:])
|
|
||||||
|
|
||||||
return ecdsa.Verify(p.k, hash[:], r, s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicKey) VerifyASN1(message, signature []byte) bool {
|
func (p *PublicKey) VerifyASN1(message, signature []byte) bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user