Skip to content

Commit

Permalink
Add marshalling for EdDSA signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
wussler committed Aug 12, 2022
1 parent 7fcef0d commit 5aa09b7
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 24 deletions.
15 changes: 13 additions & 2 deletions openpgp/eddsa/eddsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,22 @@ func GenerateKey(rand io.Reader, c ecc.EdDSACurve) (priv *PrivateKey, err error)
}

func Sign(priv *PrivateKey, message []byte) (r, s []byte, err error) {
return priv.PublicKey.curve.Sign(priv.PublicKey.X, priv.D, message)
sig, err := priv.PublicKey.curve.Sign(priv.PublicKey.X, priv.D, message)
if err != nil {
return nil, nil, err
}

r, s = priv.PublicKey.curve.MarshalSignature(sig)
return
}

func Verify(pub *PublicKey, message, r, s []byte) bool {
return pub.curve.Verify(pub.X, message, r, s)
sig := pub.curve.UnmarshalSignature(r, s)
if sig == nil {
return false
}

return pub.curve.Verify(pub.X, message, sig)
}

func Validate(priv *PrivateKey) error {
Expand Down
6 changes: 4 additions & 2 deletions openpgp/internal/ecc/curves.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ type EdDSACurve interface {
UnmarshalBytePoint([]byte) (x []byte)
MarshalByteSecret(d []byte) []byte
UnmarshalByteSecret(d []byte) []byte
MarshalSignature(sig []byte) (r, s []byte)
UnmarshalSignature(r, s []byte) (sig []byte)
GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error)
Sign(publicKey, privateKey, message []byte) (r, s []byte, err error)
Verify(publicKey, message, r, s []byte) bool
Sign(publicKey, privateKey, message []byte) (sig []byte, err error)
Verify(publicKey, message, sig []byte) bool
ValidateEdDSA(publicKey, privateKey []byte) (err error)
}
type ECDHCurve interface {
Expand Down
38 changes: 27 additions & 11 deletions openpgp/internal/ecc/ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,28 @@ func (c *ed25519) UnmarshalByteSecret(s []byte) (d []byte) {
return
}

// MarshalSignature splits a signature in R and S.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1
func (c *ed25519) MarshalSignature(sig []byte) (r, s []byte) {
return sig[:ed25519Size], sig[ed25519Size:]
}

// UnmarshalSignature decodes R and S in the native format, re-adding the stripped leading zeroes
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1
func (c *ed25519) UnmarshalSignature(r, s []byte) (sig []byte) {
// Check size
if len(r) > 32 || len(s) > 32 {
return nil
}

sig = make([]byte, ed25519lib.SignatureSize)

// Handle stripped leading zeroes
copy(sig[ed25519Size-len(r):ed25519Size], r)
copy(sig[ed25519lib.SignatureSize-len(s):], s)
return sig
}

func (c *ed25519) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) {
pk, sk, err := ed25519lib.GenerateKey(rand)

Expand All @@ -70,19 +92,13 @@ func getEd25519Sk(publicKey, privateKey []byte) ed25519lib.PrivateKey {
return append(privateKey, publicKey...)
}

func (c *ed25519) Sign(publicKey, privateKey, message []byte) (r, s []byte, err error) {
sig := ed25519lib.Sign(getEd25519Sk(publicKey, privateKey), message)
return sig[:ed25519Size], sig[ed25519Size:], nil
func (c *ed25519) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
sig = ed25519lib.Sign(getEd25519Sk(publicKey, privateKey), message)
return sig, nil
}

func (c *ed25519) Verify(publicKey, message, r, s []byte) bool {
signature := make([]byte, ed25519lib.SignatureSize)

// Handle stripped leading zeroes as per https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.1
copy(signature[ed25519Size-len(r):ed25519Size], r)
copy(signature[ed25519lib.SignatureSize-len(s):], s)

return ed25519lib.Verify(publicKey, message, signature)
func (c *ed25519) Verify(publicKey, message, sig []byte) bool {
return ed25519lib.Verify(publicKey, message, sig)
}

func (c *ed25519) ValidateEdDSA(publicKey, privateKey []byte) (err error) {
Expand Down
31 changes: 22 additions & 9 deletions openpgp/internal/ecc/ed448.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ func (c *ed448) UnmarshalByteSecret(s []byte) (d []byte) {
return s[1:]
}

// MarshalSignature splits a signature in R and S, where R is in prefixed native format and
// S is an MPI with value zero.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.2
func (c *ed448) MarshalSignature(sig []byte) (r, s []byte) {
return append([]byte{0x40}, sig...), []byte{}
}

// UnmarshalSignature decodes R and S in the native format. Only R is used, in prefixed native format.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-5.2.3.3.2
func (c *ed448) UnmarshalSignature(r, s []byte) (sig []byte) {
if len(r) != ed448lib.SignatureSize + 1 {
return nil
}

return r[1:]
}

func (c *ed448) GenerateEdDSA(rand io.Reader) (pub, priv []byte, err error) {
pk, sk, err := ed448lib.GenerateKey(rand)

Expand All @@ -70,22 +87,18 @@ func getEd448Sk(publicKey, privateKey []byte) ed448lib.PrivateKey {
return append(privateKey, publicKey...)
}

func (c *ed448) Sign(publicKey, privateKey, message []byte) (r, s []byte, err error) {
func (c *ed448) Sign(publicKey, privateKey, message []byte) (sig []byte, err error) {
// Ed448 is used with the empty string as a context string.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7
sig := ed448lib.Sign(getEd448Sk(publicKey, privateKey), message, "")
sig = ed448lib.Sign(getEd448Sk(publicKey, privateKey), message, "")

// Only R is used, in prefixed native format.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-9.2.1
return append([]byte{0x40}, sig...), nil, nil
return sig, nil
}

func (c *ed448) Verify(publicKey, message, r, s []byte) bool {
// Only R is used, in prefixed native format.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-9.2.1
func (c *ed448) Verify(publicKey, message, sig []byte) bool {
// Ed448 is used with the empty string as a context string.
// See https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-06#section-13.7
return ed448lib.Verify(publicKey, message, r[1:], "")
return ed448lib.Verify(publicKey, message, sig, "")
}

func (c *ed448) ValidateEdDSA(publicKey, privateKey []byte) (err error) {
Expand Down

0 comments on commit 5aa09b7

Please sign in to comment.