Spaces:
Running
Running
talexm
commited on
Commit
•
92c34be
1
Parent(s):
fdc732d
adding chinguard, anomaly detector and visualisation tool
Browse files- anomaly_detection_tool/README.md +50 -0
- {sec-rag-model → anomaly_detection_tool}/__init__.py +0 -0
- anomaly_detection_tool/anomaly_detection_model.py +30 -0
- anomaly_detection_tool/data_processor.py +38 -0
- chainguard/__init__.py +0 -0
- chainguard/blockchain.py +46 -0
- chainguard/blockchain_logger.py +30 -0
- chainguard/data_transfer.py +46 -0
- chainguard/data_transformer.py +35 -0
- chainguard/encryption.py +45 -0
- chainguard/tests/__init__.py +0 -0
- chainguard/tests/test_blockchain.py +29 -0
- chainguard/tests/test_data_transfer.py +30 -0
- chainguard/tests/test_encryption.py +29 -0
- visualisation/__init__.py +0 -0
- visualisation/chainguard_graph_db.py +102 -0
anomaly_detection_tool/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Anomaly Detection Model
|
2 |
+
## Overview
|
3 |
+
This repository contains a Python class AnomalyDetectionModel built using TensorFlow and Keras
|
4 |
+
for detecting anomalies in network traffic data. The class encapsulates the creation, training,
|
5 |
+
and evaluation of a neural network model designed to classify network data as either normal or anomalous.
|
6 |
+
|
7 |
+
### Why Use a Sequential Model?
|
8 |
+
The Sequential model in Keras is a simple, linear stack of layers.
|
9 |
+
It is ideal for building feedforward neural networks where the model
|
10 |
+
progresses through each layer sequentially, without any branching or complex topologies.
|
11 |
+
|
12 |
+
### Key Reasons for Using Sequential:
|
13 |
+
|
14 |
+
Simplicity: The Sequential API is straightforward and easy to use. It is perfect for beginners and
|
15 |
+
for models that involve a single input and output with layers stacked one after the other.
|
16 |
+
|
17 |
+
Linear Stack: For the task of anomaly detection, the architecture typically involves a simple
|
18 |
+
forward pass through several dense layers, making the Sequential model a natural fit.
|
19 |
+
|
20 |
+
Flexibility: While simple, the Sequential model is flexible enough to allow for customization
|
21 |
+
through the addition of various types of layers, activation functions, and regularization techniques.
|
22 |
+
|
23 |
+
Example Usage
|
24 |
+
```python
|
25 |
+
|
26 |
+
# Initialize the model with the input shape
|
27 |
+
anomaly_model = AnomalyDetectionModel(X_train.shape[1])
|
28 |
+
|
29 |
+
# Train the model
|
30 |
+
history = anomaly_model.train(X_train, y_train)
|
31 |
+
|
32 |
+
# Evaluate the model on the test data
|
33 |
+
loss, accuracy = anomaly_model.evaluate(X_test, y_test)
|
34 |
+
print(f'Test Accuracy: {accuracy:.4f}')
|
35 |
+
```
|
36 |
+
|
37 |
+
Dependencies
|
38 |
+
Python 3.x
|
39 |
+
TensorFlow
|
40 |
+
Keras (included with TensorFlow)
|
41 |
+
Scikit-learn
|
42 |
+
Pandas
|
43 |
+
Installation
|
44 |
+
Install the required packages using pip:
|
45 |
+
|
46 |
+
Conclusion
|
47 |
+
The Sequential model is a great choice for this anomaly detection task due to its simplicity,
|
48 |
+
ease of use, and the linear nature of the problem. This approach ensures that the model is easy
|
49 |
+
to build, understand, and maintain while still providing robust performance for binary classification
|
50 |
+
tasks such as anomaly detection.
|
{sec-rag-model → anomaly_detection_tool}/__init__.py
RENAMED
File without changes
|
anomaly_detection_tool/anomaly_detection_model.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import tensorflow as tf
|
2 |
+
from tensorflow.keras import layers, models
|
3 |
+
|
4 |
+
class AnomalyDetectionModel:
|
5 |
+
def __init__(self, input_shape):
|
6 |
+
self.model = self.build_model(input_shape)
|
7 |
+
|
8 |
+
def build_model(self, input_shape):
|
9 |
+
model = models.Sequential([
|
10 |
+
layers.Dense(64, activation='relu', input_shape=(input_shape,)),
|
11 |
+
layers.Dense(32, activation='relu'),
|
12 |
+
layers.Dense(16, activation='relu'),
|
13 |
+
layers.Dense(1, activation='sigmoid')
|
14 |
+
])
|
15 |
+
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
|
16 |
+
return model
|
17 |
+
|
18 |
+
def train(self, X_train, y_train, epochs=10, batch_size=32, validation_split=0.2):
|
19 |
+
history = self.model.fit(X_train, y_train, epochs=epochs, batch_size=batch_size, validation_split=validation_split)
|
20 |
+
return history
|
21 |
+
|
22 |
+
def evaluate(self, X_test, y_test):
|
23 |
+
loss, accuracy = self.model.evaluate(X_test, y_test)
|
24 |
+
return loss, accuracy
|
25 |
+
|
26 |
+
# Example usage:
|
27 |
+
# anomaly_model = AnomalyDetectionModel(X_train.shape[1])
|
28 |
+
# history = anomaly_model.train(X_train, y_train)
|
29 |
+
# loss, accuracy = anomaly_model.evaluate(X_test, y_test)
|
30 |
+
# print(f'Test Accuracy: {accuracy:.4f}')
|
anomaly_detection_tool/data_processor.py
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#import fireducks.pandas as pd
|
2 |
+
import pandas as pd
|
3 |
+
|
4 |
+
from sklearn.model_selection import train_test_split
|
5 |
+
from sklearn.preprocessing import LabelEncoder, StandardScaler
|
6 |
+
|
7 |
+
class DataProcessor:
|
8 |
+
def __init__(self, csv_file):
|
9 |
+
self.data = pd.read_csv(csv_file)
|
10 |
+
self.label_encoders = {}
|
11 |
+
self.scaler = StandardScaler()
|
12 |
+
|
13 |
+
def preprocess_data(self):
|
14 |
+
for column in ['IP', 'Hostnames', 'OS']:
|
15 |
+
self.label_encoders[column] = LabelEncoder()
|
16 |
+
self.data[column] = self.label_encoders[column].fit_transform(self.data[column].astype(str))
|
17 |
+
|
18 |
+
self.data['Port'] = self.scaler.fit_transform(self.data[['Port']])
|
19 |
+
self.data['Timestamp'] = pd.to_datetime(self.data['Timestamp']).astype(int) / 10**9
|
20 |
+
return self.data
|
21 |
+
|
22 |
+
def get_features_and_labels(self, label_column='Anomaly'):
|
23 |
+
if label_column not in self.data.columns:
|
24 |
+
raise ValueError(f"Label column '{label_column}' not found in data.")
|
25 |
+
|
26 |
+
X = self.data.drop([label_column], axis=1)
|
27 |
+
y = self.data[label_column]
|
28 |
+
return X, y
|
29 |
+
|
30 |
+
def split_data(self, X, y, test_size=0.2, random_state=42):
|
31 |
+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=random_state)
|
32 |
+
return X_train, X_test, y_train, y_test
|
33 |
+
|
34 |
+
# # Example usage:
|
35 |
+
# processor = DataProcessor('shodan_scan_results.csv')
|
36 |
+
# processed_data = processor.preprocess_data()
|
37 |
+
# X, y = processor.get_features_and_labels()
|
38 |
+
# X_train, X_test, y_train, y_test = processor.split_data(X, y)
|
chainguard/__init__.py
ADDED
File without changes
|
chainguard/blockchain.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import hashlib
|
2 |
+
import time
|
3 |
+
|
4 |
+
class Block:
|
5 |
+
def __init__(self, index, previous_hash, timestamp, data, hash):
|
6 |
+
self.index = index
|
7 |
+
self.previous_hash = previous_hash
|
8 |
+
self.timestamp = timestamp
|
9 |
+
self.data = data
|
10 |
+
self.hash = hash
|
11 |
+
|
12 |
+
class Blockchain:
|
13 |
+
def __init__(self):
|
14 |
+
self.chain = [self.create_genesis_block()]
|
15 |
+
|
16 |
+
def create_genesis_block(self):
|
17 |
+
genesis_block = Block(0, "0", int(time.time()), "Genesis Block", "0")
|
18 |
+
genesis_block.hash = self.calculate_hash(genesis_block)
|
19 |
+
return genesis_block
|
20 |
+
|
21 |
+
def calculate_hash(self, block):
|
22 |
+
block_string = f"{block.index}{block.previous_hash}{block.timestamp}{block.data}".encode()
|
23 |
+
return hashlib.sha256(block_string).hexdigest()
|
24 |
+
|
25 |
+
def get_latest_block(self):
|
26 |
+
return self.chain[-1]
|
27 |
+
|
28 |
+
def add_block(self, data):
|
29 |
+
latest_block = self.get_latest_block()
|
30 |
+
new_block = Block(len(self.chain), latest_block.hash, int(time.time()), data, "")
|
31 |
+
new_block.hash = self.calculate_hash(new_block)
|
32 |
+
self.chain.append(new_block)
|
33 |
+
print(f"Block added: {new_block.hash}")
|
34 |
+
return new_block
|
35 |
+
|
36 |
+
def is_chain_valid(self):
|
37 |
+
for i in range(1, len(self.chain)):
|
38 |
+
current_block = self.chain[i]
|
39 |
+
previous_block = self.chain[i - 1]
|
40 |
+
|
41 |
+
if current_block.hash != self.calculate_hash(current_block):
|
42 |
+
return False
|
43 |
+
|
44 |
+
if current_block.previous_hash != previous_block.hash:
|
45 |
+
return False
|
46 |
+
return True
|
chainguard/blockchain_logger.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from chainguard.blockchain import Blockchain
|
2 |
+
|
3 |
+
class BlockchainLogger:
|
4 |
+
def __init__(self):
|
5 |
+
self.blockchain = Blockchain()
|
6 |
+
|
7 |
+
def log_data(self, data: str):
|
8 |
+
"""
|
9 |
+
Logs the provided data into the blockchain.
|
10 |
+
Args:
|
11 |
+
data (str): The data to be logged in the blockchain.
|
12 |
+
Returns:
|
13 |
+
dict: The details of the newly added block.
|
14 |
+
"""
|
15 |
+
new_block = self.blockchain.add_block(data)
|
16 |
+
return {
|
17 |
+
"block_hash": new_block.hash,
|
18 |
+
"block_index": new_block.index,
|
19 |
+
"blockchain_length": len(self.blockchain.chain),
|
20 |
+
"previous_hash": new_block.previous_hash,
|
21 |
+
"timestamp": new_block.timestamp
|
22 |
+
}
|
23 |
+
|
24 |
+
def is_blockchain_valid(self):
|
25 |
+
"""
|
26 |
+
Validates the integrity of the blockchain.
|
27 |
+
Returns:
|
28 |
+
bool: True if the blockchain is valid, False otherwise.
|
29 |
+
"""
|
30 |
+
return self.blockchain.is_chain_valid()
|
chainguard/data_transfer.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import socket
|
2 |
+
from chainguard.encryption import AESCipher
|
3 |
+
from chainguard.blockchain_logger import BlockchainLogger
|
4 |
+
|
5 |
+
class SecureDataTransfer:
|
6 |
+
def __init__(self, password: str, host: str = 'localhost', port: int = 12345):
|
7 |
+
self.cipher = AESCipher(password)
|
8 |
+
self.host = host
|
9 |
+
self.port = port
|
10 |
+
self.blockchain_logger = BlockchainLogger()
|
11 |
+
|
12 |
+
def send_data(self, data: str):
|
13 |
+
"""
|
14 |
+
Encrypts and sends data over the network, then logs it in the blockchain.
|
15 |
+
"""
|
16 |
+
encrypted_data = self.cipher.encrypt(data)
|
17 |
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
18 |
+
s.connect((self.host, self.port))
|
19 |
+
s.sendall(encrypted_data.encode())
|
20 |
+
print(f"Sent encrypted data: {encrypted_data}")
|
21 |
+
# Log the transaction in the blockchain
|
22 |
+
self.blockchain_logger.log_data(encrypted_data)
|
23 |
+
|
24 |
+
def receive_data(self):
|
25 |
+
"""
|
26 |
+
Receives encrypted data, decrypts it, and logs it in the blockchain.
|
27 |
+
"""
|
28 |
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
29 |
+
s.bind((self.host, self.port))
|
30 |
+
s.listen()
|
31 |
+
conn, addr = s.accept()
|
32 |
+
with conn:
|
33 |
+
print(f"Connected by {addr}")
|
34 |
+
encrypted_data = conn.recv(1024).decode()
|
35 |
+
decrypted_data = self.cipher.decrypt(encrypted_data)
|
36 |
+
print(f"Received encrypted data: {encrypted_data}")
|
37 |
+
print(f"Decrypted data: {decrypted_data}")
|
38 |
+
# Log the transaction in the blockchain
|
39 |
+
self.blockchain_logger.log_data(encrypted_data)
|
40 |
+
return decrypted_data
|
41 |
+
|
42 |
+
def validate_blockchain(self):
|
43 |
+
"""
|
44 |
+
Validates the blockchain's integrity.
|
45 |
+
"""
|
46 |
+
return self.blockchain_logger.is_blockchain_valid()
|
chainguard/data_transformer.py
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from chainguard.blockchain_logger import BlockchainLogger
|
2 |
+
|
3 |
+
class DataTransformer:
|
4 |
+
def __init__(self):
|
5 |
+
"""
|
6 |
+
Initializes a DataTransformer with a blockchain logger instance.
|
7 |
+
"""
|
8 |
+
self.blockchain_logger = BlockchainLogger()
|
9 |
+
|
10 |
+
def secure_transform(self, data):
|
11 |
+
"""
|
12 |
+
Securely transforms the input data by logging it into the blockchain.
|
13 |
+
|
14 |
+
Args:
|
15 |
+
data (dict): The log data or any data to be securely transformed.
|
16 |
+
|
17 |
+
Returns:
|
18 |
+
dict: A dictionary containing the original data, block hash, and blockchain length.
|
19 |
+
"""
|
20 |
+
# Log the data into the blockchain
|
21 |
+
block_details = self.blockchain_logger.log_data(data)
|
22 |
+
|
23 |
+
# Return the block details and blockchain status
|
24 |
+
return {
|
25 |
+
"data": data,
|
26 |
+
**block_details
|
27 |
+
}
|
28 |
+
|
29 |
+
def validate_blockchain(self):
|
30 |
+
"""
|
31 |
+
Validates the integrity of the blockchain.
|
32 |
+
Returns:
|
33 |
+
bool: True if the blockchain is valid, False otherwise.
|
34 |
+
"""
|
35 |
+
return self.blockchain_logger.is_blockchain_valid()
|
chainguard/encryption.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
2 |
+
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
3 |
+
from cryptography.hazmat.primitives import hashes
|
4 |
+
from cryptography.hazmat.backends import default_backend
|
5 |
+
from cryptography.hazmat.primitives import padding
|
6 |
+
from base64 import b64encode, b64decode
|
7 |
+
import os
|
8 |
+
|
9 |
+
class AESCipher:
|
10 |
+
def __init__(self, key: str):
|
11 |
+
self.backend = default_backend()
|
12 |
+
salt = os.urandom(16)
|
13 |
+
kdf = PBKDF2HMAC(
|
14 |
+
algorithm=hashes.SHA256(),
|
15 |
+
length=32,
|
16 |
+
salt=salt,
|
17 |
+
iterations=100000,
|
18 |
+
backend=self.backend
|
19 |
+
)
|
20 |
+
self.key = kdf.derive(key.encode())
|
21 |
+
self.iv = os.urandom(16)
|
22 |
+
|
23 |
+
def encrypt(self, plaintext: str) -> str:
|
24 |
+
padder = padding.PKCS7(algorithms.AES.block_size).padder()
|
25 |
+
padded_data = padder.update(plaintext.encode()) + padder.finalize()
|
26 |
+
|
27 |
+
cipher = Cipher(algorithms.AES(self.key), modes.CBC(self.iv), backend=self.backend)
|
28 |
+
encryptor = cipher.encryptor()
|
29 |
+
encrypted_data = encryptor.update(padded_data) + encryptor.finalize()
|
30 |
+
|
31 |
+
return b64encode(self.iv + encrypted_data).decode('utf-8')
|
32 |
+
|
33 |
+
def decrypt(self, ciphertext: str) -> str:
|
34 |
+
encrypted_data = b64decode(ciphertext)
|
35 |
+
iv = encrypted_data[:16]
|
36 |
+
encrypted_data = encrypted_data[16:]
|
37 |
+
|
38 |
+
cipher = Cipher(algorithms.AES(self.key), modes.CBC(iv), backend=self.backend)
|
39 |
+
decryptor = cipher.decryptor()
|
40 |
+
padded_plaintext = decryptor.update(encrypted_data) + decryptor.finalize()
|
41 |
+
|
42 |
+
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
|
43 |
+
plaintext = unpadder.update(padded_plaintext) + unpadder.finalize()
|
44 |
+
|
45 |
+
return plaintext.decode('utf-8')
|
chainguard/tests/__init__.py
ADDED
File without changes
|
chainguard/tests/test_blockchain.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import unittest
|
2 |
+
from chainguard.blockchain import Blockchain
|
3 |
+
|
4 |
+
class TestBlockchain(unittest.TestCase):
|
5 |
+
def setUp(self):
|
6 |
+
self.blockchain = Blockchain()
|
7 |
+
|
8 |
+
def test_genesis_block(self):
|
9 |
+
genesis_block = self.blockchain.chain[0]
|
10 |
+
self.assertEqual(genesis_block.data, "Genesis Block")
|
11 |
+
|
12 |
+
def test_add_block(self):
|
13 |
+
self.blockchain.add_block("Test Block")
|
14 |
+
latest_block = self.blockchain.get_latest_block()
|
15 |
+
self.assertEqual(latest_block.data, "Test Block")
|
16 |
+
|
17 |
+
def test_chain_validity(self):
|
18 |
+
self.blockchain.add_block("First block")
|
19 |
+
self.blockchain.add_block("Second block")
|
20 |
+
self.assertTrue(self.blockchain.is_chain_valid())
|
21 |
+
|
22 |
+
def test_chain_invalidity(self):
|
23 |
+
self.blockchain.add_block("First block")
|
24 |
+
self.blockchain.chain[1].data = "Tampered Data"
|
25 |
+
self.assertFalse(self.blockchain.is_chain_valid())
|
26 |
+
|
27 |
+
if __name__ == '__main__':
|
28 |
+
unittest.main()
|
29 |
+
|
chainguard/tests/test_data_transfer.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# chainguard/tests/test_data_transfer.py
|
2 |
+
|
3 |
+
import unittest
|
4 |
+
import threading
|
5 |
+
from chainguard.data_transfer import SecureDataTransfer
|
6 |
+
|
7 |
+
class TestSecureDataTransfer(unittest.TestCase):
|
8 |
+
def setUp(self):
|
9 |
+
self.password = "transferpassword123"
|
10 |
+
self.data = "Sensitive data being transferred."
|
11 |
+
self.server = SecureDataTransfer(self.password)
|
12 |
+
self.client = SecureDataTransfer(self.password)
|
13 |
+
|
14 |
+
def test_data_transfer(self):
|
15 |
+
def run_server():
|
16 |
+
received_data = self.server.receive_data()
|
17 |
+
self.assertEqual(received_data, self.data)
|
18 |
+
|
19 |
+
server_thread = threading.Thread(target=run_server)
|
20 |
+
server_thread.start()
|
21 |
+
|
22 |
+
self.client.send_data(self.data)
|
23 |
+
server_thread.join()
|
24 |
+
|
25 |
+
# Validate blockchain integrity after transfer
|
26 |
+
self.assertTrue(self.server.validate_blockchain())
|
27 |
+
self.assertTrue(self.client.validate_blockchain())
|
28 |
+
|
29 |
+
if __name__ == '__main__':
|
30 |
+
unittest.main()
|
chainguard/tests/test_encryption.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import unittest
|
2 |
+
from chainguard.encryption import AESCipher
|
3 |
+
|
4 |
+
|
5 |
+
class TestAESCipher(unittest.TestCase):
|
6 |
+
def setUp(self):
|
7 |
+
self.password = "securepassword123"
|
8 |
+
self.cipher = AESCipher(self.password)
|
9 |
+
|
10 |
+
def test_encryption_decryption(self):
|
11 |
+
plaintext = "This is a secret message."
|
12 |
+
encrypted = self.cipher.encrypt(plaintext)
|
13 |
+
decrypted = self.cipher.decrypt(encrypted)
|
14 |
+
|
15 |
+
self.assertEqual(plaintext, decrypted)
|
16 |
+
|
17 |
+
def test_different_plaintext(self):
|
18 |
+
plaintext1 = "Message One"
|
19 |
+
plaintext2 = "Message Two"
|
20 |
+
encrypted1 = self.cipher.encrypt(plaintext1)
|
21 |
+
encrypted2 = self.cipher.encrypt(plaintext2)
|
22 |
+
|
23 |
+
self.assertNotEqual(encrypted1, encrypted2)
|
24 |
+
self.assertEqual(self.cipher.decrypt(encrypted1), plaintext1)
|
25 |
+
self.assertEqual(self.cipher.decrypt(encrypted2), plaintext2)
|
26 |
+
|
27 |
+
|
28 |
+
if __name__ == '__main__':
|
29 |
+
unittest.main()
|
visualisation/__init__.py
ADDED
File without changes
|
visualisation/chainguard_graph_db.py
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from neo4j import GraphDatabase
|
2 |
+
|
3 |
+
class ChainGuardGraphDB:
|
4 |
+
def __init__(self, uri, user, password):
|
5 |
+
self.driver = GraphDatabase.driver(uri, auth=(user, password))
|
6 |
+
|
7 |
+
def close(self):
|
8 |
+
"""Close the database connection."""
|
9 |
+
self.driver.close()
|
10 |
+
|
11 |
+
def create_node(self, label, properties):
|
12 |
+
"""Create a node with the specified label and properties."""
|
13 |
+
with self.driver.session() as session:
|
14 |
+
session.write_transaction(self._create_and_return_node, label, properties)
|
15 |
+
|
16 |
+
@staticmethod
|
17 |
+
def _create_and_return_node(tx, label, properties):
|
18 |
+
query = (
|
19 |
+
f"CREATE (n:{label} {{"
|
20 |
+
+ ", ".join([f"{k}: ${k}" for k in properties.keys()])
|
21 |
+
+ "}}) RETURN n"
|
22 |
+
)
|
23 |
+
result = tx.run(query, **properties)
|
24 |
+
return result.single()[0]
|
25 |
+
|
26 |
+
def create_relationship(self, node1_label, node1_property, node2_label, node2_property, relationship_type):
|
27 |
+
"""Create a relationship between two nodes."""
|
28 |
+
with self.driver.session() as session:
|
29 |
+
session.write_transaction(
|
30 |
+
self._create_and_return_relationship,
|
31 |
+
node1_label, node1_property, node2_label, node2_property, relationship_type
|
32 |
+
)
|
33 |
+
|
34 |
+
@staticmethod
|
35 |
+
def _create_and_return_relationship(tx, node1_label, node1_property, node2_label, node2_property, relationship_type):
|
36 |
+
query = (
|
37 |
+
f"MATCH (a:{node1_label} {{name: $node1_property}}), (b:{node2_label} {{name: $node2_property}}) "
|
38 |
+
f"CREATE (a)-[r:{relationship_type}]->(b) "
|
39 |
+
"RETURN r"
|
40 |
+
)
|
41 |
+
result = tx.run(query, node1_property=node1_property, node2_property=node2_property)
|
42 |
+
return result.single()[0]
|
43 |
+
|
44 |
+
def find_related_anomalies(self, transaction_name):
|
45 |
+
"""Find all anomalies related to a specific blockchain transaction."""
|
46 |
+
with self.driver.session() as session:
|
47 |
+
result = session.run(
|
48 |
+
"MATCH (t:BlockchainTransaction {name: $transaction_name})-[:DETECTED_IN]->(a:Anomaly) "
|
49 |
+
"RETURN a.name, a.type, a.severity",
|
50 |
+
transaction_name=transaction_name
|
51 |
+
)
|
52 |
+
return [record for record in result]
|
53 |
+
|
54 |
+
def find_blockchain_transactions(self, anomaly_name):
|
55 |
+
"""Find all blockchain transactions related to a specific anomaly."""
|
56 |
+
with self.driver.session() as session:
|
57 |
+
result = session.run(
|
58 |
+
"MATCH (a:Anomaly {name: $anomaly_name})<-[:DETECTED_IN]-(t:BlockchainTransaction) "
|
59 |
+
"RETURN t.name, t.amount, t.timestamp",
|
60 |
+
anomaly_name=anomaly_name
|
61 |
+
)
|
62 |
+
return [record for record in result]
|
63 |
+
|
64 |
+
def validate_blockchain(self):
|
65 |
+
"""Validate the blockchain (this is a simplified example)."""
|
66 |
+
with self.driver.session() as session:
|
67 |
+
result = session.run(
|
68 |
+
"MATCH (b:BlockchainTransaction) "
|
69 |
+
"RETURN COUNT(b) as transaction_count"
|
70 |
+
)
|
71 |
+
count = result.single()["transaction_count"]
|
72 |
+
# Simplified validation: checks if there are transactions in the blockchain
|
73 |
+
return count > 0
|
74 |
+
|
75 |
+
# Example usage
|
76 |
+
if __name__ == "__main__":
|
77 |
+
# Connect to the database
|
78 |
+
db = ChainGuardGraphDB(uri="bolt://localhost:7687", user="neo4j", password="your_password")
|
79 |
+
|
80 |
+
# Create nodes
|
81 |
+
db.create_node("BlockchainTransaction", {"name": "Tx1", "amount": 100, "timestamp": "2024-09-01"})
|
82 |
+
db.create_node("Anomaly", {"name": "Anomaly1", "type": "Network", "severity": "High"})
|
83 |
+
|
84 |
+
# Create relationships
|
85 |
+
db.create_relationship("BlockchainTransaction", "Tx1", "Anomaly", "Anomaly1", "DETECTED_IN")
|
86 |
+
|
87 |
+
# Query related anomalies for a transaction
|
88 |
+
related_anomalies = db.find_related_anomalies("Tx1")
|
89 |
+
for anomaly in related_anomalies:
|
90 |
+
print(f"Related Anomaly: {anomaly['a.name']}, Type: {anomaly['a.type']}, Severity: {anomaly['a.severity']}")
|
91 |
+
|
92 |
+
# Query related transactions for an anomaly
|
93 |
+
related_transactions = db.find_blockchain_transactions("Anomaly1")
|
94 |
+
for tx in related_transactions:
|
95 |
+
print(f"Related Transaction: {tx['t.name']}, Amount: {tx['t.amount']}, Timestamp: {tx['t.timestamp']}")
|
96 |
+
|
97 |
+
# Validate the blockchain
|
98 |
+
is_valid = db.validate_blockchain()
|
99 |
+
print(f"Blockchain valid: {is_valid}")
|
100 |
+
|
101 |
+
# Close the connection
|
102 |
+
db.close()
|