예제 #1
0
        public static byte[] CreateTransportPacket(TransportPacket packet)
        {
            // [TNW]:[TYPE]:[VERSION]:[DATA_SIZE]:[DATA]:[EOP] : MIN SIZE 12 Bytes
            // TNW      : 'T', 'N', 'W' : 3 BYTES
            // TYPE     : 1 BYTE
            // VERSION  : 1 BYTE
            // DATA_SZ  : 4 BYTES [Little Endian Byte Order]
            // DATA     : DATA_SZ BYTES
            // EOP      : 'E', 'O', 'P' : 3 BYTES

            MemoryStream ms = new MemoryStream();

            ms.WriteByte((byte)'T');
            ms.WriteByte((byte)'N');
            ms.WriteByte((byte)'W');
            ms.WriteByte((byte)packet.Type);
            ms.WriteByte((byte)packet.Version);
            ms.Write(Utils.GetLengthAsBytes(packet.Data.Length), 0, 4);
            ms.Write(packet.Data, 0, packet.Data.Length);
            ms.WriteByte((byte)'E');
            ms.WriteByte((byte)'O');
            ms.WriteByte((byte)'P');

            return ms.ToArray();
        }
예제 #2
0
 public static async Task SendTransportPacket(NetworkStream sw, TransportPacketType type, byte[] Data)
 {
     TransportPacket tp = new TransportPacket(Data, type, Constants.TransportVersion);
     byte[] msg = PacketCodec.CreateTransportPacket(tp);
     sw.Write(msg, 0, msg.Length);
     await sw.FlushAsync();
 }
        //System.Diagnostics.Stopwatch sw_timer = new System.Diagnostics.Stopwatch();

        async Task ProcessIncomingUserInternal(IncomingClient iClient, TransportPacket p)
        {
            BinaryReader reader = new BinaryReader(iClient.client.GetStream());
            //BinaryWriter writer = new BinaryWriter(iClient.client.GetStream());

            NetworkStream writer = iClient.client.GetStream();

            //DisplayUtils.Display("Packet Received: " + p.Type);

            switch (p.Type)
            {
                case TransportPacketType.Initialize:

                    iClient.ConnTimeStart = DateTime.UtcNow.Ticks;

                    //DisplayUtils.Display("Init Received", DisplayType.Info);

                    if ((!iClient.WorkProven) && (!iClient.KeyExchanged))
                    {
                        await PacketSender.SendTransportPacket(writer, TransportPacketType.WorkProofRequest, iClient.WorkTask);
                    }

                    break;

                case TransportPacketType.WorkProofKeyResponse:
                    //DisplayUtils.Display("WorkProofResponse Received : " + p.Data.Length, DisplayType.Info);

                    if ((!iClient.WorkProven) && (!iClient.KeyExchanged))
                    {
                        if (p.Data.Length == 60)
                        {
                            Constants.SERVER_GLOBAL_AUTH_PACKETS++;

                            byte[] Proof = new byte[4];
                            byte[] DHClientPublic = new byte[32];
                            byte[] AuthRandom = new byte[24];

                            Array.Copy(p.Data, 0, Proof, 0, 4);
                            Array.Copy(p.Data, 4, DHClientPublic, 0, 32);
                            Array.Copy(p.Data, 36, AuthRandom, 0, 24);

                            iClient.WorkProven = WorkProof.VerifyProof(iClient.WorkTask, Proof, Constants.Difficulty);

                            if (iClient.WorkProven)
                            {
                                //DisplayUtils.Display("Work Proved", DisplayType.Info);
                                Common.rngCsp.GetBytes(iClient.DHRandomBytes);

                                iClient.DHPrivateKey = Curve25519.ClampPrivateKey(iClient.DHRandomBytes);
                                iClient.DHPublicKey = Curve25519.GetPublicKey(iClient.DHPrivateKey);

                                // Generate the shared-secret using the provided client Public Key
                                byte[] sharedSecret = (new SHA512Managed()).ComputeHash(Curve25519.GetSharedSecret(iClient.DHPrivateKey, DHClientPublic));

                                Array.Copy(sharedSecret, iClient.TransportKey, 32);
                                Array.Copy(sharedSecret, 32, iClient.AuthenticationKey, 0, 32);

                                // Sign the data using the Node-Private key, so that the client can know that the connection is secure.
                                // This thwarts MITM attacks.
                                byte[] Client_ServerAuthSignature = nodeConfig.SignDataWithPrivateKey(AuthRandom);

                                // 64 bytes Signature
                                byte[] signPlain = Client_ServerAuthSignature;

                                if (signPlain.Length != 64) throw new Exception("Improbable Assertion failed : 1");

                                // Encrypt the Signature and Identifier using Salsa20
                                byte[] signCrypted = Salsa20.ProcessSalsa20(signPlain, iClient.TransportKey, new byte[8], 0);

                                // EtM -> Encrypt then MAC
                                byte[] signMAC = (new HMACSHA256(iClient.AuthenticationKey)).ComputeHash(signCrypted);

                                // SERVER_PUBLIC[32] || signMAC[32] || signCrypted[64] => 128 bytes
                                byte[] KeysSignature = iClient.DHPublicKey.Concat(signMAC).Concat(signCrypted).ToArray();

                                await PacketSender.SendTransportPacket(writer, TransportPacketType.ServerPublicTransfer, KeysSignature);
                            }
                            else
                            {
                                DisplayUtils.Display("Work Proof invalid : " + p.Data.Length, DisplayType.Exception);
                                await PacketSender.SendTransportPacket(writer, TransportPacketType.InvalidAuthDisconnect, new byte[0]);
                            }
                        }
                        else
                        {
                            DisplayUtils.Display("Invalid Packet Length : " + p.Data.Length, DisplayType.Exception);
                            await PacketSender.SendTransportPacket(writer, TransportPacketType.InvalidAuthDisconnect, new byte[0]);
                        }
                    }

                    break;

                case TransportPacketType.KeyExComplete_1:

                    if ((iClient.WorkProven) && (!iClient.KeyExchanged))
                    {
                        if (p.Data.Length == 128)
                        {
                            // cryptedSigPK_MAC[32] || cryptedSigPK[96] = 128 bytes

                            byte[] cryptedSigPK_MAC = new byte[32];
                            byte[] cryptedSigPK = new byte[96];

                            Array.Copy(p.Data, 0, cryptedSigPK_MAC, 0, 32);
                            Array.Copy(p.Data, 32, cryptedSigPK, 0, 96);

                            byte[] cryptedSigPK_MAC_Expected = (new HMACSHA256(iClient.AuthenticationKey)).ComputeHash(cryptedSigPK);

                            if (CryptoBytes.ConstantTimeEquals(cryptedSigPK_MAC_Expected, cryptedSigPK_MAC))
                            {
                                byte[] workSignPK = Salsa20.ProcessSalsa20(cryptedSigPK, iClient.TransportKey, new byte[8], 0);

                                // workSignPK[96]  = workSign[64] || nodeConfig.PublicKey[32]

                                byte[] workSign = new byte[64];
                                byte[] remotePK = new byte[32];

                                Array.Copy(workSignPK, 0, workSign, 0, 64);
                                Array.Copy(workSignPK, 64, remotePK, 0, 32);

                                bool serverVerified = Ed25519.Verify(workSign, iClient.WorkTask, remotePK);

                                if (serverVerified)
                                {
                                    iClient.PublicKey = new Hash(remotePK);

                                    if (Constants.NetworkVerbosity >= Verbosity.Info)
                                    {
                                        /*DisplayUtils.Display(NodeSocketData.GetString(nodeSocketData) + " : Key Exchanged 1: Shared KEY [TransportKey] : {" +
                                            (HexUtil.ToString(TransportKey)) + "}", DisplayType.Info);*/

                                        DisplayUtils.Display(iClient.PublicKey.ToString() + " Client Authenticated", DisplayType.Info);
                                    }

                                    await PacketSender.SendTransportPacket(writer, TransportPacketType.KeyExComplete_2, new byte[0]);

                                    iClient.KeyExchanged = true;

                                    IncomingConnections.Add(iClient.PublicKey, iClient);

                                    DisplayUtils.Display("Exchange Complete 2, Shared KEY [TransportKey] : " + HexUtil.ToString(iClient.TransportKey), DisplayType.Info);

                                }
                            }
                        }
                    }

                    break;

                case TransportPacketType.DataCrypted:

                    if (iClient.KeyExchanged && p.Data.Length > 28)
                    {
                        Constants.SERVER_GLOBAL_DATA_PACKETS++;

                        byte[] nonce = new byte[8];
                        byte[] hmac = new byte[16];
                        byte[] crypted_data = new byte[p.Data.Length - 24];

                        Array.Copy(p.Data, 0, nonce, 0, 8);
                        Array.Copy(p.Data, 8, hmac, 0, 16);
                        Array.Copy(p.Data, 24, crypted_data, 0, crypted_data.Length);

                        byte[] MAC_EXPECTED = (new HMACSHA256(iClient.AuthenticationKey)).ComputeHash(crypted_data).Take(16).ToArray();

                        if (CryptoBytes.ConstantTimeEquals(MAC_EXPECTED, hmac))
                        {
                            byte[] DeCryptedData = Salsa20.ProcessSalsa20(crypted_data, iClient.TransportKey, nonce, 0);

                            byte[] counter = new byte[4];
                            byte[] rec_data = new byte[p.Data.Length - 28];

                            Array.Copy(DeCryptedData, 0, counter, 0, 4);
                            Array.Copy(DeCryptedData, 4, rec_data, 0, rec_data.Length);

                            Array.Copy(DeCryptedData, 0, counter, 0, 4);
                            Array.Copy(DeCryptedData, 4, rec_data, 0, rec_data.Length);

                            NetworkPacket np = new NetworkPacket();

                            np.Deserialize(rec_data);

                            if (iClient.PublicKey == np.PublicKeySource)
                            {
                                if (PacketReceived != null)
                                    PacketReceived(np);
                            }
                            else
                            {
                                DisplayUtils.Display("Packet Source Incoming Mismatch", DisplayType.Warning);
                            }

                        }
                        else
                        {
                            DisplayUtils.Display("HMAC FAILED : ");
                        }
                    }

                    break;
            }
        }
예제 #4
0
        async private Task ProcessOutgoingConnectionInternal(TcpClient client, TransportPacket p)
        {
            BinaryReader reader = new BinaryReader(client.GetStream());
            NetworkStream writer = client.GetStream();

            switch (p.Type) // Decode received messages from Server.
            {

                case TransportPacketType.WorkProofRequest:

                    // INPUT : 24 Bytes of (random[16] + timestamp[8])
                    // OUTPUT : 4 bytes Proof, 32 Bytes of KeypairPublic, 16 Bytes Random => 52 bytes
                    if (p.Data.Length == 24)
                    {
                        //DisplayUtils.Display(NodeSocketData.GetString(nodeSocketData) + " : WorkProofRequest Received : " + p.Data.Length, DisplayType.Info);

                        byte[] Proof = WorkProof.CalculateProof(p.Data, Constants.Difficulty);

                        WorkTask = p.Data;

                        byte[] rv = new byte[Proof.Length + DH_PublicKey.Length + AuthRandom.Length /*+ Sig_WorkTask.Length*/];

                        Buffer.BlockCopy(Proof, 0, rv, 0, Proof.Length);
                        Buffer.BlockCopy(DH_PublicKey, 0, rv, Proof.Length, DH_PublicKey.Length);
                        Buffer.BlockCopy(AuthRandom, 0, rv, Proof.Length + DH_PublicKey.Length, AuthRandom.Length);

                        await PacketSender.SendTransportPacket(writer, TransportPacketType.WorkProofKeyResponse, rv);
                    }

                    break;

                case TransportPacketType.ServerPublicTransfer:

                    // SERVER_PUBLIC[32] || SIGN_MAC[32] || Sign_Crypted[64] => 128 bytes
                    if (p.Data.Length == 128)
                    {
                        byte[] serverPublic = new byte[32];
                        byte[] signMAC = new byte[32];
                        byte[] signCrypted = new byte[64];

                        Array.Copy(p.Data, 0, serverPublic, 0, 32);
                        Array.Copy(p.Data, 32, signMAC, 0, 32);
                        Array.Copy(p.Data, 64, signCrypted, 0, 64);

                        byte[] sharedSecret = (new SHA512Managed()).ComputeHash(Curve25519.GetSharedSecret(DH_PrivateKey, serverPublic));

                        Array.Copy(sharedSecret, TransportKey, 32);
                        Array.Copy(sharedSecret, 32, AuthenticationKey, 0, 32);

                        byte[] SIGN_ID_MAC_EXPECTED = (new HMACSHA256(AuthenticationKey)).ComputeHash(signCrypted);

                        if (CryptoBytes.ConstantTimeEquals(SIGN_ID_MAC_EXPECTED, signMAC))
                        {
                            byte[] Sign_Plain = Salsa20.ProcessSalsa20(signCrypted, TransportKey, new byte[8], 0);

                            // The remote node should be able to identify itself properly. 
                            bool serverVerified = Ed25519.Verify(Sign_Plain, AuthRandom, nodeSocketData.PublicKey.Hex);

                            if (serverVerified)
                            {
                                if (Constants.NetworkVerbosity >= Verbosity.Info)
                                {
                                    DisplayUtils.Display(NodeSocketData.GetString(nodeSocketData) + " : Key Exchanged 1: Shared KEY [TransportKey] : {" +
                                        (HexUtil.ToString(TransportKey)) + "}", DisplayType.Info);

                                    DisplayUtils.Display(NodeSocketData.GetString(nodeSocketData) + " : Server Authenticated 1", DisplayType.Info);
                                }

                                // workSignPK[96]  = workSign[64] || nodeConfig.PublicKey[32]

                                // Sign the WorkTask with private key.
                                byte[] workSign = nodeConfig.SignDataWithPrivateKey(WorkTask);

                                byte[] workSignPK = new byte[96]; // 64 + 32

                                Array.Copy(workSign, workSignPK, 64);
                                Array.Copy(nodeConfig.PublicKey.Hex, 0, workSignPK, 64, 32);

                                // cryptedSigPK_MAC[32] || cryptedSigPK[96]

                                byte[] cryptedSigPK = Salsa20.ProcessSalsa20(workSignPK, TransportKey, new byte[8], 0);
                                byte[] cryptedSigPK_MAC = (new HMACSHA256(AuthenticationKey)).ComputeHash(cryptedSigPK);

                                byte[] macSigPK = new byte[128]; // 32 + 96
                                Array.Copy(cryptedSigPK_MAC, macSigPK, 32);
                                Array.Copy(cryptedSigPK, 0, macSigPK, 32, 96);

                                await PacketSender.SendTransportPacket(writer, TransportPacketType.KeyExComplete_1, macSigPK);

                                InterKeyExchanged = true;
                            }
                            else
                            {
                                if (Constants.NetworkVerbosity >= Verbosity.Errors)
                                    DisplayUtils.Display(NodeSocketData.GetString(nodeSocketData) + " : Remote Authentication Failed : Remote Node Could not authenticate itself", DisplayType.AuthFailure);
                            }
                        }
                        else
                        {
                            if (Constants.NetworkVerbosity >= Verbosity.Errors)
                                DisplayUtils.Display(NodeSocketData.GetString(nodeSocketData) + " : Server Authentication Failed : Server Could not authenticate itself : Invalid MAC ", DisplayType.AuthFailure);
                        }
                    }

                    break;

                case TransportPacketType.KeyExComplete_2:

                    if (InterKeyExchanged)
                    {
                        KeyExchanged = true;
                        if (Constants.NetworkVerbosity >= Verbosity.Info)
                        {
                            DisplayUtils.Display(NodeSocketData.GetString(nodeSocketData) + " : Key Exchanged 3 (Sync)", DisplayType.Info);
                        }
                    }

                    break;

                case TransportPacketType.KeepAlive:

                    if (p.Data.Length == 4)
                    {
                        uint pCounter = BitConverter.ToUInt32(p.Data, 0);
                        if (KeepAlives != null) KeepAlives(pCounter);
                    }

                    break;

                case TransportPacketType.DataCrypted:

                    if (KeyExchanged)
                    {
                        if (p.Data.Length >= 28)
                        {
                            byte[] nonce = new byte[8];
                            byte[] hmac = new byte[16];
                            byte[] crypted_data = new byte[p.Data.Length - 24];

                            Array.Copy(p.Data, 0, nonce, 0, 8);
                            Array.Copy(p.Data, 8, hmac, 0, 16);
                            Array.Copy(p.Data, 24, crypted_data, 0, crypted_data.Length);

                            byte[] MAC_EXPECTED = (new HMACSHA256(AuthenticationKey)).ComputeHash(crypted_data).Take(16).ToArray();

                            if (CryptoBytes.ConstantTimeEquals(MAC_EXPECTED, hmac))
                            {
                                byte[] DeCryptedData = new byte[p.Data.Length - 24];

                                DeCryptedData = Salsa20.ProcessSalsa20(crypted_data, TransportKey, nonce, 0);

                                byte[] counter = new byte[4];
                                byte[] rec_data = new byte[p.Data.Length - 28];

                                Array.Copy(DeCryptedData, 0, counter, 0, 4);
                                Array.Copy(DeCryptedData, 4, rec_data, 0, rec_data.Length);

                                NetworkPacket np = new NetworkPacket();

                                np.Deserialize(rec_data);

                                if (nodeSocketData.PublicKey == np.PublicKeySource)
                                {
                                    if (PacketReceived != null)
                                        PacketReceived(np);
                                }
                                else
                                {
                                    DisplayUtils.Display("Packet Source Outgoing Mismatch", DisplayType.Warning);
                                }

                            }
                            else
                            {
                                if (Constants.NetworkVerbosity >= Verbosity.Errors)
                                    DisplayUtils.Display(NodeSocketData.GetString(nodeSocketData) + " : HMAC FAILED : ");
                            }
                        }
                    }

                    break;

                default:

                    if (Constants.NetworkVerbosity >= Verbosity.Errors)
                        DisplayUtils.Display(NodeSocketData.GetString(nodeSocketData) + " : Unknown Packet received : " + p.Type.ToString());

                    break;
            }
        }