Как использовать хранимую процедуру MySQL, которая генерирует случайный ключ длиной 8 символов для повторного шифрования данных при каждом входе пользователя в систему - PullRequest
1 голос
/ 20 января 2020

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

В моем конкретном случае я повторно шифрую данные идентификаторы ответов (помощь), используя эту фразу-пароль в сочетании с AES. Чтобы повторно зашифровать данные, которые уже хранятся в зашифрованном виде в моей базе данных, пользователь предоставляет свой пароль для расшифровки значения длиной в 8 символов, которое уже было сохранено в базе данных. Другими словами, пароль используется для расшифровки старого ключа шифрования, поэтому этот ключ может использоваться для расшифровки идентификатора ответа на вопрос, за который проголосовал пользователь. Затем процедура генерирует новый ключ длиной 8 символов для повторного шифрования этих идентификаторов ответов каждый раз, когда пользователь успешно вошел в систему.

К сожалению, когда я проверяю свою процедуру и проверяю таблицу «голосования» Я получаю NULL в качестве нового зашифрованного идентификатора ответа. Я предпринял много попыток исправить эту ошибку, и, возможно, это связано с семантикой, но я до сих пор не смог ее решить, и мне очень трудно понять, что пошло не так. Процедура входа в систему вызывает другую процедуру, которая отвечает за извлечение и дешифрование уже зашифрованных идентификаторов ответов, поэтому она использует while-l oop, который вставляет данные во временную таблицу. Не могли бы вы, ребята, помочь мне?

На мой взгляд, это немного продвинутая процедура, возможно, слишком продвинутая для моих целей. Вот почему я предоставил некоторые комментарии, которые проведут вас через все выполняемые шаги. Это мой код:

процедура LoginUser

--------------------
-- LoginUser --
-- uname is stored encrypted by passwordhash, 
-- pw is stored encrypted by unamehash, 
-- key is encrypted by passwordhash, 
-- aid is encrypted by key 
--------------------
DROP PROCEDURE IF EXISTS LoginUser;
DELIMITER //
CREATE PROCEDURE LoginUser(IN uname CHAR(64), IN pw CHAR(64))
BEGIN
-- declare variables
DECLARE validUser, validLogin, validCombination BOOLEAN default 0;
DECLARE encryptedUsername, oldEncryptedKey, newEncryptedKey, encryptedPassword VARBINARY(32);
DECLARE plainOldKey, plainNewKey CHAR(8);

-- set encrypted username
SET encryptedUsername = (SELECT AES_ENCRYPT(uname,SHA2(pw,256)));
-- check if username exists - returns 1 for true, 0 for false
SET validUser = (SELECT EXISTS(SELECT username FROM user WHERE username = encryptedUsername));

-- logic when valid user
IF (validUser = 1) THEN

    -- get pkey from user
    SET oldEncryptedKey = (SELECT pkey FROM user WHERE username = encryptedUsername);
    -- decrypt pkey using passwordhash
    SET plainOldKey = (SELECT AES_DECRYPT(oldEncryptedKey, SHA2(pw,256)));
    -- encrypt pw using plainOldKey
    SET encryptedPassword = (SELECT AES_ENCRYPT(pw,SHA2(uname,256)));
    -- check combination
    SET validCombination = (SELECT EXISTS(SELECT * FROM user WHERE username = encryptedUsername AND `password` = encryptedPassword));

    -- logic when valid combination
    IF(validCombination = 1) THEN
        -- set valid login to true
        SET validLogin = 1;
        -- generate a plainNewKey
        SET plainNewKey = (SELECT SUBSTRING(MD5(RAND()) FROM 1 FOR 8));
        -- set new encrypted key
        SET newEncryptedKey = (SELECT AES_ENCRYPT(plainNewKey,SHA2(pw,256)));
        -- call procedure to re-encrypt answer ids.
        CALL EncryptAidsAgain(plainOldKey,plainNewKey,encryptedUsername);

        -- update pkey from user table by newKey
        UPDATE user SET pkey = newEncryptedKey WHERE username = encryptedUsername;

    END IF;

END IF;

SELECT validLogin;

END //
DELIMITER ;

процедура EncryptAidsAgain

DROP PROCEDURE IF EXISTS EncryptAidsAgain;
DELIMITER //
CREATE PROCEDURE EncryptAidsAgain(IN oldKeyValue CHAR(8), IN newKeyValue CHAR(8), IN encryptedUsername VARBINARY(32))
BEGIN

DECLARE i, answered INT DEFAULT 0;
DECLARE encryptedAid, newEncryptedAid VARBINARY(32);
DECLARE plainAid CHAR(7);

-- create temporary table to store aids
CREATE TEMPORARY TABLE aids(oldEncryptedAid VARBINARY(32));

-- get amount of given answers
SET answered = (SELECT COUNT(*) FROM vote WHERE username = encryptedUsername);

-- perform while loop
WHILE i < answered DO
    -- insert single aid in temporary table aids
    INSERT INTO aids (oldEncryptedAid) SELECT aid FROM vote WHERE username = encryptedUsername LIMIT i, 1;
    -- retrieve stored aid from aids
    SET encryptedAid = (SELECT oldEncryptedAid FROM aids LIMIT i, 1);
    -- decrypt stored aid from aids using oldKeyValue
    SET plainAid = (SELECT AES_DECRYPT(encryptedAid, SHA2(oldKeyValue,256)));
    -- set new encrypted aid
    SET newEncryptedAid = (SELECT AES_ENCRYPT(plainAid,SHA2(newKeyValue,256)));
    -- update table vote (aid)
    UPDATE vote SET aid = newEncryptedAid WHERE username = encryptedUsername AND aid = encryptedAid;
    -- increase i
    SET i = i + 1;
END WHILE;

DROP TABLE aids;

END //
DELIMITER ;

результаты теста

При многократном вызове процедуры LoginUser каждый раз, когда ключ хорошо обновляется:

mysql> select * from user;
+------------------+------------------+------------------+------------------------------------------------------------------+
| username         | password         | pkey             | ip                                                               |
+------------------+------------------+------------------+------------------------------------------------------------------+
| EÞ¯k·\â¥çJ¤EÃîP  | EÞ¯k·\â¥çJ¤EÃîP  | 6░ÛõaǪhpK║ÔäV   | 26b92be7c4ad202f842d1755c3db56f25b39c54c51cc56642b8f14ba4bda793d |
+------------------+------------------+------------------+------------------------------------------------------------------+
4 rows in set (0.00 sec)

mysql> call LoginUser("test4","test4");
+------------+
| validLogin |
+------------+
|          1 |
+------------+
1 row in set (0.02 sec)

Query OK, 0 rows affected (0.02 sec)

mysql> select * from user;
+------------------+------------------+------------------+------------------------------------------------------------------+
| username         | password         | pkey             | ip                                                               |
+------------------+------------------+------------------+------------------------------------------------------------------+
| EÞ¯k·\â¥çJ¤EÃîP  | EÞ¯k·\â¥çJ¤EÃîP  | ┴O¥╝Îìöãñ#='¹    | 26b92be7c4ad202f842d1755c3db56f25b39c54c51cc56642b8f14ba4bda793d |
+------------------+------------------+------------------+------------------------------------------------------------------+
4 rows in set (0.00 sec)

Но когда я захожу в систему несколько раз, новые зашифрованные идентификаторы ответов go NULL

mysql> select * from vote;
+-----+------------------+------+------------------+
| vid | username         | qid  | aid              |
+-----+------------------+------+------------------+
|   3 | EÞ¯k·\â¥çJ¤EÃîP |    2 | ðlözaò3OîÙW▓B═Ï |
|   4 | EÞ¯k·\â¥çJ¤EÃîP |    1 | z)ı╝├║%~╝V&7@"─V |
+-----+------------------+------+------------------+
2 rows in set (0.00 sec)


mysql> call LoginUser("test4","test4");
+------------+
| validLogin |
+------------+
|          1 |
+------------+
1 row in set (0.03 sec)

Query OK, 0 rows affected (0.03 sec)

mysql> select * from vote;
+-----+------------------+------+------+
| vid | username         | qid  | aid  |
+-----+------------------+------+------+
|   3 | EÞ¯k·\â¥çJ¤EÃîP |    2 | NULL |
|   4 | EÞ¯k·\â¥çJ¤EÃîP |    1 | NULL |
+-----+------------------+------+------+
2 rows in set (0.00 sec)

Большое спасибо заранее, если у вас есть какие-либо советы по улучшению политики шифрования, они очень приветствуются!

...