Add dependencies/vendor (whatsapp)
This commit is contained in:
131
vendor/go.mau.fi/whatsmeow/handshake.go
vendored
Normal file
131
vendor/go.mau.fi/whatsmeow/handshake.go
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2021 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package whatsmeow
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
waProto "go.mau.fi/whatsmeow/binary/proto"
|
||||
"go.mau.fi/whatsmeow/socket"
|
||||
"go.mau.fi/whatsmeow/util/keys"
|
||||
)
|
||||
|
||||
const NoiseHandshakeResponseTimeout = 20 * time.Second
|
||||
|
||||
// doHandshake implements the Noise_XX_25519_AESGCM_SHA256 handshake for the WhatsApp web API.
|
||||
func (cli *Client) doHandshake(fs *socket.FrameSocket, ephemeralKP keys.KeyPair) error {
|
||||
nh := socket.NewNoiseHandshake()
|
||||
nh.Start(socket.NoiseStartPattern, fs.Header)
|
||||
nh.Authenticate(ephemeralKP.Pub[:])
|
||||
data, err := proto.Marshal(&waProto.HandshakeMessage{
|
||||
ClientHello: &waProto.ClientHello{
|
||||
Ephemeral: ephemeralKP.Pub[:],
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal handshake message: %w", err)
|
||||
}
|
||||
err = fs.SendFrame(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send handshake message: %w", err)
|
||||
}
|
||||
var resp []byte
|
||||
select {
|
||||
case resp = <-fs.Frames:
|
||||
case <-time.After(NoiseHandshakeResponseTimeout):
|
||||
return fmt.Errorf("timed out waiting for handshake response")
|
||||
}
|
||||
var handshakeResponse waProto.HandshakeMessage
|
||||
err = proto.Unmarshal(resp, &handshakeResponse)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal handshake response: %w", err)
|
||||
}
|
||||
serverEphemeral := handshakeResponse.GetServerHello().GetEphemeral()
|
||||
serverStaticCiphertext := handshakeResponse.GetServerHello().GetStatic()
|
||||
certificateCiphertext := handshakeResponse.GetServerHello().GetPayload()
|
||||
if len(serverEphemeral) != 32 || serverStaticCiphertext == nil || certificateCiphertext == nil {
|
||||
return fmt.Errorf("missing parts of handshake response")
|
||||
}
|
||||
serverEphemeralArr := *(*[32]byte)(serverEphemeral)
|
||||
|
||||
nh.Authenticate(serverEphemeral)
|
||||
err = nh.MixSharedSecretIntoKey(*ephemeralKP.Priv, serverEphemeralArr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mix server ephemeral key in: %w", err)
|
||||
}
|
||||
|
||||
staticDecrypted, err := nh.Decrypt(serverStaticCiphertext)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt server static ciphertext: %w", err)
|
||||
} else if len(staticDecrypted) != 32 {
|
||||
return fmt.Errorf("unexpected length of server static plaintext %d (expected 32)", len(staticDecrypted))
|
||||
}
|
||||
err = nh.MixSharedSecretIntoKey(*ephemeralKP.Priv, *(*[32]byte)(staticDecrypted))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mix server static key in: %w", err)
|
||||
}
|
||||
|
||||
certDecrypted, err := nh.Decrypt(certificateCiphertext)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt noise certificate ciphertext: %w", err)
|
||||
}
|
||||
var cert waProto.NoiseCertificate
|
||||
err = proto.Unmarshal(certDecrypted, &cert)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal noise certificate: %w", err)
|
||||
}
|
||||
certDetailsRaw := cert.GetDetails()
|
||||
certSignature := cert.GetSignature()
|
||||
if certDetailsRaw == nil || certSignature == nil {
|
||||
return fmt.Errorf("missing parts of noise certificate")
|
||||
}
|
||||
var certDetails waProto.NoiseCertificateDetails
|
||||
err = proto.Unmarshal(certDetailsRaw, &certDetails)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal noise certificate details: %w", err)
|
||||
} else if !bytes.Equal(certDetails.GetKey(), staticDecrypted) {
|
||||
return fmt.Errorf("cert key doesn't match decrypted static")
|
||||
}
|
||||
|
||||
encryptedPubkey := nh.Encrypt(cli.Store.NoiseKey.Pub[:])
|
||||
err = nh.MixSharedSecretIntoKey(*cli.Store.NoiseKey.Priv, serverEphemeralArr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to mix noise private key in: %w", err)
|
||||
}
|
||||
|
||||
clientFinishPayloadBytes, err := proto.Marshal(cli.Store.GetClientPayload())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal client finish payload: %w", err)
|
||||
}
|
||||
encryptedClientFinishPayload := nh.Encrypt(clientFinishPayloadBytes)
|
||||
data, err = proto.Marshal(&waProto.HandshakeMessage{
|
||||
ClientFinish: &waProto.ClientFinish{
|
||||
Static: encryptedPubkey,
|
||||
Payload: encryptedClientFinishPayload,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal handshake finish message: %w", err)
|
||||
}
|
||||
err = fs.SendFrame(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send handshake finish message: %w", err)
|
||||
}
|
||||
|
||||
ns, err := nh.Finish(fs, cli.handleFrame, cli.onDisconnect)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create noise socket: %w", err)
|
||||
}
|
||||
|
||||
cli.socket = ns
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user