Вставка зашифрованного текста в MySQL с использованием Python - PullRequest
1 голос
/ 15 марта 2019

Итак, у меня есть программа, которая зашифрует строку с использованием AES и сгенерирует шифр в байтах []. Я хочу сохранить этот шифр в базе данных MySQL. Я обнаружил, что мы можем использовать тип данных VARBINARY в MySQL для этого.

Какими способами мы могли бы этого достичь.

Вот моя попытка сделать это:

import ast
import mysql.connector
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes



def encrypt(key, msg):
    iv = get_random_bytes(16)
    cipher = AES.new(key, AES.MODE_CFB, iv)
    ciphertext = cipher.encrypt(msg)    # Use the right method here
    db = iv + ciphertext
    print(db)
    cursor.executemany(sql_para_query,db)
    print(cursor.fetchone())
    connection.commit()
    return iv + ciphertext


def decrypt(key, ciphertext):
    iv = ciphertext[:16]
    ciphertext = ciphertext[16:]
    cipher = AES.new(key, AES.MODE_CFB, iv)
    msg = cipher.decrypt(ciphertext)
    return msg.decode("utf-8")


if __name__ == "__main__":
    connection = mysql.connector.connect(host = "localhost", database = "test_db", user = "sann", password = "userpass",use_pure=True)
    cursor = connection.cursor(prepared = True)
    sql_para_query = """insert into test1 values(UNHEX(%s)) """
    ed = input("(e)ncrypt or (d)ecrypt: ")
    key = str(1234567899876543)
    if ed == "e":
        msg = input("message: ")
        s= encrypt(key, msg)
        print("Encrypted message: ", s)
        file = open("e_tmp","wb+")
        file.write(s)
        print(type(s))

    elif ed == "d":
        #smsg = input("encrypted message: ")
        #file = open("e_tmp","rb")
        #smsg = file.read()
        #print(type(smsg))
        sql_para_query = """select * from test1"""
        cursor.execute(sql_para_query)
        row = cursor.fetchone()
        print(row)
        #smsg = str(smsg)
        #msg = ast.literal_eval(smsg)
        #print(msg)
        #print(type(msg))
        #s=decrypt(key, msg)
        #print("Decrypted message: ", s)
        #print(type(s))

Ошибка, которую я получаю:

Traceback (последний вызов был последним): File "/Home/mr_pool/.local/lib/python3.6/site-packages/mysql/connector/cursor.py", линия 1233, в исполнении self.execute (операция, параметры) Файл "/home/mr_pool/.local/lib/python3.6/site-packages/mysql/connector/cursor.py", строка 1207, в исполнении elif len (self._prepared ['parameters'])! = len (params): TypeError: объект типа 'int' не имеет len ()

Во время обработки вышеуказанного исключения произошло другое исключение:

Traceback (последний вызов был последним): файл "tmp1.py", строка 36, в s = encrypt (key, msg) Файл "tmp1.py", строка 14, в зашифрованном виде cursor.executemany (sql_para_query, db) Файл "/home/mr_pool/.local/lib/python3.6/site-packages/mysql/connector/cursor.py", линия 1239, в исполнении "Не удалось выполнить операцию; {error}". Format (error = err)) mysql.connector.errors.InterfaceError: Не удалось выполнить операцию; объект типа 'int' не имеет len ()

Любые другие альтернативы также приветствуются.

Моя конечная цель - сохранить зашифрованный текст в базе данных.

1 Ответ

0 голосов
/ 17 марта 2019

Я воспроизвел вашу ошибку, но, похоже, в вашем коде больше ошибок.Ключ и сообщение являются строками, поэтому я получил эту ошибку:

TypeError: Object type <class 'str'> cannot be passed to C code

, которую я исправил, кодировав их в utf-8:

# line 38:
key = str(1234567899876543).encode("utf8")
# .... line 41:
s= encrypt(key, msg.encode("utf8"))

Функция UNHEX в вашемSQL-запрос не нужен, потому что мы вводим данные как VARBINARY.Вы можете изменить свой оператор на:

"""insert into test1 values(%s) """

Функция executemany () может быть заменена execute (), потому что вы вводите только один оператор.Однако я напишу решение для использования обоих: execute или executemany.

insert with execute ():

Из документации:

cursor.execute (операция, params = None, multi = False)

iterator = cursor.execute (операция, params = None, multi = True)

Этот метод выполняет данную операцию базы данных(запрос или команда).Параметры , найденные в кортеже или словаре, параметры связаны с переменными в операции.Укажите переменные, используя стиль параметра% s или% (name) s (то есть, используя формат или стиль pyformat).execute () возвращает итератор, если multi равно True.https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html

Итак, нам нужно просто создать кортеж с вашими параметрами, изменив строку cursor.execute на:

cursor.execute(sql_para_query, (db, ))

insert with executemany ():

Из документации:

cursor.executemany (операция, seq_of_params) Этот метод подготавливает операцию базы данных (запрос или команду) и выполняет ее для всех последовательностей параметров или отображений найдено в последовательности seq_of_params .https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-executemany.html

Поэтому нам нужно построить последовательность со значениями, которые вы хотите вставить.В вашем случае только одно значение:

 cursor.executemany(sql_para_query, [(db, )])

Чтобы вставить несколько значений, вы можете добавить в свою последовательность столько кортежей, сколько хотите.

полный код:

import ast
import mysql.connector
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

def encrypt(key, msg):
    iv = get_random_bytes(16)
    cipher = AES.new(key, AES.MODE_CFB, iv)
    ciphertext = cipher.encrypt(msg)    # Use the right method here
    db = iv + ciphertext
    cursor.execute(sql_para_query, (db, ))
    connection.commit()
    return iv + ciphertext


def decrypt(key, ciphertext):
    iv = ciphertext[:16]
    ciphertext = ciphertext[16:]
    cipher = AES.new(key, AES.MODE_CFB, iv)
    msg = cipher.decrypt(ciphertext)
    return msg.decode("utf-8")


if __name__ == "__main__":
    connection = mysql.connector.connect(host = "localhost", database = "test_db", user = "sann", password = "userpass",use_pure=True)
    cursor = connection.cursor(prepared = True)
    sql_para_query = """insert into test1 values(%s) """
    ed = input("(e)ncrypt or (d)ecrypt: ")
    key = str(1234567899876543).encode("utf8")
    if ed == "e":
        msg = input("message: ")
        s= encrypt(key, msg.encode("utf8"))
        print("Encrypted message: ", s)
        file = open("e_tmp","wb+")
        file.write(s)
        print(type(s))

    elif ed == "d":
        sql_para_query = """select * from test1"""
        cursor.execute(sql_para_query)
        row = cursor.fetchone()
        msg = row[0] # row is a tuple, therefore get first element of it
        print("Unencrypted message: ", msg)
        s=decrypt(key, msg)
        print("Decrypted message: ", s)

выход:

#encrypt:
(e)ncrypt or (d)ecrypt: e
message: this is my test message !!
Encrypted message:  b"\x8f\xdd\xe6f\xb1\x8e\xb51\xc1'\x9d\xbf\xb5\xe1\xc7\x87\x99\x0e\xd4\xb2\x06;g\x85\xc4\xc1\xd2\x07\xb5\xc53x\xb9\xbc\x03+\xa2\x95\r4\xd1*"
<class 'bytes'>
#decrypt:
(e)ncrypt or (d)ecrypt: d
Unencrypted message:  bytearray(b"\x8f\xdd\xe6f\xb1\x8e\xb51\xc1\'\x9d\xbf\xb5\xe1\xc7\x87\x99\x0e\xd4\xb2\x06;g\x85\xc4\xc1\xd2\x07\xb5\xc53x\xb9\xbc\x03+\xa2\x95\r4\xd1*")
Decrypted message:  this is my test message !!
...