Помогите расшифровать строку 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

Обсуждение

payloadstring += "AAAAAAAAAA=" выглядит довольно произвольно, @Jaromanda X

Первая ошибка: int messagelength = sizeof(str_out); нет, это не длина строки. Это количество байтов для экземпляра String. Правильный способ получить длину строки — использовать функцию-член int messagelength = str_out.length();https://www.arduino.cc/en/Tutorial/StringLength., @Mikael Patel


1 ответ


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