private RemotePlayContext SendBigBangMessages(Socket udpClient, Session session, RemotePlayContext remotePlayContext)
        {
            /******** Big Payload send ********/

            // Generate random handshake key, for ECDH pubkey signature calculation
            byte[] handshakeKey = new byte[16];
            new Random().NextBytes(handshakeKey);

            // Generate ECDH keypair
            var ecdhKeyPair = CryptoService.GenerateEcdhKeyPair();
            // Get public key bytes
            var ownPublicKey = Session.GetPublicKeyBytesFromKeyPair(ecdhKeyPair);

            // Calculate ECDH pubkey signature
            var ecdhSignature = Session.CalculateHMAC(handshakeKey, ownPublicKey);

            int    unixTimestamp = (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
            string timestampUnix = unixTimestamp.ToString();
            string sessionKey    = timestampUnix + CryptoService.GetUniqueKey(64);

            LaunchSpecification launchSpecs = LaunchSpecification.GetStandardSpecs("sessionId123", handshakeKey);

            byte[] launchSpecBuffer = Encoding.UTF8.GetBytes(launchSpecs.Serialize());

            byte[] cryptoBuffer = new byte[launchSpecBuffer.Length];
            cryptoBuffer = session.Encrypt(cryptoBuffer, 0);
            byte[] newLaunchSpec = new byte[launchSpecBuffer.Length];
            for (int i = 0; i < launchSpecBuffer.Length; i++)
            {
                newLaunchSpec[i] = (byte)(launchSpecBuffer[i] ^ cryptoBuffer[i]);
            }

            TakionMessage takionBigPayloadMessage = new TakionMessage
            {
                Type       = TakionMessage.PayloadType.Big,
                bigPayload = new BigPayload
                {
                    clientVersion = 9,
                    sessionKey    = sessionKey,
                    launchSpec    = Convert.ToBase64String(newLaunchSpec),
                    encryptedKey  = new byte[] { 0, 0, 0, 0 },
                    ecdhPubKey    = ownPublicKey,
                    ecdhSig       = ecdhSignature
                }
            };

            MemoryStream bigPayloadStream = new MemoryStream();

            Serializer.Serialize(bigPayloadStream, takionBigPayloadMessage);
            byte[] bigPayloadBuffer = ByteUtil.ConcatenateArrays(new byte[1], bigPayloadStream.ToArray()); // Padding byte + BigPayload
            ushort bigPayloadSize   = (ushort)(12 + bigPayloadBuffer.Length);

            ControlMessage controlMessageBigPayload = new ControlMessage(0, remotePlayContext.ReceiverId, 0, 0, 0, 1, bigPayloadSize, remotePlayContext.FuncIncr, 0x10000);

            controlMessageBigPayload.UnParsedPayload = bigPayloadBuffer;
            byte[] initialControlMessage2Data = GetByteArrayForControlMessage(controlMessageBigPayload);

            OnPs4LogInfo?.Invoke(this, Environment.NewLine + "Sending big payload:");
            OnPs4LogInfo?.Invoke(this, "ECDH pubkey: " + HexUtil.Hexlify(takionBigPayloadMessage.bigPayload.ecdhPubKey));
            OnPs4LogInfo?.Invoke(this, "ECDH sig: " + HexUtil.Hexlify(takionBigPayloadMessage.bigPayload.ecdhSig));
            OnPs4LogInfo?.Invoke(this, "Session key: " + takionBigPayloadMessage.bigPayload.sessionKey + Environment.NewLine);

            ControlResult bigPayloadResult = SendControlDataAndWaitForAnswer(udpClient, initialControlMessage2Data, 2, "Send BigPayload");

            if (!bigPayloadResult.WasSuccessful)
            {
                return(null);
            }

            /******** Bang Payload receive ********/

            ControlMessage answerPacket1 = bigPayloadResult.ControlMessages[0];
            ControlMessage answerPacket2 = bigPayloadResult.ControlMessages[1];

            if (answerPacket1.ProtoBuffFlag != 1 && answerPacket2.ProtoBuffFlag != 1)
            {
                return(null);
            }

            TakionMessage bangPayload = answerPacket1.ProtoBuffFlag == 1 ?
                                        Serializer.Deserialize <TakionMessage>(new MemoryStream(answerPacket1.UnParsedPayload)) :
                                        Serializer.Deserialize <TakionMessage>(new MemoryStream(answerPacket2.UnParsedPayload));

            if (bangPayload.bangPayload == null)
            {
                return(null);
            }

            ControlMessage bangPayloadControl = answerPacket1.ProtoBuffFlag == 1 ? answerPacket1 : answerPacket2;

            OnPs4LogInfo?.Invoke(this, Environment.NewLine + "Received bang payload:");
            OnPs4LogInfo?.Invoke(this, "ECDH pubkey: " + HexUtil.Hexlify(bangPayload.bangPayload.ecdhPubKey));
            OnPs4LogInfo?.Invoke(this, "ECDH sig: " + HexUtil.Hexlify(bangPayload.bangPayload.ecdhSig));
            OnPs4LogInfo?.Invoke(this, "Session key: " + bangPayload.bangPayload.sessionKey);

            /* Derive ECDH shared secret */
            var foreignPubkeyParams = Session.ConvertPubkeyBytesToCipherParams(bangPayload.bangPayload.ecdhPubKey);

            remotePlayContext.SharedSecret   = Session.GenerateSharedSecret(ecdhKeyPair.Private, foreignPubkeyParams);
            remotePlayContext.LocalGmacInfo  = CryptoService.SetUpGmac(2, handshakeKey, remotePlayContext.SharedSecret);
            remotePlayContext.RemoteGmacInfo = CryptoService.SetUpGmac(3, handshakeKey, remotePlayContext.SharedSecret);
            OnPs4LogInfo?.Invoke(this, "HANDSHAKE KEY: " + HexUtil.Hexlify(handshakeKey));
            OnPs4LogInfo?.Invoke(this, "SHARED SECRET: " + HexUtil.Hexlify(remotePlayContext.SharedSecret));

            byte[]         ackBangPayload        = HexUtil.Unhexlify("00000000");
            ushort         ackBangPayloadSize    = (ushort)(12 + ackBangPayload.Length);
            ControlMessage ackBangPayloadMessage = new ControlMessage(0, bangPayloadControl.FuncIncr, 0, 0, 3, 0, ackBangPayloadSize, bangPayloadControl.FuncIncr, 0x19000);

            ackBangPayloadMessage.UnParsedPayload = ackBangPayload;
            byte[] ackBangPayloadMessageData = GetByteArrayForControlMessage(ackBangPayloadMessage);
            remotePlayContext.LastSentMessage = ackBangPayloadMessageData;

            SendData(udpClient, ackBangPayloadMessageData);

            return(remotePlayContext);
        }
Esempio n. 2
0
        private void HandleControlMessage(byte[] payload, Session session)
        {
            if (payload[0] == 0) // Control Packet
            {
                byte[]         message        = payload;
                ControlMessage controlMessage = new ControlMessage();
                using (MemoryStream memoryStream = new MemoryStream(message, 0, message.Length))
                    using (BinaryReader binaryWriter = new BinaryReader(memoryStream))
                    {
                        controlMessage.Deserialize(binaryWriter);
                    }

                if (controlMessage.ProtoBuffFlag == 1 && controlMessage.PLoadSize > 100)
                {
                    TakionMessage takionMessage = ProtobufUtil.Deserialize <TakionMessage>(controlMessage.UnParsedPayload);

                    if (takionMessage.bigPayload != null)
                    {
                        this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("!!! Big payload session key: " + takionMessage.bigPayload.sessionKey)));
                        this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("!!! Big payload ecdh pub key in hex: " + HexUtil.Hexlify(takionMessage.bigPayload.ecdhPubKey))));
                        this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("!!! Big payload ecdh sig in hex: " + HexUtil.Hexlify(takionMessage.bigPayload.ecdhSig))));
                        if (session != null)
                        {
                            byte[] launchSpecBuffer = Convert.FromBase64String(takionMessage.bigPayload.launchSpec);
                            byte[] cryptoBuffer     = new byte[launchSpecBuffer.Length];
                            cryptoBuffer = session.Encrypt(cryptoBuffer, 0);
                            byte[] newLaunchSpec = new byte[launchSpecBuffer.Length];
                            for (int j = 0; j < launchSpecBuffer.Length; j++)
                            {
                                newLaunchSpec[j] = (byte)(launchSpecBuffer[j] ^ cryptoBuffer[j]);
                            }

                            string launchSpecs = Encoding.UTF8.GetString(newLaunchSpec);
                            LaunchSpecification launchSpecJsonObject = LaunchSpecification.Deserialize(launchSpecs);
                            byte[] handshakeKey = launchSpecJsonObject.HandshakeKey;

                            if (handshakeKey != null)
                            {
                                this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("!!! Big payload handshake key in launchSpec in hex: " + HexUtil.Hexlify(handshakeKey))));
                                var ecdhSignatureVerification = Session.CalculateHMAC(handshakeKey, takionMessage.bigPayload.ecdhPubKey);

                                if (ecdhSignatureVerification.SequenceEqual(takionMessage.bigPayload.ecdhSig))
                                {
                                    this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("ECDH Signature matches!")));
                                }
                                else
                                {
                                    this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("!!!! ECDH Signature mismatch")));
                                }
                            }
                            this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("!!! Big payload full launchSpec: " + Environment.NewLine + launchSpecJsonObject.Serialize() + Environment.NewLine)));
                        }
                        else
                        {
                            this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox(Environment.NewLine)));
                        }
                    }
                    else if (takionMessage.bangPayload != null)
                    {
                        this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("!!! Bang payload session key: " + takionMessage.bangPayload.sessionKey)));
                        this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("!!! Bang payload ecdh pub key in hex: " + HexUtil.Hexlify(takionMessage.bangPayload.ecdhPubKey))));
                        this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("!!! Bang payload ecdh sig in hex: " + HexUtil.Hexlify(takionMessage.bangPayload.ecdhSig) + Environment.NewLine)));
                    }
                }
                else
                {
                    if (controlMessage.Crypto != 0)
                    {
                        this.textBoxPcapLogOutput.Invoke(new MethodInvoker(() => AppendLogOutputToPcapLogTextBox("!!! Control message with crypto value: " + HexUtil.Hexlify(ByteUtil.UIntToByteArray(controlMessage.Crypto)))));
                    }
                }
            }
        }