diff --git a/SPHERE/Blockchain/Block/Block.cs b/SPHERE/Blockchain/Block/Block.cs index 72c92bf..d3bcdbe 100644 --- a/SPHERE/Blockchain/Block/Block.cs +++ b/SPHERE/Blockchain/Block/Block.cs @@ -76,9 +76,6 @@ namespace SPHERE.Blockchain [JsonPropertyName("LastUpdateTime")] public required DateTime LastUpdateTime { get; set; } = new(); // Time stamp of last Update to the block by validated user. - [JsonPropertyName("EncryptionAlgorithm")] - public required string EncryptionAlgorithm { get; set; } = ""; // Algorithm used for encryption (e.g. AES256, RSA2048, ECDsa) - [JsonPropertyName("KeyUsagePolicies")] public required string? KeyUsagePolicies { get; set; } // Policies for key usage @@ -100,7 +97,7 @@ namespace SPHERE.Blockchain // Calculates the hash for the block public string CalculateBlockHash() { - string input = $"{BlockId}{PreviousHash}{BlockCreationTime}{EncryptionAlgorithm}{KeyUsagePolicies}"; + string input = $"{BlockId}{PreviousHash}{BlockCreationTime}{KeyUsagePolicies}"; using var sha256 = SHA256.Create(); byte[] inputBytes = Encoding.UTF8.GetBytes(input); byte[] hashBytes = sha256.ComputeHash(inputBytes); @@ -128,41 +125,45 @@ namespace SPHERE.Blockchain // Creating a Contact Block - public static Block CreateContactBlock(Node node, string nodeId, string previousHash, string encryptedContactData, EncryptionAlgorithm encryptionAlgorithm) + public static Block CreateContactBlock(Node node, string previousHash, Contact contact) { //Check to see if Keys exist. - PrivateKeyManager PrivateKeyManager = new(); + DateTime creationTime = DateTime.Now; + byte[] LSK = node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.LocalSymmetricKey); + if (LSK == null || LSK.Length == 0) + { + SystemLogger.Log($"Debug-CreateContactBlock: LocalSymmetricKey is null or empty"); + return null; + } + + byte[] encryptedContactData = Contact.BuildEncryptedContact(contact, LSK); var header = new BlockHeader { - BlockId = BlockHeader.GenerateBlockID(), + BlockId = contact.MetaData.ContactID, BlockType = BlockType.Contact.ToString(), BlockVersion = "1.0", PreviousHash = previousHash, BlockCreationTime = creationTime, LastUpdateTime = creationTime, - EncryptionAlgorithm = encryptionAlgorithm.ToString(), KeyUsagePolicies = "MESSAGE_ENCRYPTION_ONLY", - PublicSignatureKey = PrivateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalSignatureKey), - PublicEncryptionKey = PrivateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalEncryptionKey), - CreatorNodeId = nodeId, + PublicSignatureKey = node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalSignatureKey), + PublicEncryptionKey = node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalEncryptionKey), + CreatorNodeId = node.Peer.NodeId, }; - // Serialize and store contact data - string serializedContactData = JsonSerializer.Serialize(encryptedContactData); - header.BlockHash = header.CalculateBlockHash(); - - - return new Block + Block block = new Block { Header = header, - EncryptedContact = serializedContactData, - EncryptedLocalSymmetricKey = PrivateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.EncryptedLocalSymmetricKey), + EncryptedContact = Convert.ToBase64String(encryptedContactData), + EncryptedLocalSymmetricKey = node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.EncryptedLocalSymmetricKey), }; + + return block; } // Checks if a block is a contact block @@ -186,7 +187,6 @@ namespace SPHERE.Blockchain PreviousHash = previousHash, BlockCreationTime = creationTime, LastUpdateTime = creationTime, - EncryptionAlgorithm = encryptionAlgorithm.ToString(), KeyUsagePolicies = "MESSAGE_ENCRYPTION_ONLY", PublicSignatureKey =PrivateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalSignatureKey), PublicEncryptionKey =PrivateKeyManager.UseKeyInStorageContainer(node,KeyGenerator.KeyType.PublicPersonalEncryptionKey), @@ -227,7 +227,6 @@ namespace SPHERE.Blockchain PreviousHash = previousHash, BlockCreationTime = creationTime, LastUpdateTime = creationTime, - EncryptionAlgorithm = encryptionAlgorithm.ToString(), KeyUsagePolicies = "MESSAGE_ENCRYPTION_ONLY", PublicSignatureKey =PrivateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalSignatureKey), PublicEncryptionKey =PrivateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalEncryptionKey), diff --git a/SPHERE/Blockchain/Block/Contact.cs b/SPHERE/Blockchain/Block/Contact.cs index 2fd72eb..225cffe 100644 --- a/SPHERE/Blockchain/Block/Contact.cs +++ b/SPHERE/Blockchain/Block/Contact.cs @@ -1,22 +1,25 @@ using SPHERE.Configure; using SPHERE.Security; +using System.Collections.Generic; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text.Json; namespace SPHERE.Blockchain { public class Contact { - public ContactMetaData MetaData { get; set; } // Contacts needed MetaData. - public ContactKeys Keys { get; set; } // Contacts needed Encryption keys. - public EncryptedKeyParts KeySignatureParts { get; set; } // Contacts Private key is encrypted and stored in parts with noise - public EncryptedKeyParts KeyEncryptionParts { get; set; } // Contacts Private key is encrypted and stored in parts with noise - public List<(byte[], byte[])> AuthenticationData = new(); // Hashes user for User Authentication and VAlidation for Password reset and recovery. + public required ContactMetaData MetaData { get; set; } // Contacts needed MetaData. + public required ContactKeys Keys { get; set; } // Contacts needed Encryption keys. + public required EncryptedKeyParts KeySignatureParts { get; set; } // Contacts Private key is encrypted and stored in parts with noise + public required EncryptedKeyParts KeyEncryptionParts { get; set; } // Contacts Private key is encrypted and stored in parts with noise + public required List<(byte[], byte[])> AuthenticationData = new(); // Hashes user for User Authentication and VAlidation for Password reset and recovery. /// /// !!! /// To Create a contact and Generate Pairs of needed Private Keys, A password is needed to be passed in. This is a string meeting Requirements. (Needs Upper, Lower, Number, Symbol, and to be between 8-64 characters.) /// User Password.CreatePasswordFromString(string password) to generate a password from a string or Password.GenerateRandomPassword(int length) defaults to 16char. - /// + /// /// /// /// @@ -25,60 +28,81 @@ namespace SPHERE.Blockchain /// !!! /// /// - public static Contact CreateNewContact(Node node, string displayName, string name, string blockId, string? avatarURL, string? description, Password privateKeyPassword) + public static Contact CreateNewContact(Node node, string contactId, string alias, string name, Password privateKeyPassword, string pin) { - PrivateKeyManager PrivateKeyManager = new(); + PrivateKeyManager privateKeyManager = node.KeyManager; //Generate the set or Key Pairs needed (Signature and Communication pair) - KeyGenerator.GeneratePersonalKeyPairSets(privateKeyPassword); + KeyGenerator.GeneratePersonalKeyPairSets(node); var semiPublicKey = KeyGenerator.GenerateSymmetricKey(); - PrivateKeyManager.SetPrivatePersonalKey(semiPublicKey, KeyGenerator.KeyType.SemiPublicKey); + privateKeyManager.SetPrivatePersonalKey(node, semiPublicKey, KeyGenerator.KeyType.SemiPublicKey); //used to encrypt the contact var localSymmetricKey = KeyGenerator.GenerateSymmetricKey(); - PrivateKeyManager.SetPrivatePersonalKey(localSymmetricKey, KeyGenerator.KeyType.LocalSymmetricKey); + privateKeyManager.SetPrivatePersonalKey(node, localSymmetricKey, KeyGenerator.KeyType.LocalSymmetricKey); //the LocalSymmetricKey is Encrypted with the SemiPublicKey and attached to the block so only approved people with the semiPublicKey can decrypt the EncryptedLocalSymetricKey and then decrypt the contact. var encryptedLocalSymmetricKey = Encryption.EncryptLocalSymmetricKey(localSymmetricKey, semiPublicKey); - PrivateKeyManager.SetPrivatePersonalKey(encryptedLocalSymmetricKey, KeyGenerator.KeyType.EncryptedLocalSymmetricKey); - + + privateKeyManager.SetPrivatePersonalKey(node, encryptedLocalSymmetricKey, KeyGenerator.KeyType.EncryptedLocalSymmetricKey); + ContactKeys keys = new ContactKeys { - PublicPersonalEncryptionKey = PrivateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalEncryptionKey), - PublicPersonalSignatureKey = PrivateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalSignatureKey), + PublicPersonalEncryptionKey = privateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalEncryptionKey), + PublicPersonalSignatureKey = privateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalSignatureKey), SemiPublicKey = semiPublicKey, - LocalSymmetricKey = localSymmetricKey + EncryptedLocalSymmetricKey = encryptedLocalSymmetricKey + }; ContactMetaData metaData = new ContactMetaData { - DisplayName = displayName, + DisplayName = alias, Name = name, - AvatarURLHash = avatarURL, - Description = description, - + ContactID = contactId, + ContactVersion="V1.0" }; + + + EncryptedKeyParts encryptedSignatureKeyParts = node.KeyManager.EncryptPersonalKeyParts(node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PrivatePersonalSignatureKey), privateKeyPassword.ToString(), pin); + EncryptedKeyParts encryptedEncryptionKeyParts = node.KeyManager.EncryptPersonalKeyParts(node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PrivatePersonalEncryptionKey), privateKeyPassword.ToString(), pin); Contact contact = new Contact { MetaData = metaData, Keys = keys, - + KeySignatureParts = encryptedSignatureKeyParts, + KeyEncryptionParts = encryptedEncryptionKeyParts, + AuthenticationData = CredentialManager.GenerateStoredHashes(privateKeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicPersonalSignatureKey), privateKeyPassword.ToString(), pin, contactId), }; + + + return contact; } - public static byte[] BuildEncryptedContact(Contact contact) + public static byte[] BuildEncryptedContact(Contact contact, byte[] localSymmetricKey) { - - var encryptedContact = Encryption.EncryptWithSymmetric(contact, contact.Keys.LocalSymmetricKey); + + // Encrypt the serialized data + byte[] encryptedContact = Encryption.EncryptContactWithSymmetric(contact, localSymmetricKey); return encryptedContact; - } + public static Contact DecryptAndBuildContact(string encryptedContact, byte[] localSymmetricKey) + { + // Decode the Base64 data directly + + //byte[] decryptedBytes = Encryption.DecryptContactWithSymmetricKey(encryptedContact, localSymmetricKey); + + // Deserialize the Contact object + Contact contact = Encryption.DecryptContactWithSymmetricKey(encryptedContact, localSymmetricKey); ; + + return contact; + } /// /// The contact is intended to be the core of a block. It will be encrypted with a Local Symmetric Key before it is placed on the block. /// The purpose is to allow for users to control their data, but also gain the security and decentralization of a p2p DHT. @@ -101,9 +125,10 @@ namespace SPHERE.Blockchain /// public class ContactMetaData() { - public string DisplayName { get; set; } // User's display name - public string Name { get; set; } // Users Name - public string ContactVersion { get; set; } // Contact versions would allow for deserialization of different contact styles as the platform evolves. + public required string DisplayName { get; set; } // User's display name + public required string Name { get; set; } // Users Name + public required string ContactID { get; set; } // Contacts User ID (BLOCK ID) + public required string ContactVersion { get; set; } // Contact versions would allow for deserialization of different contact styles as the platform evolves. public string? HashedSSN { get; set; } // Users can provide a salted Hash of their SSN and this can be used later by applications to comparir it against the a hash of the ssn and key provided by the user. (Optional) public string? HashedCardNumber { get; set; } // Users can provide a salted Hash of their Card Number, this will by used by verification server when provided the cc and key by the user, if it can verify the hash it creates a 1 way payment tunnel from there to the merchants account. the merchant never sees the data (optional) public string? HashedAccountNumber { get; set; } // Users can provide a salted Hash of their Recount, this will by used by verification server when provided the account number and key by the user, if it can verify the hash it creates a 1 way payment tunnel from there to the merchants account.(optional) @@ -117,10 +142,10 @@ namespace SPHERE.Blockchain public class ContactKeys() { - public byte[] SemiPublicKey { get; set; } // Semi-public key - public byte[] LocalSymmetricKey { get; set; } // Unencrypted Local Symmetric code used to encrypt the Contact. - public byte[] PublicPersonalEncryptionKey { get; set; } // Personal Communication key for encrypting messages only the user can decrypt - public byte[] PublicPersonalSignatureKey { get; set; } // Used to verify signatures created with the PrivateSignatureKey + public required byte[] SemiPublicKey { get; set; } // Semi-public key + public required byte[] EncryptedLocalSymmetricKey { get; set; } // Unencrypted Local Symmetric code used to encrypt the Contact. + public required byte[] PublicPersonalEncryptionKey { get; set; } // Personal Communication key for encrypting messages only the user can decrypt + public required byte[] PublicPersonalSignatureKey { get; set; } // Used to verify signatures created with the PrivateSignatureKey } } diff --git a/SPHERE/Blockchain/Block/Node.cs b/SPHERE/Blockchain/Block/Node.cs index 93a0d7e..d94f48f 100644 --- a/SPHERE/Blockchain/Block/Node.cs +++ b/SPHERE/Blockchain/Block/Node.cs @@ -102,7 +102,7 @@ namespace SPHERE.Blockchain //create a node. Node node = new Node(); string nodeId = GenerateKademliaId(); - //Create a client for the node using STUN. + try { @@ -153,9 +153,27 @@ namespace SPHERE.Blockchain try { // Load DHT state (internal locking already handled by LoadState) - if (File.Exists(DHT.GetAppDataPath("DHT"))) + if (File.Exists(DHT.GetAppDataPath(node, "ContactDHT"))) { - node.ContactDHT.LoadState(); + node.ContactDHT.LoadState(node,"ContactDHT"); + } + else + { + SystemLogger.Log("DHT state file not found. Starting with a fresh state."); + } + + if (File.Exists(DHT.GetAppDataPath(node, "TransactionDHT"))) + { + node.TransactionDHT.LoadState(node, "TransactionDHT"); + } + else + { + SystemLogger.Log("DHT state file not found. Starting with a fresh state."); + } + + if (File.Exists(DHT.GetAppDataPath(node, "ReputationDHT"))) + { + node.ReputationDHT.LoadState(node, "ReputationDHT"); } else { @@ -174,9 +192,9 @@ namespace SPHERE.Blockchain try { // Load RoutingTable state (internal locking already handled by LoadState) - if (File.Exists(DHT.GetAppDataPath("RT"))) + if (File.Exists(DHT.GetAppDataPath(node, "RT"))) { - node.RoutingTable.LoadRoutingTable(); + node.RoutingTable.LoadRoutingTable(node, "RT"); } else { @@ -190,29 +208,23 @@ namespace SPHERE.Blockchain { SystemLogger.Log($"Error loading RoutingTable state: {ex.Message}"); SystemLogger.Log("Starting with a fresh state."); - node.RoutingTable = new RoutingTable(); // Reinitialize + node.RoutingTable = new RoutingTable(); } + node.RoutingTable.node = node; return node; } //This is used to Create the Node and Listener or Load one if it exists. - public static Node CreateNodeWithClientListenerUsingSTUN(NodeType nodeType) + public static Node CreateNodeUsingSTUN(NodeType nodeType) { - - - //create a node. + SystemLogger.Log($"Debug-CreateNodeWithClientUsingSTUN: Creating Node with STUN"); Node node = new Node(); node.Peer.NodeId = Node.GenerateKademliaId(); node.KeyManager = new(); node.KeyManager.SetNodeEncryptionFilePath(node); - //Create a client get listeners using STUN. - - Client client = new Client(); - - - // Thread-safe key generation - lock (stateLock) + node.Client = new Client(); + try { try { @@ -225,78 +237,129 @@ namespace SPHERE.Blockchain Console.WriteLine($"Error-CreateTestNodeWithFakeSTUNAsync: Generating Key pairs. Reason: {ex.Message}"); throw; } - } - client.StartClientListenerWithSTUNSync(node, client); - node.Client = client; - try - { - // Initialize PeerHeader - Peer peer = new Peer + var stun = new STUN(); + var (PublicIP, PublicPort) = stun.GetPublicEndpoint(); + SystemLogger.Log($"Debug-CreateNodeWithClientUsingSTUN: STUN Returned an IP of: {PublicIP}."); + SystemLogger.Log($"Debug-CreateNodeWithClientUsingSTUN: STUN Returned a Port of: {PublicPort}."); + + string testModeEnv = Environment.GetEnvironmentVariable("SPHERE_TEST_MODE"); + SystemLogger.Log($"Debug-CreateNodeWithClientUsingSTUN: Test mode: {testModeEnv}."); + node.Client.clientIP = node.Client.GetLocalIPAddress(); + if (testModeEnv!="true") { - Node_Type = nodeType, - NodeIP = client.clientIP.ToString(), - NodePort = client.clientListenerPort, - PreviousNodesHash = DefaultPreviousHash, // Placeholder value - PublicSignatureKey = node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicNodeSignatureKey), - PublicEncryptKey = node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicNodeEncryptionKey), - }; + node.Client.clientIP = PublicIP; + } + node.Client.clientListenerPort = PublicPort; + + + try + { + Console.WriteLine("Initializing Peer Header..."); + Peer peer = new Peer + { + Node_Type = nodeType, + NodeId = node.Peer.NodeId, + NodeIP = node.Client.clientIP.ToString(), + NodePort = PublicPort, + PreviousNodesHash = Node.DefaultPreviousHash, + PublicSignatureKey = node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicNodeSignatureKey), + PublicEncryptKey = node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PublicNodeEncryptionKey), + }; + node.Peer = peer; + SystemLogger.Log($"Debug-CreateNodeWithClientUsingSTUN: Node Client IP of: {node.Client.clientIP.ToString()}."); + SystemLogger.Log($"Debug-CreateNodeWithClientUsingSTUN: Node Client Port of: {node.Client.clientListenerPort}."); + + SystemLogger.Log($"Debug-CreateNodeWithClientUsingSTUN: Peer IP of: {node.Peer.NodeIP}."); + SystemLogger.Log($"Debug-CreateNodeWithClientUsingSTUN: Peer Port of: {node.Peer.NodePort}."); + } + catch (Exception ex) + { + Console.WriteLine($"Error Creating Peer Header: {ex.Message}"); + throw; + } + + try + { + // Load DHT state (internal locking already handled by LoadState) + if (File.Exists(DHT.GetAppDataPath(node, "ContactDHT"))) + { + node.ContactDHT.LoadState(node, "ContactDHT"); + } + else + { + SystemLogger.Log("ContactDHT state file not found. Starting with a fresh state."); + node.ContactDHT = new DHT(); + } + + if (File.Exists(DHT.GetAppDataPath(node, "ReputationDHT"))) + { + node.ReputationDHT.LoadState(node, "ReputationDHT"); + } + else + { + SystemLogger.Log("ReputationDHT state file not found. Starting with a fresh state."); + node.ReputationDHT = new DHT(); + } + + if (File.Exists(DHT.GetAppDataPath(node, "TransactionDHT"))) + { + node.TransactionDHT.LoadState(node, "TransactionDHT"); + } + else + { + SystemLogger.Log("TransactionDHT state file not found. Starting with a fresh state."); + node.TransactionDHT = new DHT(); + } + + + } + catch (Exception ex) + { + SystemLogger.Log($"Error loading DHT state: {ex.Message}"); + + + } + + try + { + // Load RoutingTable state (internal locking already handled by LoadState) + if (File.Exists(DHT.GetAppDataPath(node, "RT"))) + { + node.RoutingTable.LoadRoutingTable(node, "RT"); + } + else + { + SystemLogger.Log("Routing Table state file not found. Starting with a fresh state."); + node.RoutingTable = new RoutingTable(); + } + + + } + catch (Exception ex) + { + SystemLogger.Log($"Error loading RoutingTable state: {ex.Message}"); + } + + if (node != null) + { + SystemLogger.Log($"Debug-CreateNodeWithClientUsingSTUN: Node is build returning Node."); + node.Client.StartClientListenerAsync(node); + return node; + } + else + { + SystemLogger.Log($"Debug-CreateNodeWithClientUsingSTUN: Node was returned null."); + return null; + } + - // Assign header to node - node.Peer = peer; } catch (Exception ex) { - SystemLogger.Log($"Error retrieving or creating keys: {ex.Message}"); + Console.WriteLine($"Error CreatingNodeWithClientUsingStun: EndFail{ex.Message}"); throw; } - - // Initialize DHT - node.ContactDHT = new DHT(); - - try - { - // Load DHT state (internal locking already handled by LoadState) - if (File.Exists(DHT.GetAppDataPath("DHT"))) - { - node.ContactDHT.LoadState(); - } - else - { - SystemLogger.Log("DHT state file not found. Starting with a fresh state."); - } - - - } - catch (Exception ex) - { - SystemLogger.Log($"Error loading DHT state: {ex.Message}"); - SystemLogger.Log("Starting with a fresh state."); - node.ContactDHT = new DHT(); // Reinitialize - } - - try - { - // Load RoutingTable state (internal locking already handled by LoadState) - if (File.Exists(DHT.GetAppDataPath("RT"))) - { - node.RoutingTable.LoadRoutingTable(); - } - else - { - SystemLogger.Log("Routing Table state file not found. Starting with a fresh state."); - } - - - } - catch (Exception ex) - { - SystemLogger.Log($"Error loading RoutingTable state: {ex.Message}"); - SystemLogger.Log("Starting with a fresh state."); - node.RoutingTable = new RoutingTable(); // Reinitialize - } - - return node; } //Once the Node has a Routing Table it can get the Previous Hash and update the Previous Hash @@ -382,7 +445,7 @@ namespace SPHERE.Blockchain //Generate Node and Block Id's internal static string GenerateKademliaId() { - byte[] randomBytes = new byte[32]; // 256 bits = 32 bytes + byte[] randomBytes = new byte[32]; // Use the modern RandomNumberGenerator.Fill method System.Security.Cryptography.RandomNumberGenerator.Fill(randomBytes); diff --git a/SPHERE/Blockchain/Chain/DHT/DHT.cs b/SPHERE/Blockchain/Chain/DHT/DHT.cs index 2a86e4e..d1244fd 100644 --- a/SPHERE/Blockchain/Chain/DHT/DHT.cs +++ b/SPHERE/Blockchain/Chain/DHT/DHT.cs @@ -143,11 +143,12 @@ namespace SPHERE.Blockchain } } - public static string GetAppDataPath(string fileName) + public static string GetAppDataPath(Node node, string fileName) { string appDataDir; + string firstSix = node.Peer.NodeId.Length >= 6 ? node.Peer.NodeId.Substring(0, 6) : node.Peer.NodeId; appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - return Path.Combine(appDataDir, $"{AppIdentifier.GetOrCreateServiceName()}{fileName}.state"); + return Path.Combine(appDataDir, $"{AppIdentifier.GetOrCreateServiceName()}{firstSix}{fileName}.state"); } /// @@ -206,23 +207,18 @@ namespace SPHERE.Blockchain return false; } - // Optionally validate encryption algorithm, signature, or other policies - if (block.Header.EncryptionAlgorithm != "AES256" && block.Header.EncryptionAlgorithm != "RSA2048") - { - SystemLogger.Log($"Unsupported encryption algorithm: {block.Header.EncryptionAlgorithm}"); - return false; - } return true; } - public void SaveState() + public void SaveState(Node node, string _filePast) { lock (stateLock) // Ensure thread safety { try { - string filePath = GetAppDataPath("DHT"); + // SaveContactDHT + string filePath = GetAppDataPath(node, _filePast); // Ensure the directory exists string directoryPath = Path.GetDirectoryName(filePath); @@ -256,13 +252,13 @@ namespace SPHERE.Blockchain } // Load DHT state from a file - public void LoadState() + public void LoadState(Node node, string _filePath) { lock (stateLock) // Ensure thread safety { try { - string filePath = GetAppDataPath("DHT"); + string filePath = GetAppDataPath(node, _filePath); if (!File.Exists(filePath)) { diff --git a/SPHERE/Blockchain/Chain/DHT/DHTManagement.cs b/SPHERE/Blockchain/Chain/DHT/DHTManagement.cs index 3595c98..4b597f1 100644 --- a/SPHERE/Blockchain/Chain/DHT/DHTManagement.cs +++ b/SPHERE/Blockchain/Chain/DHT/DHTManagement.cs @@ -102,7 +102,7 @@ namespace SPHERE.Blockchain - Packet responsePacket = Packet.PacketBuilder.BuildPacket(responseHeader, JsonSerializer.Serialize(block)); + Packet responsePacket = Packet.PacketBuilder.BuildPacket(node, responseHeader, JsonSerializer.Serialize(block)); byte[] serializedResponse = Packet.PacketBuilder.SerializePacket(responsePacket); // Encrypt with the requester's public key @@ -192,7 +192,7 @@ namespace SPHERE.Blockchain 15 ); - Packet requestPacket = Packet.PacketBuilder.BuildPacket(header, blockType.ToString()); + Packet requestPacket = Packet.PacketBuilder.BuildPacket(node, header, blockType.ToString()); byte[] serializedPacket = Packet.PacketBuilder.SerializePacket(requestPacket); // Encrypt the packet with the peer's public key diff --git a/SPHERE/Blockchain/Chain/DHT/RoutingTable.cs b/SPHERE/Blockchain/Chain/DHT/RoutingTable.cs index 10a361d..e4b30dd 100644 --- a/SPHERE/Blockchain/Chain/DHT/RoutingTable.cs +++ b/SPHERE/Blockchain/Chain/DHT/RoutingTable.cs @@ -233,13 +233,13 @@ public class RoutingTable } } - public void SaveRoutingTable() + public void SaveRoutingTable(Node node, string _filePath) { lock (_lock) { try { - string filePath = DHT.GetAppDataPath("RT"); + string filePath = DHT.GetAppDataPath(node, _filePath); string directoryPath = Path.GetDirectoryName(filePath); if (!Directory.Exists(directoryPath)) @@ -280,13 +280,13 @@ public class RoutingTable } } - public void LoadRoutingTable() + public void LoadRoutingTable(Node node, string _filePath) { lock (_lock) { try { - string filePath = DHT.GetAppDataPath("RT"); + string filePath = DHT.GetAppDataPath(node, _filePath); if (!File.Exists(filePath)) { diff --git a/SPHERE/Blockchain/Chain/Networking/Bootstrap.cs b/SPHERE/Blockchain/Chain/Networking/Bootstrap.cs index e40443f..499f41f 100644 --- a/SPHERE/Blockchain/Chain/Networking/Bootstrap.cs +++ b/SPHERE/Blockchain/Chain/Networking/Bootstrap.cs @@ -56,12 +56,12 @@ namespace SPHERE.Networking node.Peer.Node_Type.ToString(), node.Peer.PublicSignatureKey, node.Peer.PublicEncryptKey, - node.Client.clientListenerPort, - node.Client.clientIP.ToString(), + node.Peer.NodePort, + node.Peer.NodeIP, 25 ); - Packet packet = Packet.PacketBuilder.BuildPacket(header, Packet.PacketBuilder.PacketType.BootstrapRequest.ToString()); + Packet packet = Packet.PacketBuilder.BuildPacket(node, header, Packet.PacketBuilder.PacketType.BootstrapRequest.ToString()); SystemLogger.Log($"Debug-SendBootstrapRequest: Packet built with NodeId: {node.Peer.NodeId}, IP: {node.Client.clientIP}, Port: {node.Client.clientListenerPort}"); // Serialize the packet into a byte array @@ -374,7 +374,7 @@ namespace SPHERE.Networking var SerializedPayload = JsonSerializer.Serialize(responsePayload); - Packet responsePacket = Packet.PacketBuilder.BuildPacket(header, SerializedPayload); + Packet responsePacket = Packet.PacketBuilder.BuildPacket(node, header, SerializedPayload); byte[] serializedPacket = Packet.PacketBuilder.SerializePacket(responsePacket); diff --git a/SPHERE/Blockchain/Chain/Networking/Client.cs b/SPHERE/Blockchain/Chain/Networking/Client.cs index 4779daf..f47e9d8 100644 --- a/SPHERE/Blockchain/Chain/Networking/Client.cs +++ b/SPHERE/Blockchain/Chain/Networking/Client.cs @@ -15,6 +15,8 @@ using System; using System.Security.Cryptography; using System.Text.Json; using static SPHERE.Networking.Packet; +using System.Reflection.PortableExecutable; +using System.IO; namespace SPHERE.Networking @@ -67,6 +69,7 @@ namespace SPHERE.Networking { PacketBuilder.PacketType.Ping, (node, packet) => node.NetworkManager.PongPeerAsync(node, packet) }, { PacketBuilder.PacketType.Pong, (node, packet) => node.NetworkManager.ProcessPongAsync(node, packet) }, { PacketBuilder.PacketType.GetRequest, (node, packet) => node.NetworkManager.RespondToGetRequest(node, packet) }, + { PacketBuilder.PacketType.GetResponse, (node, packet) => node.NetworkManager.ProcessGetResponse(node, packet) }, { PacketBuilder.PacketType.BrodcastConnection, (node, packet) => node.NetworkManager.PeerListResponse(node, packet) }, { PacketBuilder.PacketType.PeerUpdate, (node, packet) => node.Peer.ProcessPeerListResponse(node, packet) }, { PacketBuilder.PacketType.SyncDHTRequest, (node, packet) => DHTManagement.ProcessSyncDHTRequest(node, packet) }, @@ -355,37 +358,38 @@ namespace SPHERE.Networking } - public async Task StartClientListenerAsync(Node node, Client client) + public async Task StartClientListenerAsync(Node node) { try { - // Ensure we have a valid listener port - if (client.clientListenerPort == 0) - { - client.clientListenerPort = FindAvailablePort(); - } - client.Listener = new TcpListener(client.clientIP, client.clientListenerPort); - client.Listener.Start(); - SystemLogger.Log($"Async server is listening on port {client.clientListenerPort}"); + // Ensure we have a valid listener port + if (node.Client.clientListenerPort == 0) + { + SystemLogger.Log($"Error-StartClientListenerAsync: Port was 0."); + return; + } + node.Client.Listener = new TcpListener(node.Client.clientIP, node.Client.clientListenerPort); + node.Client.Listener.Start(); + //SystemLogger.Log($"Async server is listening on port {node.Client.clientListenerPort}"); while (true) { try { - client.client = await client.Listener.AcceptTcpClientAsync(); - SystemLogger.Log($"Connection established with {client.client.Client.RemoteEndPoint}"); + node.Client.client = await node.Client.Listener.AcceptTcpClientAsync(); + //SystemLogger.Log($"Connection established with {node.Client.client.Client.RemoteEndPoint}"); - _ = HandleClientAsync(node, client.client); + _ = HandleClientAsync(node, node.Client.client); } catch (Exception ex) { - SystemLogger.Log($"Server error: {ex.Message}"); + // SystemLogger.Log($"Server error: {ex.Message}"); } } } catch (Exception ex) { - SystemLogger.Log($"Error starting listener: {ex.Message}"); + //SystemLogger.Log($"Error starting listener: {ex.Message}"); return; } } @@ -400,11 +404,11 @@ namespace SPHERE.Networking if (PublicIP == null || PublicPort == 0) { - SystemLogger.Log("StartClientListenerWithSTUNAsync: Failed to retrieve public endpoint. Trying once more."); + //SystemLogger.Log("StartClientListenerWithSTUNAsync: Failed to retrieve public endpoint. Trying once more."); var (PublicIP1, PublicPort1) = stun.GetPublicEndpoint(); if (PublicIP1 == null || PublicPort1 == 0) { - SystemLogger.Log("StartClientListenerWithSTUNAsync: Failed to retrieve public endpoint again. Exiting."); + //SystemLogger.Log("StartClientListenerWithSTUNAsync: Failed to retrieve public endpoint again. Exiting."); return; } @@ -443,9 +447,13 @@ namespace SPHERE.Networking // Synchronous method to start the client listener using STUN public void StartClientListenerWithSTUNSync(Node node, Client client) { + SystemLogger.Log($"Debug-StartClientListenerWithSTUNSync: Starting Stun search"); try { - // Step 1: Retrieve public IP and port using STUN + // Retrieve public IP and port using STUN + + + var stun = new STUN(); var (PublicIP, PublicPort) = stun.GetPublicEndpoint(); @@ -561,6 +569,7 @@ namespace SPHERE.Networking } finally { + await client.GetStream().FlushAsync(); client.Close(); } } @@ -605,9 +614,35 @@ namespace SPHERE.Networking try { + string normalizedContent = "empty"; + string packetHash = ""; //Store a Hash of the Packet Content to check and prevent processing duplicate packets. - string normalizedContent = JsonSerializer.Serialize(JsonSerializer.Deserialize(packet.Content), new JsonSerializerOptions { WriteIndented = false }); - string packetHash = ComputeHash(normalizedContent); // Hash only the static parts + try + { + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = false, + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + var contentObject = JsonSerializer.Deserialize(packet.Content, options); + + if (contentObject is string stringContent) + { + normalizedContent = stringContent; + } + else + { + normalizedContent = JsonSerializer.Serialize(contentObject, options); + } + } + catch(Exception ex) + { + // SystemLogger.Log($"Error-ProcessIncomingPacket: Error processing packet(Preventing Duplicates-normalizedContent serialization failed.): {ex.Message}"); + } + + packetHash = ComputeHash(normalizedContent); + if (node.seenPackets.ContainsKey(packetHash)) { @@ -629,13 +664,38 @@ namespace SPHERE.Networking try { - byte[] sendersPublicSignatureKey = packet.Header.PublicSignatureKey; - SystemLogger.Log($"Debug-ProcessIncomingPacket: Sender Public Signature Key: {Convert.ToBase64String(sendersPublicSignatureKey)}."); - SystemLogger.Log($"Debug-ProcessIncomingPacket: Raw Signature Before Decoding: {packet.Signature}"); - byte[] rawSignature = Convert.FromBase64String(packet.Signature); - SystemLogger.Log($"Debug-ProcessIncomingPacket: Raw Signature: {Convert.ToBase64String(rawSignature)}."); - bool isValidSignature = SignatureGenerator.VerifyByteArray(packetData, rawSignature, sendersPublicSignatureKey); + var modifiedHeader = new PacketHeader + { + NodeId = packet.Header.NodeId, + Node_Type = packet.Header.Node_Type, + IPAddress = packet.Header.IPAddress, + Port = packet.Header.Port, + PublicSignatureKey = packet.Header.PublicSignatureKey, + PublicEncryptKey = packet.Header.PublicEncryptKey, + Packet_Type = packet.Header.Packet_Type + + }; + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = false, + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + string serializedHeader = JsonSerializer.Serialize(modifiedHeader, options); + byte[] headerBytes = Encoding.UTF8.GetBytes(serializedHeader); + byte[] contentBytes = Encoding.UTF8.GetBytes(packet.Content); + + int totalLength = headerBytes.Length + contentBytes.Length; + byte[] combinedBytes = new byte[totalLength]; + Buffer.BlockCopy(headerBytes, 0, combinedBytes, 0, headerBytes.Length); + Buffer.BlockCopy(contentBytes, 0, combinedBytes, headerBytes.Length, contentBytes.Length); + + byte[] sendersPublicSignatureKey = packet.Header.PublicSignatureKey; + byte[] rawSignature = Convert.FromBase64String(packet.Signature); + bool isValidSignature = SignatureGenerator.VerifyByteArray(combinedBytes, rawSignature, packet.Header.PublicSignatureKey); + if (!isValidSignature) { SystemLogger.Log("Error-ProcessIncomingPacket: Invalid Signature! Packet rejected."); @@ -711,80 +771,7 @@ namespace SPHERE.Networking SystemLogger.Log($"ProcessIncomingPacket: Unknown packet type: {packet.Header.Packet_Type}"); } - //switch (packetType) - //{ - // case PacketBuilder.PacketType.BootstrapRequest: - // await Bootstrap.SendBootstrapResponse(node, packet); - // break; - - // case PacketBuilder.PacketType.BootstrapResponse: - // await Bootstrap.ProcessBootstrapResponse(node, packet); - // break; - - // case PacketBuilder.PacketType.Ping: - // await node.NetworkManager.PongPeerAsync(node, packet); - // break; - - // case PacketBuilder.PacketType.Pong: - // await node.NetworkManager.ProcessPongAsync(node, packet); - // break; - - // case PacketBuilder.PacketType.GetRequest: - // await node.NetworkManager.RespondToGetRequest(node, packet); - // break; - - // case PacketBuilder.PacketType.BrodcastConnection: - // await node.NetworkManager.PeerListResponse(node, packet); - // break; - - // case PacketBuilder.PacketType.PeerUpdate: - // await node.Peer.ProcessPeerListResponse(node, packet); - // break; - - // case PacketBuilder.PacketType.SyncDHTRequest: - // await DHTManagement.ProcessSyncDHTRequest(node, packet); - // break; - - // case PacketBuilder.PacketType.SyncDHTResponse: - // await DHTManagement.ProcessSyncDHTResponse(node, packet); - // break; - - // case PacketBuilder.PacketType.PushTokenIssued: - // await NetworkManager.ProcessIssuedToken(node, packet); - // break; - - // case PacketBuilder.PacketType.PingPal: - // await node.NetworkManager.RespondToPingPalAsync(node, packet); - // break; - - // case PacketBuilder.PacketType.PongPal: - // await NetworkManager.PongPalProcess(node, packet); - // break; - - // case PacketBuilder.PacketType.ReputationUpdate: - // await NetworkManager.ProcessReputationUpdate(node, packet); - // break; - - // case PacketBuilder.PacketType.ReputationRequest: - // await node.NetworkManager.ReturnRequestedReputation(node, packet); - // break; - - // case PacketBuilder.PacketType.ReputationResponse: - // await NetworkManager.ProcessReputationResponse(node, packet); - // break; - - // case PacketBuilder.PacketType.PutRequest: - // await NetworkManager.VerifyAndBroadcastPutRequest(node, packet); - // break; - - // case PacketBuilder.PacketType.PutResponse: - // await NetworkManager.ProcessIncomingVerifiedPutRequest(node, packet); - // break; - - // default: - // SystemLogger.Log($"ProcessIncomingPacket:Unknown packet type: {packet.Header.Packet_Type}"); - // break; - //} + } catch (Exception ex) { @@ -792,6 +779,24 @@ namespace SPHERE.Networking } } + + public IPAddress GetLocalIPAddress() + { + foreach (var netInterface in System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()) + { + var ipProps = netInterface.GetIPProperties(); + foreach (var addr in ipProps.UnicastAddresses) + { + if (addr.Address.AddressFamily == AddressFamily.InterNetwork && + !addr.Address.ToString().StartsWith("169.")) // Ignore APIPA addresses + { + return addr.Address; + } + } + } + return IPAddress.Parse("127.0.0.1"); // Fall back to loop back if no local IP is found + } + } /// /// The STUN server is used to get an IP and port that is open for listening for traffic without needing pinholes or port forwarding. @@ -799,7 +804,7 @@ namespace SPHERE.Networking /// /// The implementation here is limited and needs TURN to also be included for some situations. This as it sits is a basic prototyped temporary implementation. /// - /// Futureistlly every node should have the ability to act as a stun server or at least full Nodes. The app can use the provided ip and port for bootstrapping, to first send a STUN request. + /// Futuristically every node should have the ability to act as a stun server or at least full Nodes. The app can use the provided ip and port for bootstrapping, to first send a STUN request. /// It will then get its IP and port back, set up its listener, then send its bootstrap request and wait to get its peers and the Chain or shards. /// /// @@ -826,6 +831,7 @@ namespace SPHERE.Networking public (IPAddress PublicIP, int PublicPort) GetPublicEndpoint() { + SystemLogger.Log($"Debug-GetPublicEndpoint: Getting Public Endpoint"); foreach (var server in stunServers) { try @@ -918,10 +924,11 @@ namespace SPHERE.Networking } } + } - } +} diff --git a/SPHERE/Blockchain/Chain/Networking/NetworkManager.cs b/SPHERE/Blockchain/Chain/Networking/NetworkManager.cs index eac6bb6..7a7bd1b 100644 --- a/SPHERE/Blockchain/Chain/Networking/NetworkManager.cs +++ b/SPHERE/Blockchain/Chain/Networking/NetworkManager.cs @@ -20,13 +20,10 @@ namespace SPHERE.Networking internal class NetworkManager { - //-----Connection Calls-----\\ public async Task BroadcastConnectionToNetwork(Node node) { - - try { SystemLogger.Log("Debug-BrodcastConnectionToNetwork: Starting Broadcast Network Connection..."); @@ -47,7 +44,7 @@ namespace SPHERE.Networking 50 ); - Packet packet = Packet.PacketBuilder.BuildPacket(header, Packet.PacketBuilder.PacketType.BrodcastConnection.ToString()); + Packet packet = Packet.PacketBuilder.BuildPacket(node, header, Packet.PacketBuilder.PacketType.BrodcastConnection.ToString()); SystemLogger.Log($"Debug-BrodcastConnectionToNetwork: Packet built with NodeId: {node.Peer.NodeId}, IP: {node.Client.clientIP}, Port: {node.Client.clientListenerPort}"); // Serialize the packet into a byte array @@ -686,7 +683,7 @@ namespace SPHERE.Networking - Packet responsePacket = Packet.PacketBuilder.BuildPacket(header, JsonSerializer.Serialize(peerList)); + Packet responsePacket = Packet.PacketBuilder.BuildPacket(node, header, JsonSerializer.Serialize(peerList)); SystemLogger.Log("Debug-PeerListResponse: Serializing response payload..."); byte[] responseData = Packet.PacketBuilder.SerializePacket(responsePacket); @@ -766,7 +763,7 @@ namespace SPHERE.Networking 1 ); - var responsePacket = Packet.PacketBuilder.BuildPacket(responseHeader, JsonSerializer.Serialize(token)); + var responsePacket = Packet.PacketBuilder.BuildPacket(node, responseHeader, JsonSerializer.Serialize(token)); byte[] serializedResponse = Packet.PacketBuilder.SerializePacket(responsePacket); // Encrypt with the requester's public key @@ -791,7 +788,7 @@ namespace SPHERE.Networking { if (packet == null || packet.Header == null || packet.Content == null) { - SystemLogger.Log("Received an invalid PushTokenIssued packet."); + SystemLogger.Log($"Debug-ProcessIssuedToken: Received an invalid PushTokenIssued packet."); return Task.CompletedTask; } @@ -799,7 +796,7 @@ namespace SPHERE.Networking if (senderPeer == null) { - SystemLogger.Log("Received an invalid PushTokenIssued packet."); + SystemLogger.Log($"Debug-ProcessIssuedToken: Received an invalid PushTokenIssued packet."); return Task.CompletedTask; } @@ -808,7 +805,7 @@ namespace SPHERE.Networking if (token == null || string.IsNullOrWhiteSpace(token.TokenId)) { - SystemLogger.Log("Received an empty or invalid PushTokenIssued payload."); + SystemLogger.Log($"Debug-ProcessIssuedToken: Received an empty or invalid PushTokenIssued payload."); return Task.CompletedTask; } @@ -819,8 +816,10 @@ namespace SPHERE.Networking } catch (Exception ex) { - SystemLogger.Log($"Error processing PushTokenIssued: {ex.Message}"); + SystemLogger.Log($"Error-ProcessIssuedToken: processing PushTokenIssued: {ex.Message}"); } + + SystemLogger.Log($"Debug-ProcessIssuedToken: Received an Issued Push Token."); return Task.CompletedTask; } @@ -860,7 +859,7 @@ namespace SPHERE.Networking throw new ArgumentException("Block ID cannot be null or empty.", nameof(blockId)); } - var existingBlock = node.ContactDHT.GetBlock(blockId); + Block existingBlock = node.ContactDHT.GetBlock(blockId); if (existingBlock != null) { SystemLogger.Log("Block already exists locally."); @@ -894,10 +893,11 @@ namespace SPHERE.Networking node.Peer.PublicEncryptKey, node.Client.clientListenerPort, node.Client.clientIP.ToString(), - 15 // TTL value + 15 ); - Packet requestPacket = Packet.PacketBuilder.BuildPacket(header, blockId); + + Packet requestPacket = Packet.PacketBuilder.BuildPacket(node, header, blockId); byte[] serializedPacket = Packet.PacketBuilder.SerializePacket(requestPacket); @@ -944,7 +944,7 @@ namespace SPHERE.Networking try { - + Peer senderPeer = Peer.CreatePeerFromPacket(packet); if (packet == null || packet.Header == null) { SystemLogger.Log("Received an invalid GetRequest packet."); @@ -959,45 +959,23 @@ namespace SPHERE.Networking int newTTL = ttlValue - 1; - var requestedBlockIds = JsonSerializer.Deserialize>(packet.Content); + string requestedBlockId = packet.Content; - SystemLogger.Log($"Received GetRequest for Block ID: {requestedBlockIds}"); + SystemLogger.Log($"Received GetRequest for Block ID: {requestedBlockId}"); - List requestedBlocks = new List(); - List notFoundBlocks = new List(); + Block block = node.ContactDHT.GetBlock(requestedBlockId); - // Check if we already have the requested block - foreach (var blockId in requestedBlockIds) + + if (block != null) { - Block block = node.ContactDHT.GetBlock(blockId); - if (block != null) - { - SystemLogger.Log($"Block {blockId} found locally. Adding to response list."); - requestedBlocks.Add(block); - } - else - { - SystemLogger.Log($"Block {blockId} not found locally. Adding to not found list."); - notFoundBlocks.Add(blockId); - } - } - - - if (requestedBlocks.Count > 0) - { await node.NetworkManager.RetryAsync(async () => { - SystemLogger.Log($"Block {requestedBlockIds.Count} found locally. Sending GetResponse to requester..."); - - BlockResponsePayload payload = new BlockResponsePayload - { - Type = requestedBlocks[0].Header.BlockType, - Blocks = requestedBlocks - }; + SystemLogger.Log($"Block {requestedBlockId} found locally. Sending GetResponse to requester..."); + string serializedBlock = JsonSerializer.Serialize(block); // Build GetResponse packet var responseHeader = Packet.PacketBuilder.BuildPacketHeader( @@ -1008,66 +986,75 @@ namespace SPHERE.Networking node.Peer.PublicEncryptKey, node.Client.clientListenerPort, node.Client.clientIP.ToString(), - 5 // TTL value for response + 5 ); - Packet responsePacket = Packet.PacketBuilder.BuildPacket(responseHeader, JsonSerializer.Serialize(payload)); + Packet responsePacket = Packet.PacketBuilder.BuildPacket(node, responseHeader, serializedBlock); byte[] serializedResponse = Packet.PacketBuilder.SerializePacket(responsePacket); // Encrypt with the requester's public key - byte[] encryptedResponse = Encryption.EncryptPacketWithPublicKey(node, serializedResponse, packet.Header.PublicEncryptKey); + byte[] encryptedResponse = Encryption.EncryptPacketWithPublicKey(node, serializedResponse, senderPeer.PublicEncryptKey); // Send the response to the requester bool success = await Client.SendPacketToPeerAsync(node, packet.Header.IPAddress, int.Parse(packet.Header.Port), encryptedResponse); if (success) - SystemLogger.Log($"Successfully sent GetResponse for {requestedBlockIds.Count} Blocks to {packet.Header.IPAddress}:{packet.Header.Port}"); + SystemLogger.Log($"Successfully sent GetResponse for {requestedBlockId} Blocks to {packet.Header.IPAddress}:{packet.Header.Port}"); else - SystemLogger.Log($"Failed to send GetResponse for {requestedBlockIds} Blocks to {packet.Header.IPAddress}:{packet.Header.Port}"); + SystemLogger.Log($"Failed to send GetResponse for {requestedBlockId} Blocks to {packet.Header.IPAddress}:{packet.Header.Port}"); return success; }); - } - // Block not found, rebroadcast the request to the closest peers + } + else + { + SystemLogger.Log($"Blocks not found locally. Rebroadcasting request to peers..."); - bool success = false; - await node.NetworkManager.RetryAsync(async () => - { - foreach (var Ids in notFoundBlocks) - { - - // Get closest peers - List closestPeers = node.RoutingTable.GetClosestPeers(Ids, 5); - if (closestPeers.Count == 0) + + + + bool success = false; + if (newTTL >= 1) + { + await node.NetworkManager.RetryAsync(async () => { - SystemLogger.Log("No peers available to forward the request."); - continue; - } - packet.Header.TTL = newTTL.ToString(); - - byte[] serializedPacket = Packet.PacketBuilder.SerializePacket(packet); - - var tasks = closestPeers.Select(async peer => - { - SystemLogger.Log($"Forwarding GetRequest for Block {Ids} to {peer.NodeIP}:{peer.NodePort}"); - - try + // Get closest peers + List closestPeers = node.RoutingTable.GetClosestPeers(block.Header.BlockId, 5); + if (closestPeers.Count == 0) { - byte[] encryptedPacket = Encryption.EncryptPacketWithPublicKey(node, serializedPacket, peer.PublicEncryptKey); - success = await Client.SendPacketToPeerAsync(node, peer.NodeIP, peer.NodePort, encryptedPacket); + SystemLogger.Log("No peers available to forward the request."); + return false; } - catch (Exception ex) + + packet.Header.TTL = newTTL.ToString(); + + byte[] serializedPacket = Packet.PacketBuilder.SerializePacket(packet); + + var tasks = closestPeers.Select(async peer => { - SystemLogger.Log($"Error forwarding GetRequest to {peer.NodeIP}:{peer.NodePort}: {ex.Message}"); - } + SystemLogger.Log($"Forwarding GetRequest for Block {block.Header.BlockId} to {peer.NodeIP}:{peer.NodePort}"); + + try + { + byte[] encryptedPacket = Encryption.EncryptPacketWithPublicKey(node, serializedPacket, peer.PublicEncryptKey); + success = await Client.SendPacketToPeerAsync(node, peer.NodeIP, peer.NodePort, encryptedPacket); + } + catch (Exception ex) + { + SystemLogger.Log($"Error forwarding GetRequest to {peer.NodeIP}:{peer.NodePort}: {ex.Message}"); + } + }); + + await Task.WhenAll(tasks); + + return success; }); - await Task.WhenAll(tasks); + } - return success; - }); + } } catch (Exception ex) { @@ -1083,57 +1070,49 @@ namespace SPHERE.Networking try { - if (packet == null || packet.Header == null || packet.Content == null) + Peer senderPeer = Peer.CreatePeerFromPacket(packet); + + if (senderPeer == null) + { + SystemLogger.Log("Sender Peer is null."); + return; + } + + if (packet == null || packet.Header == null || packet.Content == null) { SystemLogger.Log("Received an invalid GetResponse packet."); return; } // Deserialize the payload - BlockResponsePayload payload = JsonSerializer.Deserialize(packet.Content); + Block block = JsonSerializer.Deserialize(packet.Content); - if (payload == null || payload.Blocks == null || payload.Blocks.Count == 0) + if (block == null ) { SystemLogger.Log("Received an empty or invalid GetResponse payload."); + //BroadcastReputationUpdate(node, senderPeer, Blockchain.Reputation.ReputationReason.GetTransactionFailed); return; } - // Process each block in the response - foreach (var block in payload.Blocks) + // Check if the block is already requested + if (!node.requestedBlocks.ContainsKey(block.Header.BlockId)) { - if (block == null || string.IsNullOrWhiteSpace(block.Header.BlockId)) - { - SystemLogger.Log("Received an invalid block in GetResponse."); - continue; - } - - // Check if the block is already requested - if (!node.requestedBlocks.ContainsKey(block.Header.BlockId)) - { - SystemLogger.Log($"Block {block.Header.BlockId} was not requested. Ignoring."); - continue; - } - - // Add the block to the DHT - node.ContactDHT.AddBlock(block); - - // Remove the block from the requested list - node.requestedBlocks.TryRemove(block.Header.BlockId, out _); - - SystemLogger.Log($"Successfully added block {block.Header.BlockId} to the DHT."); + SystemLogger.Log($"Block {block.Header.BlockId} was not requested. Ignoring."); + return; } + // Add the block to the DHT + node.ContactDHT.AddBlock(block); + SystemLogger.Log($"Successfully added block {block.Header.BlockId} to the DHT."); + + //Reward the sender with a Reputation Score and a Token - Peer senderPeer= Peer.CreatePeerFromPacket(packet); + TokenManager.PushToken token = node.TokenManager.CreatePushToken(node, senderPeer.NodeId); + await node.NetworkManager.SendTokenToPeer(node, senderPeer, token); + node.TokenManager.AddIssuedPushToken(token); - if (senderPeer != null) - { - TokenManager.PushToken token = node.TokenManager.CreatePushToken(node, senderPeer.NodeId); - await node.NetworkManager.SendTokenToPeer(node, senderPeer, token); - node.TokenManager.AddIssuedPushToken(token); - - BroadcastReputationUpdate(node, senderPeer, Blockchain.Reputation.ReputationReason.GetContactFailed); - } + //BroadcastReputationUpdate(node, senderPeer, Blockchain.Reputation.ReputationReason.GetTransactionSuccessful); + } catch (Exception ex) { @@ -1197,7 +1176,7 @@ namespace SPHERE.Networking 50 // TTL value ); - Packet putPacket = Packet.PacketBuilder.BuildPacket(header, JsonSerializer.Serialize(block)); + Packet putPacket = Packet.PacketBuilder.BuildPacket(node, header, JsonSerializer.Serialize(block)); SystemLogger.Log($"Sending PutRequest to peerlist"); @@ -1279,7 +1258,7 @@ namespace SPHERE.Networking }; - Packet putPacket = Packet.PacketBuilder.BuildPacket(header, JsonSerializer.Serialize(payload)); + Packet putPacket = Packet.PacketBuilder.BuildPacket(node, header, JsonSerializer.Serialize(payload)); SystemLogger.Log($"Error:-RequestPutWithToken: Sending PutRequest to peerlist"); @@ -1581,7 +1560,7 @@ namespace SPHERE.Networking var serializedBlock = JsonSerializer.Serialize(block); - Packet responsePacket = Packet.PacketBuilder.BuildPacket(responseHeader, serializedBlock); + Packet responsePacket = Packet.PacketBuilder.BuildPacket(node, responseHeader, serializedBlock); byte[] serializedResponse = Packet.PacketBuilder.SerializePacket(responsePacket); // Encrypt with the requester's public key diff --git a/SPHERE/Blockchain/Chain/Networking/Packet.cs b/SPHERE/Blockchain/Chain/Networking/Packet.cs index 406d492..e66cea3 100644 --- a/SPHERE/Blockchain/Chain/Networking/Packet.cs +++ b/SPHERE/Blockchain/Chain/Networking/Packet.cs @@ -7,6 +7,9 @@ using System.Reflection.PortableExecutable; using System.Text; using System.Text.Json.Serialization; using static SPHERE.Networking.Packet.PacketBuilder; +using SPHERE.Configure; +using SPHERE.Blockchain; +using System.Text.Json; @@ -170,20 +173,49 @@ namespace SPHERE.Networking - internal static Packet BuildPacket(PacketHeader header, string message) + internal static Packet BuildPacket(Node node, PacketHeader header, string message) { if (Debugger.IsAttached || Debugger.IsLogging()) { Environment.FailFast("Debugger detected! Exiting..."); } + Packet packet = new Packet { Header = header, Content = message, - Signature = "TestSignature", }; + var modifiedHeader = new PacketHeader + { + NodeId = header.NodeId, + Node_Type = header.Node_Type, + IPAddress = header.IPAddress, + Port = header.Port, + PublicSignatureKey = header.PublicSignatureKey, + PublicEncryptKey = header.PublicEncryptKey, + Packet_Type = header.Packet_Type + }; + + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = false, + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + string serializedHeader = JsonSerializer.Serialize(modifiedHeader, options); + byte[] headerBytes = Encoding.UTF8.GetBytes(serializedHeader); + byte[] contentBytes = Encoding.UTF8.GetBytes(packet.Content); + + int totalLength = headerBytes.Length + contentBytes.Length; + byte[] combinedBytes = new byte[totalLength]; + Buffer.BlockCopy(headerBytes, 0, combinedBytes, 0, headerBytes.Length); + Buffer.BlockCopy(contentBytes, 0, combinedBytes, headerBytes.Length, contentBytes.Length); + + byte[] signature = SignatureGenerator.SignByteArray(node, combinedBytes); + packet.Signature = Convert.ToBase64String(signature); return packet; } @@ -410,10 +442,19 @@ namespace SPHERE.Networking try { + _stream.ReadTimeout = 5000; + _stream.WriteTimeout = 5000; + byte[] lengthPrefix = new byte[4]; // Read total message length - await ReadExactlyAsync(_stream, lengthPrefix, 4); + if (!await ReadExactlyAsync(_stream, lengthPrefix, 4)) + { + SystemLogger.Log($"Error-ReadMessage: Failed to read message length."); + return (null, null, null); + } + + int messageLength = BitConverter.ToInt32(lengthPrefix, 0); // SystemLogger.Log($"Debug-ReadMessage: Declared Message Length: {messageLength} bytes"); @@ -427,9 +468,12 @@ namespace SPHERE.Networking // Read the remaining packet int remainingPacketSize = messageLength - 4; byte[] fullPacket = new byte[remainingPacketSize]; - await ReadExactlyAsync(_stream, fullPacket, remainingPacketSize); - - //SystemLogger.Log($"Debug-ReadMessage: Fully Received Packet - {remainingPacketSize} bytes"); + //await ReadExactlyAsync(_stream, fullPacket, remainingPacketSize); + if (!await ReadExactlyAsync(_stream, fullPacket, remainingPacketSize)) + { + SystemLogger.Log($"Error-ReadMessage: Failed to read full packet. Expected {remainingPacketSize} bytes."); + return (null, null, null); + } //Parse the packet to extract data return ParsePacket(fullPacket); @@ -530,13 +574,19 @@ namespace SPHERE.Networking private static async Task ReadExactlyAsync(NetworkStream stream, byte[] buffer, int size) { + if (stream == null || !stream.CanRead) + { + SystemLogger.Log($"Warning-ReadExactlyAsync: Stream is null or cannot be read."); + return false; + } + if (Debugger.IsAttached || Debugger.IsLogging()) { Environment.FailFast("Debugger detected! Exiting..."); } int totalBytesRead = 0; - + try { while (totalBytesRead < size) diff --git a/SPHERE/Configure/Encryption.cs b/SPHERE/Configure/Encryption.cs index a2cfc3d..ba2174b 100644 --- a/SPHERE/Configure/Encryption.cs +++ b/SPHERE/Configure/Encryption.cs @@ -39,11 +39,11 @@ namespace SPHERE.Configure // The Local Symmetric Key is used to Encrypt the blockContact. - public static byte[] EncryptWithSymmetric(Contact contactData, byte[] key) + public static byte[] EncryptContactWithSymmetric(Contact contactData, byte[] key) { byte[] convertedKey = key; - string data = System.Text.Json.JsonSerializer.Serialize(contactData); + string data = JsonSerializer.Serialize(contactData); using var aes = Aes.Create(); aes.Key = convertedKey; aes.GenerateIV(); @@ -61,27 +61,33 @@ namespace SPHERE.Configure return ms.ToArray(); // Return Base64-encoded encrypted data } - public static Contact DecryptWithSymmetricKey(string encryptedData, string key) + public static Contact DecryptContactWithSymmetricKey(string data, byte[] key) { - byte[] convertedKey = Convert.FromBase64String(key); - byte[] convertedEncryptedData = Convert.FromBase64String(encryptedData); - + byte[] encryptedData = Convert.FromBase64String(data); using var aes = Aes.Create(); // Extract IV from the encrypted data byte[] iv = new byte[16]; - Array.Copy(convertedEncryptedData, 0, iv, 0, iv.Length); + Array.Copy(encryptedData, 0, iv, 0, iv.Length); aes.IV = iv; - aes.Key = convertedKey; + aes.Key = key; using var decryptor = aes.CreateDecryptor(aes.Key, aes.IV); - using var ms = new MemoryStream(convertedEncryptedData, iv.Length, convertedEncryptedData.Length - iv.Length); + using var ms = new MemoryStream(encryptedData, iv.Length, encryptedData.Length - iv.Length); using var cryptoStream = new CryptoStream(ms, decryptor, CryptoStreamMode.Read); using var reader = new StreamReader(cryptoStream); string decryptedData = reader.ReadToEnd(); // Deserialize the contact from the data. - return System.Text.Json.JsonSerializer.Deserialize(decryptedData); + Contact contact = JsonSerializer.Deserialize(decryptedData); + if (contact != null) + { + return contact; + } + else + { + return null; + } } //Encrypt with a personal(public) Key Provides a secretKey to Validate its use. @@ -295,7 +301,7 @@ namespace SPHERE.Configure } // Decrypts the Local Symmetric Key(LSK) with the Semi Public Key(SPK) - public static string DecryptLocalSymmetricKey(byte[] encryptedLocalSymmetricKey, byte[] semiPublicKey) + public static byte[] DecryptLocalSymmetricKey(byte[] encryptedLocalSymmetricKey, byte[] semiPublicKey) { // Convert the keys and encrypted data to byte arrays @@ -315,7 +321,7 @@ namespace SPHERE.Configure byte[] decryptedKeyBytes = reader.ReadBytes((int)(ms.Length - iv.Length)); - return Convert.ToBase64String(decryptedKeyBytes); // Return Base64-encoded localSymmetricKey + return decryptedKeyBytes; // Return Base64-encoded localSymmetricKey } // Encrypts data using a local symmetric key and a salt @@ -484,47 +490,57 @@ namespace SPHERE.Configure } // Retrieves the private Contact key from memory - internal byte[] GetPersonalKey(KeyGenerator.KeyType keyType) + internal byte[] GetPersonalKey(Node node, KeyGenerator.KeyType keyType) { - if (keyType != KeyGenerator.KeyType.PrivatePersonalEncryptionKey || keyType != KeyGenerator.KeyType.PrivatePersonalSignatureKey || keyType != KeyGenerator.KeyType.PublicPersonalEncryptionKey || keyType != KeyGenerator.KeyType.PublicPersonalSignatureKey || keyType != KeyGenerator.KeyType.SemiPublicKey || keyType != KeyGenerator.KeyType.LocalSymmetricKey || keyType != KeyGenerator.KeyType.EncryptedLocalSymmetricKey) - { - SystemLogger.Log($"Error-GetPrivateContactKey: KeyType is not a Private Personal Key"); - return null; - } + //SystemLogger.Log("Debug-GetPersonalKey: Attempting to retrieve a personal key."); SecureString secureKey = keyType switch { - KeyGenerator.KeyType.PrivatePersonalEncryptionKey => PrivatePersonalEncryptionKey, - KeyGenerator.KeyType.PrivatePersonalSignatureKey => PrivatePersonalSignatureKey, - KeyGenerator.KeyType.PublicPersonalSignatureKey => PublicPersonalSignatureKey, - KeyGenerator.KeyType.PublicPersonalEncryptionKey => PublicPersonalEncryptionKey, - KeyGenerator.KeyType.SemiPublicKey => SemiPublicKey, - KeyGenerator.KeyType.EncryptedLocalSymmetricKey => EncryptedLocalSymmetricKey, - KeyGenerator.KeyType.LocalSymmetricKey => LocalSymmetricKey, + KeyGenerator.KeyType.PrivatePersonalEncryptionKey => node.KeyManager.PrivatePersonalEncryptionKey, + KeyGenerator.KeyType.PrivatePersonalSignatureKey => node.KeyManager.PrivatePersonalSignatureKey, + KeyGenerator.KeyType.PublicPersonalSignatureKey => node.KeyManager.PublicPersonalSignatureKey, + KeyGenerator.KeyType.PublicPersonalEncryptionKey => node.KeyManager.PublicPersonalEncryptionKey, + KeyGenerator.KeyType.SemiPublicKey => node.KeyManager.SemiPublicKey, + KeyGenerator.KeyType.LocalSymmetricKey => node.KeyManager.LocalSymmetricKey, + KeyGenerator.KeyType.EncryptedLocalSymmetricKey => node.KeyManager.EncryptedLocalSymmetricKey, _ => null }; if (secureKey == null || secureKey.Length == 0) { - throw new InvalidOperationException("Private key is not loaded in memory."); + SystemLogger.Log($"Error-GetPersonalKey: Key {keyType} is not available in memory."); + return null; } - // Convert SecureString to String + // Convert SecureString to byte[] IntPtr ptr = Marshal.SecureStringToGlobalAllocUnicode(secureKey); try { - return Convert.FromBase64String(Marshal.PtrToStringUni(ptr)); + string base64Key = Marshal.PtrToStringUni(ptr); + if (string.IsNullOrEmpty(base64Key)) + { + SystemLogger.Log($"Error-GetPersonalKey: Extracted key string is empty for {keyType}"); + return null; + } + + //SystemLogger.Log($"Debug-GetPersonalKey: Successfully retrieved {keyType}"); + return Convert.FromBase64String(base64Key); + } + catch (FormatException ex) + { + SystemLogger.Log($"Error-GetPersonalKey: Failed to decode Base64 key. Reason: {ex.Message}"); + return null; } finally { - Marshal.ZeroFreeGlobalAllocUnicode(ptr); + Marshal.ZeroFreeGlobalAllocUnicode(ptr); } } // Retrieves the private Node key from memory internal byte[] GetNodeKey(KeyGenerator.KeyType keyType) { - SystemLogger.Log($"Debug-GetNodeKey: Getting Node Key...@.@"); + // SystemLogger.Log($"Debug-GetNodeKey: Getting Node Key...@.@"); try { @@ -663,60 +679,69 @@ namespace SPHERE.Configure } //Set the Private Personal Key in Memory - internal void SetPrivatePersonalKey(byte[] key, KeyGenerator.KeyType keyType) + internal void SetPrivatePersonalKey(Node node, byte[] key, KeyGenerator.KeyType keyType) { - if (keyType != KeyGenerator.KeyType.PrivateNodeEncryptionKey && - keyType != KeyGenerator.KeyType.PrivateNodeSignatureKey && - keyType != KeyGenerator.KeyType.LocalSymmetricKey && - keyType != KeyGenerator.KeyType.SemiPublicKey) + // SystemLogger.Log($"Debug-SetPrivatePersonalKey: Using KeyManager instance {node.KeyManager.GetHashCode()} to retrieve {keyType}"); + if (key == null || key.Length == 0) { + SystemLogger.Log("Error-SetPrivatePersonalKey: Key cannot be null or empty."); return; } - - try + string keyString = Convert.ToBase64String(key); + SecureString newSecureString = new SecureString(); + foreach (char c in keyString) { - if (key == null || key.Length == 0) - { - SystemLogger.Log("Error- SetPrivatePersonalKey: Key cannot be null or empty."); - return; - } - - SecureString newSecureString = new SecureString(); - foreach (byte b in key) - { - newSecureString.AppendChar((char)b); - } - newSecureString.MakeReadOnly(); - - switch (keyType) - { - case KeyGenerator.KeyType.PrivateNodeEncryptionKey: - PrivatePersonalEncryptionKey?.Dispose(); - PrivatePersonalEncryptionKey = newSecureString; - break; - - case KeyGenerator.KeyType.PrivateNodeSignatureKey: - PrivatePersonalSignatureKey?.Dispose(); - PrivatePersonalSignatureKey = newSecureString; - break; - - case KeyGenerator.KeyType.SemiPublicKey: - SemiPublicKey?.Dispose(); - SemiPublicKey = newSecureString; - break; - - case KeyGenerator.KeyType.LocalSymmetricKey: - LocalSymmetricKey?.Dispose(); - LocalSymmetricKey = newSecureString; - break; - } - - // Wipe the original key from memory - Array.Clear(key, 0, key.Length); + newSecureString.AppendChar(c); } - catch (Exception ex) + newSecureString.MakeReadOnly(); + + switch (keyType) { - SystemLogger.Log($"Error- SetPrivatePersonalKey: Failed to Set Key Reason: {ex.Message}"); + case KeyGenerator.KeyType.PrivatePersonalEncryptionKey: + node.KeyManager.PrivatePersonalEncryptionKey?.Dispose(); + node.KeyManager.PrivatePersonalEncryptionKey = newSecureString; + // SystemLogger.Log($"Debug-SetPrivatePersonalKey: Successfully stored {keyType}"); + break; + + case KeyGenerator.KeyType.PrivatePersonalSignatureKey: + node.KeyManager.PrivatePersonalSignatureKey?.Dispose(); + node.KeyManager.PrivatePersonalSignatureKey = newSecureString; + //SystemLogger.Log($"Debug-SetPrivatePersonalKey: Successfully stored {keyType}"); + break; + + case KeyGenerator.KeyType.PublicPersonalEncryptionKey: + node.KeyManager.PublicPersonalEncryptionKey?.Dispose(); + node.KeyManager.PublicPersonalEncryptionKey = newSecureString; + //SystemLogger.Log($"Debug-SetPrivatePersonalKey: Successfully stored {keyType}"); + break; + + case KeyGenerator.KeyType.PublicPersonalSignatureKey: + node.KeyManager.PublicPersonalSignatureKey?.Dispose(); + node.KeyManager.PublicPersonalSignatureKey = newSecureString; + //SystemLogger.Log($"Debug-SetPrivatePersonalKey: Successfully stored {keyType}"); + break; + + case KeyGenerator.KeyType.SemiPublicKey: + node.KeyManager.SemiPublicKey?.Dispose(); + node.KeyManager.SemiPublicKey = newSecureString; + //SystemLogger.Log($"Debug-SetPrivatePersonalKey: Successfully stored {keyType}"); + break; + + case KeyGenerator.KeyType.LocalSymmetricKey: + node.KeyManager.LocalSymmetricKey?.Dispose(); + node.KeyManager.LocalSymmetricKey = newSecureString; + // SystemLogger.Log($"Debug-SetPrivatePersonalKey: Successfully stored {keyType}"); + break; + + case KeyGenerator.KeyType.EncryptedLocalSymmetricKey: + node.KeyManager.EncryptedLocalSymmetricKey?.Dispose(); + node.KeyManager.EncryptedLocalSymmetricKey = newSecureString; + //SystemLogger.Log($"Debug-SetPrivatePersonalKey: Successfully stored {keyType}"); + break; + + default: + SystemLogger.Log($"Error-SetPrivatePersonalKey: Unhandled KeyType {keyType}"); + return; } } @@ -984,7 +1009,7 @@ namespace SPHERE.Configure { try { - SystemLogger.Log($"Debug-StoreKeyLocally: Attempting to Store a Key of type {keyType}"); + //SystemLogger.Log($"Debug-StoreKeyLocally: Attempting to Store a Key of type {keyType}"); if (key == null || key.Length == 0) { @@ -996,16 +1021,16 @@ namespace SPHERE.Configure if (File.Exists(KeyFilePath)) { - SystemLogger.Log($"Debug-StoreKeyLocally: File Path Exists - Loading existing file."); + //SystemLogger.Log($"Debug-StoreKeyLocally: File Path Exists - Loading existing file."); newKeyStorage = LoadKeyFile() ?? new NodeKeyStorageFile(); } else { - SystemLogger.Log($"Debug-StoreKeyLocally: No File Existed. Creating new File..."); + //SystemLogger.Log($"Debug-StoreKeyLocally: No File Existed. Creating new File..."); newKeyStorage = new NodeKeyStorageFile(); } - SystemLogger.Log($"Debug-StoreKeyLocally: Storing Keys:"); + //SystemLogger.Log($"Debug-StoreKeyLocally: Storing Keys:"); switch (keyType) { @@ -1036,7 +1061,7 @@ namespace SPHERE.Configure { try { - SystemLogger.Log($"Debug-LoadKeyFile: Loading Key File..."); + // SystemLogger.Log($"Debug-LoadKeyFile: Loading Key File..."); if (!File.Exists(KeyFilePath)) { @@ -1068,7 +1093,7 @@ namespace SPHERE.Configure return null; } - SystemLogger.Log($"Debug-LoadKeyFile: Successfully deserialized key file."); + // SystemLogger.Log($"Debug-LoadKeyFile: Successfully deserialized key file."); return file; } catch (Exception ex) @@ -1089,7 +1114,7 @@ namespace SPHERE.Configure return; } - SystemLogger.Log($"Debug-SaveKeyStorage: Saving Node Key Storage:"); + //SystemLogger.Log($"Debug-SaveKeyStorage: Saving Node Key Storage:"); // Prevent saving if all keys are NULL if (string.IsNullOrEmpty(keyStorage.NodePublicSignatureKey) && @@ -1112,7 +1137,7 @@ namespace SPHERE.Configure } File.WriteAllBytes(KeyFilePath, encryptedData); - SystemLogger.Log($"Debug-SaveKeyStorage: Successfully wrote Key to file."); + // SystemLogger.Log($"Debug-SaveKeyStorage: Successfully wrote Key to file."); SetSecureFilePermissions(KeyFilePath); } @@ -1185,7 +1210,8 @@ namespace SPHERE.Configure { try { - SystemLogger.Log($"Debug-UseKeyInStorageContainer: Attempting to get Key."); + // SystemLogger.Log($"Debug-UseKeyInStorageContainer: Using KeyManager instance {node.KeyManager.GetHashCode()} to retrieve {keyType}"); + // SystemLogger.Log($"Debug-UseKeyInStorageContainer: Attempting to get Key."); byte[] keyData= null; PrivateKeyManager privateKeyManager = node.KeyManager; @@ -1209,31 +1235,31 @@ namespace SPHERE.Configure break; case KeyType.PrivatePersonalEncryptionKey: - keyData = privateKeyManager.GetPersonalKey(KeyType.PrivatePersonalEncryptionKey); + keyData = privateKeyManager.GetPersonalKey(node, KeyType.PrivatePersonalEncryptionKey); break; case KeyType.PrivatePersonalSignatureKey: - keyData = privateKeyManager.GetPersonalKey(KeyType.PrivatePersonalSignatureKey); + keyData = privateKeyManager.GetPersonalKey(node, KeyType.PrivatePersonalSignatureKey); break; case KeyType.PublicPersonalEncryptionKey: - keyData = privateKeyManager.GetPersonalKey(KeyType.PrivatePersonalEncryptionKey); + keyData = privateKeyManager.GetPersonalKey(node, KeyType.PublicPersonalEncryptionKey); break; case KeyType.PublicPersonalSignatureKey: - keyData = privateKeyManager.GetPersonalKey(KeyType.PrivatePersonalSignatureKey); + keyData = privateKeyManager.GetPersonalKey(node, KeyType.PublicPersonalSignatureKey); break; case KeyType.SemiPublicKey: - keyData = privateKeyManager.GetPersonalKey(KeyType.SemiPublicKey); + keyData = privateKeyManager.GetPersonalKey(node, KeyType.SemiPublicKey); break; case KeyType.LocalSymmetricKey: - keyData = privateKeyManager.GetPersonalKey(KeyType.LocalSymmetricKey); + keyData = privateKeyManager.GetPersonalKey(node, KeyType.LocalSymmetricKey); break; case KeyType.EncryptedLocalSymmetricKey: - keyData = privateKeyManager.GetPersonalKey(KeyType.LocalSymmetricKey); + keyData = privateKeyManager.GetPersonalKey(node, KeyType.EncryptedLocalSymmetricKey); break; default: @@ -1242,7 +1268,7 @@ namespace SPHERE.Configure } if (keyData == null || keyData.Length == 0) { - SystemLogger.Log($"Error-UseKeyInStorageContainer: Retrieved key is null or empty for keyType: {keyType}"); + // SystemLogger.Log($"Error-UseKeyInStorageContainer: Retrieved key is null or empty for keyType: {keyType}"); throw new Exception($"Key retrieval failed for {keyType}, keyData is null or empty."); } return keyData; diff --git a/SPHERE/Configure/SecureLoader.cs b/SPHERE/Configure/SecureLoader.cs deleted file mode 100644 index 2aa12ec..0000000 --- a/SPHERE/Configure/SecureLoader.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.IO; -using System.Reflection; - -namespace SPHERE.Configure -{ - - - - public static class SecureLoader - { - // private static bool _isLoaded = false; - - // public static void EnsureLoaded() - // { - // if (_isLoaded) return; // Prevent redundant loading - // _isLoaded = true; - - // string basePath = AppDomain.CurrentDomain.BaseDirectory; - // string[] possiblePaths = - // { - // Path.Combine(basePath, "Packet.dll"), // Standard location - // Path.Combine(basePath, "libs", "Packet.dll"), // Alternative "libs" directory - // Path.Combine(basePath, "bin", "Packet.dll"), // If it's inside a bin folder - // Path.Combine(basePath, "lib", "net8.0", "Packet.dll") // NuGet installation path - //}; - - // string packetDllPath = possiblePaths.FirstOrDefault(File.Exists) - // ?? throw new FileNotFoundException("Packet.dll not found in expected locations."); - - // SystemLogger.Log($"[INFO] Dynamically loading Packet.dll from: {packetDllPath}"); - - // // 🔥 Load with LoadFrom() to properly register the assembly - // Assembly packetAssembly = Assembly.LoadFrom(packetDllPath); - - // // 🔄 Validate successful loading - // if (packetAssembly == null) - // throw new InvalidOperationException("Failed to load Packet.dll into AppDomain."); - - // SystemLogger.Log("[INFO] Packet.dll loaded successfully."); - // } - - } -} diff --git a/SPHERE/Configure/SignatureGenerator.cs b/SPHERE/Configure/SignatureGenerator.cs index c7f339e..9e1bb90 100644 --- a/SPHERE/Configure/SignatureGenerator.cs +++ b/SPHERE/Configure/SignatureGenerator.cs @@ -108,18 +108,14 @@ namespace SPHERE.Configure public static byte[] SignByteArray(Node node, byte[] data) { - - bool isTesting = Environment.GetEnvironmentVariable("SPHERE_TEST_MODE") == "true"; - if (isTesting) - { // Create the signature using the private key try { using (var ecdsa = ECDsa.Create()) { - byte[] hash = SHA256.HashData(data); + //byte[] hash = SHA256.HashData(data); ecdsa.ImportPkcs8PrivateKey(node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PrivateNodeSignatureKey), out _); - byte[] signature = ecdsa.SignData(hash, HashAlgorithmName.SHA256); + byte[] signature = ecdsa.SignData(data, HashAlgorithmName.SHA256); // Return the signature as a Base64-encoded string return signature; @@ -131,31 +127,7 @@ namespace SPHERE.Configure SystemLogger.Log(ex.Message); return null; } - } - else - { - // Create the signature using the private key - try - { - using (var ecdsa = ECDsa.Create()) - { - byte[] hash = SHA256.HashData(data); - ecdsa.ImportPkcs8PrivateKey(node.KeyManager.UseKeyInStorageContainer(node, KeyGenerator.KeyType.PrivateNodeSignatureKey), out _); - byte[] signature = ecdsa.SignHash(hash); - - // Return the signature as a Base64-encoded string - return signature; - - } - } - catch (Exception ex) - { - SystemLogger.Log(ex.Message); - return null; - } - - - } + } // Verify a byte array using the public key @@ -163,20 +135,22 @@ namespace SPHERE.Configure { try { - // Convert the Base64 public key back to a byte array - byte[] publicKeyBytes = publicKey; - // Import the public key using (ECDsa ecdsa = ECDsa.Create()) { - ecdsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _); + ecdsa.ImportSubjectPublicKeyInfo(publicKey, out _); // Convert the signature back to a byte array byte[] signatureBytes = signature; - byte[] receivedHash = SHA256.HashData(data); - + //byte[] receivedHash = SHA256.HashData(data); + bool isValid = ecdsa.VerifyData(data, signature, HashAlgorithmName.SHA256); // Verify the signature - return ecdsa.VerifyHash(receivedHash, signatureBytes); + //return ecdsa.VerifyHash(receivedHash, signatureBytes); + if (!isValid) + { + SystemLogger.Log("Signature verification failed."); + } + return isValid; } } catch (Exception ex) diff --git a/SPHERE/Configure/System Management/CleanupTasks.cs b/SPHERE/Configure/System Management/CleanupTasks.cs index f0b1c83..7279a60 100644 --- a/SPHERE/Configure/System Management/CleanupTasks.cs +++ b/SPHERE/Configure/System Management/CleanupTasks.cs @@ -186,6 +186,11 @@ namespace SPHERE.Configure { Peer peer = new Peer(); List peers = node.RoutingTable.GetBestReputationPeers(node.Peer.NodeId, 10); + if(peers.Count==0) + { + SystemLogger.Log("No peers found Skipping Ping "); + return; + } Random rnd = new Random(); int r = rnd.Next(peers.Count); peer = peers[r]; @@ -235,8 +240,13 @@ namespace SPHERE.Configure SystemLogger.Log("Broadcasting peer ping to all known peers..."); List peers = node.RoutingTable.GetAllPeers(); + if (peers.Count == 0) + { + SystemLogger.Log("No peers found Skipping Auto Broadcast ping "); + return; + } - foreach (var peer in peers) + foreach (var peer in peers) { node.NetworkManager.PingPeerAsync(node, peer); } diff --git a/SPHERE/Configure/System Management/SystemLogger.cs b/SPHERE/Configure/System Management/SystemLogger.cs index ff7ec76..00dcaa7 100644 --- a/SPHERE/Configure/System Management/SystemLogger.cs +++ b/SPHERE/Configure/System Management/SystemLogger.cs @@ -41,7 +41,7 @@ namespace SPHERE.Configure.Logging } else { - // Console.WriteLine(message); + Console.WriteLine(message); } diff --git a/SPHERE/Security/KeyGenerator.cs b/SPHERE/Security/KeyGenerator.cs index ce0f9f5..5679c46 100644 --- a/SPHERE/Security/KeyGenerator.cs +++ b/SPHERE/Security/KeyGenerator.cs @@ -56,17 +56,12 @@ namespace SPHERE.Security LocalSymmetricKey, SemiPublicKey, CNGCert, - //PublicTestNodeSignatureKey, - //PrivateTestNodeSignatureKey, - //PublicTestNodeEncryptionKey, - //PrivateTestNodeEncryptionKey, - } - internal static void GeneratePersonalKeyPairSets(Password exportPassword) + internal static void GeneratePersonalKeyPairSets(Node node) { using var signaturePair = ECDsa.Create(ECCurve.NamedCurves.nistP256); using var encryptPair = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP256); - PrivateKeyManager PrivateKeyManager = new(); + PrivateKeyManager PrivateKeyManager = node.KeyManager; if (signaturePair == null || encryptPair == null) { throw new InvalidOperationException("Failed to create cryptographic key pairs."); @@ -79,16 +74,10 @@ namespace SPHERE.Security try { - PrivateKeyManager.SetPrivatePersonalKey(privateSignatureKey, KeyType.PrivatePersonalSignatureKey); - PrivateKeyManager.SetPrivatePersonalKey(publicSignatureKey, KeyType.PublicPersonalSignatureKey); - PrivateKeyManager.SetPrivatePersonalKey(privateEncryptionKey, KeyType.PrivatePersonalEncryptionKey); - PrivateKeyManager.SetPrivatePersonalKey(publicEncryptionKey, KeyType.PublicPersonalEncryptionKey); - - - //ServiceAccountManager.StorePrivateKeyInContainerWithExportPlainText(privateSignatureKey, KeyType.PrivatePersonalSignatureKey, exportPassword); - //ServiceAccountManager.StoreKeyInContainerWithExport(publicSignatureKey, KeyType.PublicPersonalSignatureKey); - //ServiceAccountManager.StorePrivateKeyInContainerWithExportPlainText(privateEncryptionKey, KeyType.PrivatePersonalEncryptionKey, exportPassword); - //ServiceAccountManager.StoreKeyInContainerWithExport(publicEncryptionKey, KeyType.PublicPersonalEncryptionKey); + PrivateKeyManager.SetPrivatePersonalKey(node, privateSignatureKey, KeyType.PrivatePersonalSignatureKey); + PrivateKeyManager.SetPrivatePersonalKey(node, publicSignatureKey, KeyType.PublicPersonalSignatureKey); + PrivateKeyManager.SetPrivatePersonalKey(node, privateEncryptionKey, KeyType.PrivatePersonalEncryptionKey); + PrivateKeyManager.SetPrivatePersonalKey(node, publicEncryptionKey, KeyType.PublicPersonalEncryptionKey); } catch (Exception ex) diff --git a/SPHERE/Testing.cs b/SPHERE/Testing.cs index 012c021..5a8c856 100644 --- a/SPHERE/Testing.cs +++ b/SPHERE/Testing.cs @@ -11,6 +11,10 @@ using static SPHERE.Blockchain.Contact; using System; using System.Xml.Linq; using static SPHERE.Networking.Packet; +using SPHERE.Configure; +using static SPHERE.Security.KeyGenerator; +using System.Text.Json; +using System.Diagnostics.Eventing.Reader; @@ -59,7 +63,7 @@ namespace SPHERE.TestingLib Console.WriteLine($"Debug: Starting Create Client "); Client client = new Client(); client.clientListenerPort = testClientListenerPort; - client.clientIP = IPAddress.Parse(testClientIP); + client.clientIP = client.GetLocalIPAddress(); Console.WriteLine($"Debug: Starting Create TestNode "); try @@ -74,23 +78,6 @@ namespace SPHERE.TestingLib throw; } - try - { - Console.WriteLine("Retrieving Keys from Storage..."); - byte[] publicSigKey = testNode.KeyManager.UseKeyInStorageContainer(testNode, KeyGenerator.KeyType.PublicNodeSignatureKey); - byte[] privateSigKey = testNode.KeyManager.UseKeyInStorageContainer(testNode, KeyGenerator.KeyType.PrivateNodeSignatureKey); - byte[] publicEncKey = testNode.KeyManager.UseKeyInStorageContainer(testNode, KeyGenerator.KeyType.PublicNodeEncryptionKey); - byte[] privateEncKey = testNode.KeyManager.UseKeyInStorageContainer(testNode, KeyGenerator.KeyType.PrivateNodeEncryptionKey); - - string sigKeyBase64 = Convert.ToBase64String(publicSigKey); - string encKeyBase64 = Convert.ToBase64String(publicEncKey); - - } - catch (Exception ex) - { - Console.WriteLine($"Error Retrieving Keys: {ex.Message}"); - throw; - } try { @@ -178,6 +165,7 @@ namespace SPHERE.TestingLib } Console.WriteLine("Node Created Successfully!"); + testNode.Client.StartClientListenerAsync(testNode); return testNode; } catch (Exception ex) @@ -349,7 +337,6 @@ namespace SPHERE.TestingLib PreviousHash = "PreviousHashExample", BlockCreationTime = DateTime.UtcNow, LastUpdateTime = DateTime.UtcNow, - EncryptionAlgorithm = "AES256", KeyUsagePolicies = "MESSAGE_ENCRYPTION_ONLY", PublicSignatureKey = peer.PublicSignatureKey, PublicEncryptionKey = peer.PublicEncryptKey, @@ -569,53 +556,23 @@ namespace SPHERE.TestingLib } } - public static Contact TestCreateNewContact(string displayName, string name, string blockId, string? avatarURL, string? description, Password privateKeyPassword) - { - var semiPublicKey = testSemiPublicKey; - var localSymmetricKey = testLocalSymmetricKey; - - var encryptedLocalSymmetricKey = testLocalEncryptedSymmetricKey; - - ContactKeys keys = new ContactKeys - { - PublicPersonalEncryptionKey = TestUseKeyInStorageContainer(KeyGenerator.KeyType.PublicPersonalEncryptionKey), - PublicPersonalSignatureKey = TestUseKeyInStorageContainer(KeyGenerator.KeyType.PublicPersonalSignatureKey), - SemiPublicKey = TestUseKeyInStorageContainer(KeyGenerator.KeyType.SemiPublicKey), - LocalSymmetricKey = TestUseKeyInStorageContainer(KeyGenerator.KeyType.LocalSymmetricKey) - }; - - ContactMetaData metaData = new ContactMetaData - { - DisplayName = displayName, - Name = name, - AvatarURLHash = avatarURL, - Description = description, - - }; - - Contact contact = new Contact - { - MetaData = metaData, - Keys = keys, - - }; - return contact; - } - - public class NodeManager + public class NodeManager { public static List Nodes = new List(); - public static void CreateFakeNodeTest(int nodeToMake) + public static void CreateFakeNodeTest(int nodeToMake, bool? silent) { - - Console.WriteLine("Setting test Variable True."); + Environment.SetEnvironmentVariable("SPHERE_TEST_MODE", "true"); string testModeEnv = Environment.GetEnvironmentVariable("SPHERE_TEST_MODE"); - Console.WriteLine($"SPHERE_TEST_MODE= {testModeEnv}."); + if (silent != null && silent != true) + { + Console.WriteLine("Setting test Variable True."); + Console.WriteLine($"SPHERE_TEST_MODE= {testModeEnv}."); + } for (int i = 0; i < nodeToMake; i++) { try @@ -623,29 +580,40 @@ namespace SPHERE.TestingLib Console.WriteLine("Creating a test node with a fake STUN..."); // Create a test node - Console.WriteLine("Starting testing.CreateTestNodeWithFakeSTUNAsync."); Node testNode = CreateTestNodeWithFakeSTUNAsync(NodeType.Full); - Console.WriteLine("\n=== Node Created ==="); - Console.WriteLine($"Node ID: {testNode.Peer.NodeId}"); - Console.WriteLine($"Node IP: {testNode.Peer.NodeIP}"); - Console.WriteLine($"Node Port: {testNode.Peer.NodePort}"); - Console.WriteLine($"Node Type: {testNode.Peer.Node_Type}"); - Console.WriteLine($"Public Signature Key: {testNode.Peer.PublicSignatureKey}"); - Console.WriteLine($"Public Encryption Key: {testNode.Peer.PublicEncryptKey}"); + if (silent != null && silent != true) + { + Console.WriteLine("\n=== Node Created ==="); + Console.WriteLine($"Node ID: {testNode.Peer.NodeId}"); + Console.WriteLine($"Node IP: {testNode.Peer.NodeIP}"); + Console.WriteLine($"Node Port: {testNode.Peer.NodePort}"); + Console.WriteLine($"Node Type: {testNode.Peer.Node_Type}"); + Console.WriteLine($"Public Signature Key: {testNode.Peer.PublicSignatureKey}"); + Console.WriteLine($"Public Encryption Key: {testNode.Peer.PublicEncryptKey}"); - Console.WriteLine("\n=== Routing Table ==="); + Console.WriteLine("\n=== Routing Table ==="); + } int totalPeers = testNode.RoutingTable.GetAllPeers().Count(); - Console.WriteLine($"\nRouting Table Contains {totalPeers}.."); - Console.WriteLine($"First 5 Peers..."); + + if (silent != null && silent != true) + { + Console.WriteLine($"\nRouting Table Contains {totalPeers}.."); + Console.WriteLine($"First 5 Peers..."); + } + int totalPeersCountDown = 5; + foreach (var peer in testNode.RoutingTable.GetAllPeers()) { if (totalPeersCountDown > 0) { - Console.WriteLine($"Peer ID: {peer.NodeId}, IP: {peer.NodeIP}, Port: {peer.NodePort}, Trust Score: {peer.Reputation}"); - totalPeersCountDown--; + if (silent != null && silent != true) + { + Console.WriteLine($"Peer ID: {peer.NodeId}, IP: {peer.NodeIP}, Port: {peer.NodePort}, Trust Score: {peer.Reputation}"); + } + totalPeersCountDown--; } else { @@ -653,16 +621,23 @@ namespace SPHERE.TestingLib } } - Console.WriteLine("\n=== DHT Blocks ==="); int totalBlocks = testNode.ContactDHT.GetTotalBlockCount(); - Console.WriteLine($"\nDHT Contains {totalBlocks}.."); - Console.WriteLine($"First 5 Blocks..."); + if (silent != null && silent != true) + { + Console.WriteLine("\n=== DHT Blocks ==="); + Console.WriteLine($"\nDHT Contains {totalBlocks}.."); + Console.WriteLine($"First 5 Blocks..."); + } int totalBlocksCountDown = 5; foreach (var block in testNode.ContactDHT.GetCurrentState()) { if (totalBlocksCountDown > 0) { - Console.WriteLine($"Block ID: {block.Header.BlockId}, Created: {block.Header.BlockCreationTime}, Updated: {block.Header.LastUpdateTime}"); + if (silent != null && silent != true) + { + + Console.WriteLine($"Block ID: {block.Header.BlockId}, Created: {block.Header.BlockCreationTime}, Updated: {block.Header.LastUpdateTime}"); + } totalBlocksCountDown--; } else @@ -671,7 +646,10 @@ namespace SPHERE.TestingLib } } - Console.WriteLine("\nTest node creation completed successfully."); + if (silent != null && silent != true) + { + Console.WriteLine("\nTest node creation completed successfully."); + } } catch (Exception ex) { @@ -685,13 +663,13 @@ namespace SPHERE.TestingLib } } - Console.ReadLine(); // Keep the console open + Console.ReadLine(); } public static async Task TestBootstrap() { Node hostNode = new Node(); - + try { Environment.SetEnvironmentVariable("SPHERE_TEST_MODE", "true"); @@ -701,10 +679,9 @@ namespace SPHERE.TestingLib try { //Create a Full Fake Node DHT and RT and assign as HOST - CreateFakeNodeTest(1); + CreateFakeNodeTest(1,false); hostNode = GetFirstNode(); Console.WriteLine($"Starting hostNode Listener at {hostNode.Client.clientIP}:{hostNode.Client.clientListenerPort}"); - hostNode.Client.StartClientListenerAsync(hostNode, hostNode.Client); Console.WriteLine($"hostNode Created Successfully"); Console.WriteLine($"hostNode DHT size is {hostNode.ContactDHT.GetTotalBlockCount()}"); Console.WriteLine($"hostNode Routing Table size is {hostNode.RoutingTable.GetAllPeers().Count()}"); @@ -714,14 +691,14 @@ namespace SPHERE.TestingLib Console.WriteLine($"Error: Creating hostNode. {ex.Message}"); throw new Exception(); } - Node babyNode = new Node(); + Node babyNode = Node.CreateNodeUsingSTUN(NodeType.Full); + try { - // Create a babyNode with no Rt or DHT. - babyNode = CreateTestNodeWithNoDHTorRoutingTable(NodeType.Full); + Console.WriteLine($"Creating babyNode"); + // Create a babyNode with no Rt or DHT. Console.WriteLine($"babyNode Created Successfully"); - Console.WriteLine($"Starting babyNode Listener at {babyNode.Client.clientIP}:{babyNode.Client.clientListenerPort}"); - babyNode.Client.StartClientListenerAsync(babyNode, babyNode.Client); + Console.WriteLine($"Starting babyNode Listener at {babyNode.Client.clientIP.ToString()}:{babyNode.Client.clientListenerPort}"); Console.WriteLine($"babyNode DHT Starting size is {babyNode.ContactDHT.GetTotalBlockCount()}"); Console.WriteLine($"babyNode Routing Table Starting size is {babyNode.RoutingTable.GetAllPeers().Count()}"); @@ -741,10 +718,10 @@ namespace SPHERE.TestingLib } catch (Exception ex) { - Console.WriteLine($"Error: Failed to send BootStrapRequest"); + Console.WriteLine($"Error: Failed to send BootStrapRequest. Reason: {ex.Message}"); } - await Task.Delay(300); // A slight delay to allow async operations to settle (optional) + await Task.Delay(300); // A slight delay to allow async operations to settle (optional) Console.WriteLine($"babyNode has processed the BootStrap."); Console.WriteLine($"babyNode finished the test with a DHT of size: {babyNode.ContactDHT.GetTotalBlockCount()}"); Console.WriteLine($"babyNode finished the test with a Routing Table of size: {babyNode.RoutingTable.GetAllPeers().Count()}"); @@ -780,7 +757,7 @@ namespace SPHERE.TestingLib // Reset and create test nodes Nodes.Clear(); - CreateFakeNodeTest(5); + CreateFakeNodeTest(5, false); hostNode1 = Nodes[0]; hostNodes.Add(hostNode1); @@ -829,21 +806,13 @@ namespace SPHERE.TestingLib babyNode.RoutingTable.ClearRoutingTable(); babyNode.RoutingTable.AddPeer(hostNode4.Peer); - - foreach (var node in hostNodes) - { - node.Client.StartClientListenerAsync(node, node.Client); - } - babyNode.Client.StartClientListenerAsync(babyNode, babyNode.Client); - - // Broadcasting network connection Console.WriteLine("Debug-TestBrodcastToPeers: babyNode Broadcasting Connection to Network..."); await babyNode.NetworkManager.BroadcastConnectionToNetwork(babyNode); Console.WriteLine("Debug-TestBrodcastToPeers: babyNode Broadcast completed."); - // Print routing table sizes AFTER broadcast - // 🕒 Wait for peer propagation + + // Wait for peer propagation await Task.Delay(TimeSpan.FromSeconds(2)); // Adjust delay if needed // Print routing table sizes AFTER broadcast @@ -861,6 +830,7 @@ namespace SPHERE.TestingLib Console.WriteLine($"Debug-TestBrodcastToPeers: [ERROR] Stack Trace: {ex.StackTrace}"); throw; } + Console.ReadLine(); } @@ -886,6 +856,135 @@ namespace SPHERE.TestingLib return Nodes[0]; } + public static async Task TestGetBlockProcess() + { + + + Environment.SetEnvironmentVariable("SPHERE_TEST_MODE", "true"); + string testModeEnv = Environment.GetEnvironmentVariable("SPHERE_TEST_MODE"); + Console.WriteLine($"Debug-TestGetBlockProcess: SPHERE_TEST_MODE = {testModeEnv}"); + + List hostNodes = new List(); + + Node hostNode1 = new Node(); + Node hostNode2 = new Node(); + Node hostNode3 = new Node(); + Node hostNode4 = new Node(); + Node babyNode = new Node(); + + try + { + Console.WriteLine("Debug-TestGetBlockProcess: Initializing test environment..."); + + // Reset and create test nodes + Nodes.Clear(); + CreateFakeNodeTest(5,true); + + hostNode1 = Nodes[0]; + hostNodes.Add(hostNode1); + hostNode2 = Nodes[1]; + hostNodes.Add(hostNode2); + hostNode3 = Nodes[2]; + hostNodes.Add(hostNode3); + hostNode4 = Nodes[3]; + hostNodes.Add(hostNode4); + + // Clearing routing tables to prevent stale data + hostNode1.RoutingTable.ClearRoutingTable(); + hostNode2.RoutingTable.ClearRoutingTable(); + hostNode3.RoutingTable.ClearRoutingTable(); + hostNode4.RoutingTable.ClearRoutingTable(); + + // Adding initial peer connections + hostNode1.RoutingTable.AddPeer(hostNode2.Peer); + hostNode2.RoutingTable.AddPeer(hostNode1.Peer); + hostNode3.RoutingTable.AddPeer(hostNode2.Peer); + hostNode4.RoutingTable.AddPeer(hostNode3.Peer); + + + // Create a baby node and add a connection + Console.WriteLine("Debug-TestGetBlockProcess: Creating babyNode...@5"); + babyNode = Nodes[4]; + babyNode.RoutingTable.ClearRoutingTable(); + hostNode1.RoutingTable.AddPeer(babyNode.Peer); + hostNode2.RoutingTable.AddPeer(babyNode.Peer); + hostNode3.RoutingTable.AddPeer(babyNode.Peer); + hostNode4.RoutingTable.AddPeer(babyNode.Peer); + babyNode.RoutingTable.AddPeer(hostNode1.Peer); + babyNode.RoutingTable.AddPeer(hostNode2.Peer); + babyNode.RoutingTable.AddPeer(hostNode3.Peer); + babyNode.RoutingTable.AddPeer(hostNode4.Peer); + + //build a contact + string alias = "@SphereTest"; + string name = "Kenneth:Lasyone"; + string contactId = Node.GenerateKademliaId(); + Password password = Password.GenerateRandomPassword(); + string pin = "12345"; + + Contact newContact = Contact.CreateNewContact(hostNode1, contactId , alias, name, password, pin); + + + //add it to a block + + Block block = Block.CreateContactBlock(hostNode1, "UNKNOWN", newContact); + SystemLogger.Log($"Debug-TestGetBlockProcess: Contact Length on HostNode {block.EncryptedContact.Length}."); + + // add that block to a host. + hostNode1.ContactDHT.AddBlock(block); + SystemLogger.Log($"Debug-TestGetBlockProcess: BabyNode requesting block with ID of {block.Header.BlockId}."); + + + await NetworkManager.RequestBlockFromNetwork(babyNode, block.Header.BlockId); + await Task.Delay(TimeSpan.FromSeconds(5)); + + Block recievedBlock = babyNode.ContactDHT.GetBlock(block.Header.BlockId); + string recievedContact = recievedBlock.EncryptedContact; + + if (recievedBlock!=null) + { + SystemLogger.Log($"Debug-TestGetBlockProcess: BabyNode Has found the block with ID of {recievedBlock.Header.BlockId}."); + } + else + { + SystemLogger.Log($"Debug-TestGetBlockProcess: BabyNode did not find the block after requesting."); + return; + } + + SystemLogger.Log($"Debug-TestGetBlockProcess: Received Contact Length on BabyNode {recievedBlock.EncryptedContact.Length}."); + + byte[] LocalSymetricKey = Encryption.DecryptLocalSymmetricKey(recievedBlock.EncryptedLocalSymmetricKey, newContact.Keys.SemiPublicKey); + Contact incomingContact = DecryptAndBuildContact(recievedContact, LocalSymetricKey); + + if (incomingContact != null) + { + + SystemLogger.Log($"Debug-TestGetBlockProcess: BabyNode Has found the Contact with ID of {incomingContact.MetaData.ContactID}."); + SystemLogger.Log($"Debug-TestGetBlockProcess: BabyNode Has found the Contact with Name of {incomingContact.MetaData.Name}."); + SystemLogger.Log($"Debug-TestGetBlockProcess: BabyNode Has found the Contact with DisplayName of {incomingContact.MetaData.DisplayName}."); + SystemLogger.Log($"Debug-TestGetBlockProcess: BabyNode Has successfully Completed the test. ."); + + } + else + { + SystemLogger.Log($"Debug-TestGetBlockProcess: BabyNode Failed to access Contact {recievedBlock.Header.BlockId}."); + return; + } + + + + } + catch (Exception ex) + { + Console.WriteLine($"Debug-TestGetBlockProcess: [ERROR] {ex.Message}"); + Console.WriteLine($"Debug-TestGetBlockProcess: [ERROR] Stack Trace: {ex.StackTrace}"); + throw; + } + + Console.ReadLine(); + + } + } }