// makeAuthMsg creates the initiator handshake message. func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey, token []byte) (*authMsgV4, error) { rpub, err := h.remoteID.Pubkey() if err != nil { return nil, fmt.Errorf("bad remoteID: %v", err) } h.remotePub = ecies.ImportECDSAPublic(rpub) // Generate random initiator nonce. h.initNonce = make([]byte, shaLen) if _, err := rand.Read(h.initNonce); err != nil { return nil, err } // Generate random keypair to for ECDH. h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil) if err != nil { return nil, err } // Sign known message: static-shared-secret ^ nonce token, err = h.staticSharedSecret(prv) if err != nil { return nil, err } signed := xor(token, h.initNonce) signature, err := crypto.Sign(signed, h.randomPrivKey.ExportECDSA()) if err != nil { return nil, err } msg := new(authMsgV4) copy(msg.Signature[:], signature) copy(msg.InitiatorPubkey[:], crypto.FromECDSAPub(&prv.PublicKey)[1:]) copy(msg.Nonce[:], h.initNonce) msg.Version = 4 return msg, nil }
func (h *encHandshake) handleAuthMsg(msg *authMsgV4, prv *ecdsa.PrivateKey) error { // Import the remote identity. h.initNonce = msg.Nonce[:] h.remoteID = msg.InitiatorPubkey rpub, err := h.remoteID.Pubkey() if err != nil { return fmt.Errorf("bad remoteID: %#v", err) } h.remotePub = ecies.ImportECDSAPublic(rpub) // Generate random keypair for ECDH. // If a private key is already set, use it instead of generating one (for testing). if h.randomPrivKey == nil { h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil) if err != nil { return err } } // Check the signature. token, err := h.staticSharedSecret(prv) if err != nil { return err } signedMsg := xor(token, h.initNonce) remoteRandomPub, err := secp256k1.RecoverPubkey(signedMsg, msg.Signature[:]) if err != nil { return err } h.remoteRandomPub, _ = importPublicKey(remoteRandomPub) return nil }
func decodeAuthMsg(prv *ecdsa.PrivateKey, token []byte, auth []byte) (*encHandshake, error) { var err error h := new(encHandshake) // generate random keypair for session h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, crypto.S256(), nil) if err != nil { return nil, err } // generate random nonce h.respNonce = make([]byte, shaLen) if _, err = rand.Read(h.respNonce); err != nil { return nil, err } msg, err := crypto.Decrypt(prv, auth) if err != nil { return nil, fmt.Errorf("could not decrypt auth message (%v)", err) } // decode message parameters // signature || sha3(ecdhe-random-pubk) || pubk || nonce || token-flag h.initNonce = msg[authMsgLen-shaLen-1 : authMsgLen-1] copy(h.remoteID[:], msg[sigLen+shaLen:sigLen+shaLen+pubLen]) rpub, err := h.remoteID.Pubkey() if err != nil { return nil, fmt.Errorf("bad remoteID: %#v", err) } h.remotePub = ecies.ImportECDSAPublic(rpub) // recover remote random pubkey from signed message. if token == nil { // TODO: it is an error if the initiator has a token and we don't. check that. // no session token means we need to generate shared secret. // ecies shared secret is used as initial session token for new peers. // generate shared key from prv and remote pubkey. if token, err = h.ecdhShared(prv); err != nil { return nil, err } } signedMsg := xor(token, h.initNonce) remoteRandomPub, err := secp256k1.RecoverPubkey(signedMsg, msg[:sigLen]) if err != nil { return nil, err } // validate the sha3 of recovered pubkey remoteRandomPubMAC := msg[sigLen : sigLen+shaLen] shaRemoteRandomPub := crypto.Sha3(remoteRandomPub[1:]) if !bytes.Equal(remoteRandomPubMAC, shaRemoteRandomPub) { return nil, fmt.Errorf("sha3 of recovered ephemeral pubkey does not match checksum in auth message") } h.remoteRandomPub, _ = importPublicKey(remoteRandomPub) return h, nil }
func newInitiatorHandshake(remoteID discover.NodeID) (*encHandshake, error) { // generate random initiator nonce n := make([]byte, shaLen) if _, err := rand.Read(n); err != nil { return nil, err } // generate random keypair to use for signing randpriv, err := ecies.GenerateKey(rand.Reader, crypto.S256(), nil) if err != nil { return nil, err } rpub, err := remoteID.Pubkey() if err != nil { return nil, fmt.Errorf("bad remoteID: %v", err) } h := &encHandshake{ initiator: true, remoteID: remoteID, remotePub: ecies.ImportECDSAPublic(rpub), initNonce: n, randomPrivKey: randpriv, } return h, nil }