Python шифрует данные через сокеты - PullRequest
0 голосов
/ 28 июня 2019

В настоящее время я разрабатываю приложение 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()

Я застрял с этим и не могу найти способ решить это. Я новичок в криптографии, поэтому, возможно, я не использую правильный метод шифрования или что-то в этом роде, но я немного потерян со всеми возможностями шифрования.

Спасибо !!

...