[crypto] x/crypto/ssh: implement curve25519-sha256@libssh.org key agreement.

34 views
Skip to first unread message

Han-Wen Nienhuys (Gerrit)

unread,
Aug 12, 2015, 5:20:15 AM8/12/15
to Adam Langley, Ian Lance Taylor, golang-co...@googlegroups.com
Reviewers: Adam Langley

Han-Wen Nienhuys uploaded a change:
https://go-review.googlesource.com/13592

x/crypto/ssh: implement curve255...@libssh.org key agreement.

Fixes golang/go#11004.

Change-Id: Ic37cf9d620e3397b7ad769ae16abdaee63a7733b
---
M ssh/common.go
M ssh/kex.go
2 files changed, 138 insertions(+), 5 deletions(-)



diff --git a/ssh/common.go b/ssh/common.go
index 0a9df1f..1aef9c0 100644
--- a/ssh/common.go
+++ b/ssh/common.go
@@ -33,6 +33,7 @@
// supportedKexAlgos specifies the supported key-exchange algorithms in
// preference order.
var supportedKexAlgos = []string{
+ kexAlgoCurve25519SHA256,
// P384 and P521 are not constant-time yet, but since we don't
// reuse ephemeral keys, using them for ECDH should be OK.
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
diff --git a/ssh/kex.go b/ssh/kex.go
index 6a835c7..45ad811 100644
--- a/ssh/kex.go
+++ b/ssh/kex.go
@@ -10,16 +10,20 @@
"crypto/elliptic"
"crypto/rand"
"errors"
+ "fmt"
"io"
"math/big"
+
+ "golang.org/x/crypto/curve25519"
)

const (
- kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
- kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
- kexAlgoECDH256 = "ecdh-sha2-nistp256"
- kexAlgoECDH384 = "ecdh-sha2-nistp384"
- kexAlgoECDH521 = "ecdh-sha2-nistp521"
+ kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
+ kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
+ kexAlgoECDH256 = "ecdh-sha2-nistp256"
+ kexAlgoECDH384 = "ecdh-sha2-nistp384"
+ kexAlgoECDH521 = "ecdh-sha2-nistp521"
+ kexAlgoCurve25519SHA256 = "curve255...@libssh.org"
)

// kexResult captures the outcome of a key exchange.
@@ -383,4 +387,132 @@
kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
+ kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
+}
+
+// curve25519sha256 implements the curve255...@libssh.org key
+// agreement protocol, as described in
+//
https://git.libssh.org/projects/libssh.git/tree/doc/curve255...@libssh.org.txt
+type curve25519sha256 struct{}
+
+type curve25519KeyPair struct {
+ priv [32]byte
+ pub [32]byte
+}
+
+func (kp *curve25519KeyPair) gen(rand io.Reader) error {
+ if _, err := rand.Read(kp.priv[:]); err != nil {
+ return err
+ }
+ curve25519.ScalarBaseMult(&kp.pub, &kp.priv)
+ return nil
+}
+
+func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics
*handshakeMagics) (*kexResult, error) {
+ var kp curve25519KeyPair
+ if err := kp.gen(rand); err != nil {
+ return nil, err
+ }
+ kexInit := kexECDHInitMsg{kp.pub[:]}
+ if err := c.writePacket(Marshal(&kexInit)); err != nil {
+ return nil, err
+ }
+
+ packet, err := c.readPacket()
+ if err != nil {
+ return nil, err
+ }
+
+ var reply kexECDHReplyMsg
+ if err = Unmarshal(packet, &reply); err != nil {
+ return nil, err
+ }
+ if len(reply.EphemeralPubKey) != 32 {
+ return nil, fmt.Errorf("ssh: server public key has %d bytes, want 32",
len(reply.EphemeralPubKey))
+ }
+
+ var servPub, secret [32]byte
+ copy(servPub[:], reply.EphemeralPubKey)
+ curve25519.ScalarMult(&secret, &kp.priv, &servPub)
+ kInt := &big.Int{}
+ kInt.SetBytes(secret[:])
+
+ h := crypto.SHA256.New()
+ magics.write(h)
+ writeString(h, reply.HostKey)
+ writeString(h, kexInit.ClientPubKey)
+ writeString(h, reply.EphemeralPubKey)
+
+ K := make([]byte, intLength(kInt))
+ marshalInt(K, kInt)
+ h.Write(K)
+
+ return &kexResult{
+ H: h.Sum(nil),
+ K: K,
+ HostKey: reply.HostKey,
+ Signature: reply.Signature,
+ Hash: crypto.SHA256,
+ }, nil
+}
+
+func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics
*handshakeMagics, priv Signer) (result *kexResult, err error) {
+ packet, err := c.readPacket()
+ if err != nil {
+ return
+ }
+ var kexInit kexECDHInitMsg
+ if err = Unmarshal(packet, &kexInit); err != nil {
+ return
+ }
+
+ if len(kexInit.ClientPubKey) != 32 {
+ return nil, fmt.Errorf("ssh: client public key has %d bytes, want 32",
len(kexInit.ClientPubKey))
+ }
+
+ var kp curve25519KeyPair
+ if err := kp.gen(rand); err != nil {
+ return nil, err
+ }
+
+ var clientPub, secret [32]byte
+ copy(clientPub[:], kexInit.ClientPubKey)
+ curve25519.ScalarMult(&secret, &kp.priv, &clientPub)
+ kInt := &big.Int{}
+ kInt.SetBytes(secret[:])
+
+ hostKeyBytes := priv.PublicKey().Marshal()
+
+ h := crypto.SHA256.New()
+ magics.write(h)
+ writeString(h, hostKeyBytes)
+ writeString(h, kexInit.ClientPubKey)
+ writeString(h, kp.pub[:])
+
+ K := make([]byte, intLength(kInt))
+ marshalInt(K, kInt)
+ h.Write(K)
+
+ H := h.Sum(nil)
+
+ sig, err := signAndMarshal(priv, rand, H)
+ if err != nil {
+ return nil, err
+ }
+
+ reply := kexECDHReplyMsg{
+ EphemeralPubKey: kp.pub[:],
+ HostKey: hostKeyBytes,
+ Signature: sig,
+ }
+ if err := c.writePacket(Marshal(&reply)); err != nil {
+ return nil, err
+ }
+ return &kexResult{
+ H: H,
+ K: K,
+ HostKey: hostKeyBytes,
+ Signature: sig,
+ Hash: crypto.SHA256,
+ }, nil
}

--
https://go-review.googlesource.com/13592
Gerrit-Reviewer: Adam Langley <a...@golang.org>

Han-Wen Nienhuys (Gerrit)

unread,
Aug 12, 2015, 5:20:58 AM8/12/15
to Han-Wen Nienhuys, Adam Langley, golang-co...@googlegroups.com
Han-Wen Nienhuys has posted comments on this change.

x/crypto/ssh: implement curve255...@libssh.org key agreement.

Patch Set 1:

13591 should be committed first so this gets test coverage against sshd.

--
https://go-review.googlesource.com/13592
Gerrit-Reviewer: Adam Langley <a...@golang.org>
Gerrit-Reviewer: Han-Wen Nienhuys <han...@gmail.com>
Gerrit-HasComments: No

Adam Langley (Gerrit)

unread,
Aug 17, 2015, 6:16:02 PM8/17/15
to Han-Wen Nienhuys, Han-Wen Nienhuys, golang-co...@googlegroups.com
Adam Langley uploaded a new patch set:
https://go-review.googlesource.com/13592

x/crypto/ssh: implement curve255...@libssh.org key agreement.

Fixes golang/go#11004.

Change-Id: Ic37cf9d620e3397b7ad769ae16abdaee63a7733b
---
M ssh/common.go
M ssh/kex.go
2 files changed, 146 insertions(+), 5 deletions(-)


--
https://go-review.googlesource.com/13592
Gerrit-Reviewer: Adam Langley <a...@golang.org>
Gerrit-Reviewer: Han-Wen Nienhuys <han...@gmail.com>

Adam Langley (Gerrit)

unread,
Aug 17, 2015, 6:16:34 PM8/17/15
to Han-Wen Nienhuys, Han-Wen Nienhuys, golang-co...@googlegroups.com
Adam Langley has posted comments on this change.

x/crypto/ssh: implement curve255...@libssh.org key agreement.

Patch Set 2: Code-Review+2

--
https://go-review.googlesource.com/13592
Gerrit-Reviewer: Adam Langley <a...@golang.org>

Adam Langley (Gerrit)

unread,
Aug 17, 2015, 6:16:38 PM8/17/15
to Han-Wen Nienhuys, golang-...@googlegroups.com, Han-Wen Nienhuys, golang-co...@googlegroups.com
Adam Langley has submitted this change and it was merged.

x/crypto/ssh: implement curve255...@libssh.org key agreement.

Fixes golang/go#11004.

Change-Id: Ic37cf9d620e3397b7ad769ae16abdaee63a7733b
Reviewed-on: https://go-review.googlesource.com/13592
Reviewed-by: Adam Langley <a...@golang.org>
---
M ssh/common.go
M ssh/kex.go
2 files changed, 146 insertions(+), 5 deletions(-)

Approvals:
Adam Langley: Looks good to me, approved


--
https://go-review.googlesource.com/13592
Gerrit-Reviewer: Adam Langley <a...@golang.org>
Gerrit-Reviewer: Han-Wen Nienhuys <han...@gmail.com>
Reply all
Reply to author
Forward
0 new messages