diff --git a/agessh/agessh.go b/agessh/agessh.go index 8096032..c8717f4 100644 --- a/agessh/agessh.go +++ b/agessh/agessh.go @@ -24,10 +24,10 @@ import ( "errors" "fmt" "io" + "math/big" "filippo.io/age" "filippo.io/age/internal/format" - "filippo.io/edwards25519" "golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/curve25519" "golang.org/x/crypto/hkdf" @@ -179,14 +179,37 @@ func ParseRecipient(s string) (age.Recipient, error) { return r, nil } +var curve25519P, _ = new(big.Int).SetString("57896044618658097711785492504343953926634992332820282019728792003956564819949", 10) + func ed25519PublicKeyToCurve25519(pk ed25519.PublicKey) ([]byte, error) { - // See https://blog.filippo.io/using-ed25519-keys-for-encryption and - // https://pkg.go.dev/filippo.io/edwards25519#Point.BytesMontgomery. - p, err := (&edwards25519.Point{}).SetBytes(pk) - if err != nil { - return nil, err + // ed25519.PublicKey is a little endian representation of the y-coordinate, + // with the most significant bit set based on the sign of the x-coordinate. + bigEndianY := make([]byte, ed25519.PublicKeySize) + for i, b := range pk { + bigEndianY[ed25519.PublicKeySize-i-1] = b } - return p.BytesMontgomery(), nil + bigEndianY[0] &= 0b0111_1111 + + // The Montgomery u-coordinate is derived through the bilinear map + // + // u = (1 + y) / (1 - y) + // + // See https://blog.filippo.io/using-ed25519-keys-for-encryption. + y := new(big.Int).SetBytes(bigEndianY) + denom := new(big.Int).Sub(big.NewInt(1), y) + if denom = denom.ModInverse(denom, curve25519P); denom == nil { + return nil, errors.New("invalid point") + } + u := y.Mul(y.Add(y, big.NewInt(1)), denom) + u.Mod(u, curve25519P) + + out := make([]byte, curve25519.PointSize) + uBytes := u.Bytes() + for i, b := range uBytes { + out[len(uBytes)-i-1] = b + } + + return out, nil } const ed25519Label = "age-encryption.org/v1/ssh-ed25519" diff --git a/go.mod b/go.mod index 58d8101..2573f8e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module filippo.io/age go 1.13 require ( - filippo.io/edwards25519 v1.0.0-alpha.2 github.com/sergi/go-diff v1.1.0 golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 ) diff --git a/go.sum b/go.sum index b065abd..89822ea 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -filippo.io/edwards25519 v1.0.0-alpha.2 h1:EWbZLqGEPSIj2W69gx04KtNVkyPIfe3uj0DhDQJonbQ= -filippo.io/edwards25519 v1.0.0-alpha.2/go.mod h1:X+pm78QAUPtFLi1z9PYIlS/bdDnvbCOGKtZ+ACWEf7o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=