Помогите расшифровать строку AES из модуля arduino rf в python
Прошу прощения за грубые ошибки в моем коде, я новичок и в C, и в Python.
Я пытаюсь отправить зашифрованное сообщение с моего arduino uno через датчик DHT22 и радиочастотный модуль, используя библиотеки radiohead ask и AESlib, на raspberry pi с USB RTL-SDR, используя библиотеку rtl_433 и скрипт python.
Я думаю (хотя вполне могу ошибаться), что сторона Arduino работает правильно, и мне кажется, что я довольно близок к стороне Python, однако, похоже, я не расшифровываю сообщение должным образом.
Примером строки до шифрования может быть:
"55,55,24,99,0001"
Вот код на стороне Arduino:
#include <AESLib.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "DHT.h"
#include <RH_ASK.h>
#include <Base64.h>
#define DHTPIN 2
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);
RH_ASK driver;
bool takeSensorReading = true;
float h;
float t;
String str_humid;
String str_temp;
String str_out;
uint8_t key[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
char data[32];
char endChar[1] = "Ʊ";
void setup() {
driver.init();
dht.begin();
Serial.begin(9600);
}
void loop() {
delay(5000);
int messagelength = sizeof(str_out);
byte plain[messagelength];
h = dht.readHumidity();
// Чтение температуры в градусах Цельсия
t = dht.readTemperature();
// Преобразование влажности в строку
str_humid = String(h, 2);
// Преобразование температуры в строку
str_temp = String(t, 2);
// Объединить влажность и температуру
str_out = str_humid + "," + str_temp + ",0001";
str_out.toCharArray(data, 32);
aes256_enc_single(key, data);
/*aes256_dec_single(key, data);*/
Serial.println(data);
int encryptedStringLength = sizeof(data);
int encodedLength = Base64.encodedLength(encryptedStringLength);
char encodedString[encodedLength];
Base64.encode(encodedString, data, encryptedStringLength);
Serial.print("Encoded string is:\t");
Serial.println(encodedString);
driver.send(strcat( (uint8_t *)encodedString, endChar ), 33);
driver.waitPacketSent();
takeSensorReading = !takeSensorReading;
}
а вот код Python:
import subprocess
import json
import base64
from Crypto.Cipher import AES
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[0:-ord(s[-1])]
def print_no_newline(string):
import sys
sys.stdout.write(string)
sys.stdout.flush()
def decrypt(enc):
private_key = str(bytearray([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]))
iv = enc[:16]
cipher = AES.new(private_key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(enc[16:]))
p = subprocess.Popen(['rtl_433', '-f', '433720000', '-F', 'json'],stdout=subprocess.PIPE,bufsize=1)
# rtl_433 -f 433720000 -F json
try:
for line in iter(p.stdout.readline, ""):
lineStripped = str(line).strip()
try:
jsondata = json.loads(lineStripped)
time = jsondata["time"]
payload = jsondata["payload"]
if len(payload) == 33:
payloadstring = ''
for a in range(len(payload)):
payloadstring += chr(payload[a])
payloadstring += "AAAAAAAAAA="
print payloadstring
encrypted = base64.b64decode(payloadstring)
print encrypted
decrypted = decrypt(encrypted)
print decrypted
except Exception as err:
print "oh no, something went wrong"
print("error: {0}".format(err))
except KeyboardInterrupt:
p.kill()
p.wait()
p.stdout.close()
Вот пример ошибочного вывода функции расшифровки:
"@g���6S���25zD”
Буду очень признателен за любую помощь, которую вы могли бы мне оказать в расшифровке сообщения от Arduino в скрипте Python.
Спасибо
Ричард
*ИЗМЕНИТЬ
Я подумал, что если это поможет, я мог бы предоставить немного больше информации об этапах передачи, через которые проходит сообщение:
После создания исходной строки данных датчика температуры и влажности, например "55.55,24.99,0001", это 16-байтовое сообщение добавляется к 32-байтовому массиву символов и шифруется с использованием метода aes128_enc_single. Затем зашифрованное сообщение кодируется base63. Зашифрованный массив символов затем объединяется с дополнительным незашифрованным символом «Ʊ» (который, как я думал, я мог бы использовать для грубой проверки сообщения) и отправляется с помощью метода отправки запроса Radiohead:
driver.send(strcat( (uint8_t *)encodedString, endChar ), 33);
На стороне pyhton/получателя я запускаю подпроцесс rtl_433 -f 433720000 -F json
и слушайте вывод построчно. Пример вывода команды rtl_433 будет выглядеть примерно так:
{"time": "2019-03-05 00:00:00", "model": "RadioHead ASK", "len": 33, "to": 255, "from": 255, "id ": 0, "флаги": 0, "полезная нагрузка": [111, 110, 109, 57, 120, 86, 52, 79, 121, 78, 71, 52, 48, 122, 117, 88, 67, 52 , 77, 118, 85, 81, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65], "микрофон": "CRC"}
rtl_433 преобразует сообщение в массив символов ASCII или Unicode.
Затем я попытался преобразовать символы в полученном массиве обратно в стандартные символы:
полезная строка += chr(полезная нагрузка[a])
добавлено дополнение к сообщению:
полезная строка += "AAAAAAAAAA="
затем base64 декодировал результат:
зашифровано = base64.b64decode(строка полезной нагрузки)
а затем, наконец, расшифровать это:
расшифровано = расшифровано(зашифровано)
Надеюсь, эта информация может быть полезна для выявления моих ошибок.
1 ответ
Только осмотр:
Вы используете вектор инициализации и режим CBC в коде Python, но не используете IV и одноблочное шифрование в коде Arduino.
Я думаю, что если вы используете MODE_ECB в своем Python, он будет игнорировать IV и соответствовать коду Arduino.
Глядя на AESlib github, ваш ключ должен быть ровно 16 байт - у вас 32. Я не смотрел код, чтобы увидеть, будет ли он просто игнорировать остальные, но код Python определенно не будет, поэтому вам, вероятно, следует делать то, что он говорит, и использовать 16, и настроить свой код Python, чтобы он соответствовал .
Поскольку вышеуказанного было недостаточно, чтобы заставить его работать, я бы предложил разделять и властвовать: используйте онлайн-шифратор/дешифратор AES-128, такой как aesencryption.net или encode-decode.com или infoencrypt.com для проверки и перекрестной проверки ваших функций шифрования Arduino и дешифрования Python. Если повезет, вы сможете по крайней мере исправить их один за другим по заведомо исправному эталону. Возможно, немного повозившись, вы сможете понять, где что-то идет не так.
Я предполагаю, что значение влажности может не сильно измениться, и у меня есть ощущение, что отправка нескольких сообщений с одним и тем же началом может существенно ослабить шифрование, но я не эксперт по криптографии, и, возможно, этого достаточно для ваших целей.
Привет, Марк! Большое спасибо, что нашли время помочь. Я попытался реализовать ваши предложения, изменив ключ uint8_t, чтобы он имел только 16 значений, и вызвал aes128_enc_single вместо aes_256_enc_single. На стороне Python я удалил iv, уменьшил длину private_key до 16 и изменил режим AES на AES.MODE_ECB. К сожалению, я все еще не могу правильно расшифровать сообщение. Я отредактировал свой исходный пост, включив в него некоторый контекст, касающийся этапов, через которые проходит сообщение в пути, и я надеюсь, что это поможет пролить свет на то, где я ошибаюсь. еще раз спасибо, @richardtriestodoarduino
Эй, большое спасибо за ссылки ... [encode-decode.com](https://encode-decode.com/aes128-encrypt-online/) действительно подкинул кое-что интересное.
Если я использую строку HelloIamamessage
и секрет abcdefghijklmnop
и устанавливаю соответствующие значения в сценарии Arduino uint8_t string_key[] = {97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112};
и Строка test_message = "HelloIamamessage";
Я получаю следующий вывод с сайта:
k7yooB6Mj6bgxJ2ywaZj0rRDy5XLQ8VcZMRo2jfU2Ok=
и следующее из Arduino IDE:
k7yooB6Mj6bgxJ2ywaZj0gAAAAAAAAAAAAAAAAAAAAAAAAAA=, @richardtriestodoarduino
Выходные данные начинаются одинаково, но затем расходятся. Может ли это быть проблемой заполнения (или ее отсутствия на стороне Arduino), и если да, то есть ли у вас какие-либо идеи, как это решить?, @richardtriestodoarduino
Возможно, я понял, что происходит не так. Измените свое сообщение на "HelloIamamessag"
(т.е. 15 символов) и посмотрите, совпадает ли оно. Если да, я отредактирую ответ и объясню почему., @Mark Smith
Эй, Марк, спасибо, что взглянул еще раз. Я изменил сообщение на HelloIamamessag
, к сожалению, я все еще не могу получить зашифрованную строку, совпадающую с кодировкой-декодированием.
Возможно, я сделал простую ошибку. [Вот pastebin](https://pastebin.com/EN3Yy0Kb) с моей последней попыткой (если это когда-нибудь сработает, я отредактирую вопрос и опубликую там рабочий код).
Arduino IDE возвращается:
0P3iW9FSrni+evrhrWaiMQ==
и [encode-decode](https://encode-decode.com/aes128-encrypt-online/) возвращает:
bs3Uzmhox9ARIPliQRxawQ==
Оба используют строку «HelloIamamessag»., @richardtriestodoarduino
- Последовательная связь Arduino с Python: отправка массива
- Отправьте несколько значений int из Python в Arduino, используя pySerial
- Сброс последовательного порта Arduino в последовательном мониторе и Python
- Код для 2 ультразвуковых датчиков
- Последовательная связь между python и arduino
- Динамически обновить масштаб виджета Tkinter из портов Arduino с помощью python и firmata
- Связь между Arduino и python: последовательный порт отправляет пустые данные
- Почему нужно использовать latin-1 вместо utf-8 при использовании python с arduino?
payloadstring += "AAAAAAAAAA="
выглядит довольно произвольно, @Jaromanda XПервая ошибка:
int messagelength = sizeof(str_out);
нет, это не длина строки. Это количество байтов для экземпляра String. Правильный способ получить длину строки — использовать функцию-членint messagelength = str_out.length();
https://www.arduino.cc/en/Tutorial/StringLength., @Mikael Patel