В настоящее время я разрабатываю приложение Python, разделенное на два сценария, каждый из которых будет помещен в один контейнер Docker.
Один из них имитирует работу автомата, создавая случайно сгенерированные данные, которые я храню в объекте dict, а затем отправляет их другому сценарию через библиотеку python socket
.
Данные, которые я отправляю, представлены так:
{
"unit": 1,
"timestamp": 1561566549688,
"params": {
"0": {
"temp_tank": 3.2,
"temp_ext": 11.7,
"tank_weight": 3686,
"finished_product_weighht": 406,
"pH_rate": 7.2,
"potassium_rate": 36,
"NaCL_concentration": 1.7,
"salmonella_level": 18,
"e-coli_level": 40,
"listeria_level": 30
},
"1": {
"temp_tank": 3.6,
"temp_ext": 10.2,
"tank_weight": 4597,
"finished_product_weighht": -219,
"pH_rate": 7.0,
"potassium_rate": 44,
"NaCL_concentration": 1.4,
"salmonella_level": 29,
"e-coli_level": 41,
"listeria_level": 39
},
"2": {
"temp_tank": 3.6,
"temp_ext": 11.7,
"tank_weight": 4587,
"finished_product_weighht": -938,
"pH_rate": 6.9,
"potassium_rate": 39,
"NaCL_concentration": 1.1,
"salmonella_level": 35,
"e-coli_level": 42,
"listeria_level": 50
},
"3": {
"temp_tank": 3.3,
"temp_ext": 10.3,
"tank_weight": 4120,
"finished_product_weighht": -38,
"pH_rate": 7.2,
"potassium_rate": 41,
"NaCL_concentration": 1.7,
"salmonella_level": 32,
"e-coli_level": 38,
"listeria_level": 41
},
"4": {
"temp_tank": 2.5,
"temp_ext": 12.5,
"tank_weight": 3723,
"finished_product_weighht": -134,
"pH_rate": 7.1,
"potassium_rate": 43,
"NaCL_concentration": 1.3,
"salmonella_level": 22,
"e-coli_level": 39,
"listeria_level": 30
},
"5": {
"temp_tank": 3.2,
"temp_ext": 9.5,
"tank_weight": 4236,
"finished_product_weighht": 116,
"pH_rate": 7.2,
"potassium_rate": 41,
"NaCL_concentration": 1.4,
"salmonella_level": 19,
"e-coli_level": 39,
"listeria_level": 44
},
"6": {
"temp_tank": 2.8,
"temp_ext": 11.6,
"tank_weight": 4279,
"finished_product_weighht": -616,
"pH_rate": 6.9,
"potassium_rate": 46,
"NaCL_concentration": 1.2,
"salmonella_level": 29,
"e-coli_level": 47,
"listeria_level": 47
},
"7": {
"temp_tank": 2.8,
"temp_ext": 13.0,
"tank_weight": 3774,
"finished_product_weighht": 290,
"pH_rate": 7.1,
"potassium_rate": 38,
"NaCL_concentration": 1.6,
"salmonella_level": 20,
"e-coli_level": 41,
"listeria_level": 39
},
"8": {
"temp_tank": 3.6,
"temp_ext": 13.0,
"tank_weight": 3978,
"finished_product_weighht": 381,
"pH_rate": 6.8,
"potassium_rate": 45,
"NaCL_concentration": 1.4,
"salmonella_level": 35,
"e-coli_level": 37,
"listeria_level": 49
},
"9": {
"temp_tank": 2.9,
"temp_ext": 10.2,
"tank_weight": 4109,
"finished_product_weighht": -174,
"pH_rate": 7.1,
"potassium_rate": 46,
"NaCL_concentration": 1.5,
"salmonella_level": 24,
"e-coli_level": 36,
"listeria_level": 45
}
}
}
Второй скрипт извлекает эти данные из той же библиотеки socket
, а затем помещает их в удаленную базу данных.
Эта часть работает без каких-либо проблем, я легко могу отправить отформатированную в json строку словаря данных из сценария генерации в другой с сокетами.
Проблема, с которой я столкнулся сейчас, заключается в том, что я хочу обеспечить безопасное соединение с сокетом путем асимметричного шифрования и дешифрования строки в формате json.
Для этого я использую библиотеку cryptography
python и шифрую с использованием RSA.
Когда я запускаю сценарии, при переходе к строке "socket send" оба сценария аварийно завершают работу. Первый выводит эту ошибку:
cryptography.exceptions.InternalError: Неизвестная ошибка OpenSSL. Эта ошибка обычно встречается, когда другая библиотека не очищает стек ошибок OpenSSL. Если вы используете криптографию с другой библиотекой, которую мы
Если OpenSSL попытается отключить его, прежде чем сообщать об ошибке. В противном случае, пожалуйста, сообщите о проблеме на https://github.com/pyca/cryptography/issues с информацией о том, как ее воспроизвести. ([])
И второй вывод это:
ValueError: длина зашифрованного текста должна быть равна размеру ключа.
Кажется, у меня нет другой работающей библиотеки, использующей OpenSSL.
Вот мои два сценария:
generate.py
##
# Generate file containing data from automates
##
import sys
import random
import json
import glob
import os
import time
import socket
import threading
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
# Generate the private and public keys once
# from cryptography.hazmat.primitives.asymmetric import rsa
# private_key = rsa.generate_private_key(
# public_exponent=65537,
# key_size=20480,
# backend=default_backend()
# )
# public_key = private_key.public_key()
#
# pem = private_key.private_bytes(
# encoding=serialization.Encoding.PEM,
# format=serialization.PrivateFormat.PKCS8,
# encryption_algorithm=serialization.NoEncryption()
# )
#
# with open('private.pem', 'wb') as f:
# f.write(pem)
#
# pem = public_key.public_bytes(
# encoding=serialization.Encoding.PEM,
# format=serialization.PublicFormat.SubjectPublicKeyInfo
# )
#
# with open('public.pem', 'wb') as f:
# f.write(pem)
with open("public.pem", "rb") as key_file:
public_key = serialization.load_pem_public_key(
key_file.read(),
backend=default_backend()
)
# Handle argument related errors, we only want 2! No more no less.
if len(sys.argv) > 3:
print("Please give max 2 arguments.")
exit()
elif len(sys.argv) < 2:
print("Please give the amount of time for the update cycle (in seconds), and the unit number.")
exit()
else:
print("Initializing...")
# Registering the passed arguments
cycle_value = float(sys.argv[1])
unit_number = int(sys.argv[2])
def encrypt_data(data):
return bytes(base64.b64encode(public_key.encrypt(
data,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)), 'utf-8')
# Get the tank weight of the previous data set
def get_last_tank_weight(id):
if not os.path.isdir('generated-data'):
os.mkdir('generated-data')
if len(glob.glob('generated-data/*.json')) == 0:
return 0
else:
list_of_files = glob.glob('generated-data/*.json')
latest_file = max(list_of_files, key=os.path.getctime)
return int(json.loads(open(latest_file, 'r').read())["params"][str(id - 1)]["tank_weight"])
# Generate random value for each automate
def generate_values(id):
tank_weight = int(round(random.uniform(3512, 4607), 0))
params = {
"temp_tank": round(random.uniform(2.5, 4), 1),
"temp_ext": round(random.uniform(8, 14), 1),
"tank_weight": tank_weight,
"finished_product_weighht": get_last_tank_weight(id) - tank_weight,
"pH_rate": round(random.uniform(6.8, 7.2), 1),
"potassium_rate": int(round(random.uniform(35, 47), 0)),
"NaCL_concentration": round(random.uniform(1.0, 1.7), 1),
"salmonella_level": int(round(random.uniform(17, 37), 0)),
"e-coli_level": int(round(random.uniform(35, 49), 0)),
"listeria_level": int(round(random.uniform(28, 54), 0))
}
return params
# Create and fill the json data file for the unit
def fill_json():
timestamp = int(time.time() * 1000)
json_output = {
"unit": unit_number,
"timestamp": timestamp,
"params": {}
}
params = {}
f_automates = open("automates.json", "r")
json_automates = json.loads(f_automates.read())[str(unit_number)]
print("Generating values...")
for automate in json_automates:
params[int(automate["num"]) - 1] = generate_values(automate["num"])
json_output["params"] = params
filename = "paramunite_" + str(unit_number) + "_" + str(timestamp) + ".json"
with open("generated-data/" + filename, "w+") as json_file:
json.dump(json_output, json_file)
print("file " + filename + " successfully created.")
print(encrypt_data(bytes(json.dumps(json_output), 'utf-8')))
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((socket.gethostname(), 25565))
# s.connect(('pyconcentrator', 25565))
s.sendall(encrypt_data(bytes(json.dumps(json_output), 'utf-8')))
# Line to make script wait for new creation
threading.Timer(cycle_value, fill_json).start()
# Launch main script!
fill_json()
concentrator.py
import socket
import json
import base64
import mysql.connector as mariadb
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
host = socket.gethostname()
port = 25565
s = socket.socket()
s.bind((host, port))
s.listen(60)
with open("private.pem", "rb") as key_file:
private_key = serialization.load_pem_private_key(
key_file.read(),
password=None,
backend=default_backend()
)
def decrypt_data(data):
return private_key.decrypt(
data,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
# Connect to MariaDB
def connect_to_db():
return mariadb.connect(
host='mariadbaubeurre', port=3306, user='root', password='beurette', database='beurre'
# host='127.0.0.1', port=3307, user='root', password='', database='test'
)
# Get the type of the automate given its id, by searching in the automates.json file
def get_automate_type(id, unit):
return json.loads(open('automates.json', 'r').read())[str(unit)][int(id)-1]["type"]
def send_to_db(data):
mariadb_connection = connect_to_db()
cursor = mariadb_connection.cursor()
i = 1
# Prepare INSERT SQL query
sql = "INSERT INTO measures (`measure_datetime`, `measure_temp_cuve`, `measure_temp_ext`, `measure_weight_milk`, `measure_weight_product`, `measure_ph`, `measure_k_plus`, `measure_nacl`, `measure_bacteria_salmonella`, `measure_bacteria_ecoli`, `measure_bacteria_listeria`, `measure_fk_automaton`) VALUES "
for y in data["params"]:
sql += "({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}),".format(
data["timestamp"],
data["params"][y]["temp_tank"],
data["params"][y]["temp_ext"],
data["params"][y]["tank_weight"],
data["params"][y]["finished_product_weight"],
data["params"][y]["pH_rate"],
data["params"][y]["potassium_rate"],
data["params"][y]["NaCL_concentration"],
data["params"][y]["salmonella_level"],
data["params"][y]["e-coli_level"],
data["params"][y]["listeria_level"],
"(SELECT automaton_id FROM automatons WHERE automaton_fk_unit = (SELECT unit_id FROM `units` WHERE unit_fk_site = 1 AND unit_num = {}) AND automaton_type LIKE '{}' AND automaton_num = {})".format(
data["unit"], get_automate_type(i, data["unit"]), i)
)
i += 1
cursor.execute(sql[:-1] + ";")
mariadb_connection.commit()
mariadb_connection.close()
def wait_for_data():
output = ""
print("Waiting for connection...")
conn, addr = s.accept()
print("Receiving from ", addr, "...")
while True:
data = conn.recv(1024)
output += decrypt_data(data).decode('utf-8')
if not data:
break
print(json.loads(output))
send_to_db(json.loads(output))
wait_for_data()
wait_for_data()
s.close()
Я застрял с этим и не могу найти способ решить это.
Я новичок в криптографии, поэтому, возможно, я не использую правильный метод шифрования или что-то в этом роде, но я немного потерян со всеми возможностями шифрования.
Спасибо !!