Пользовательская библиотека для Arduino для кодирования и декодирования веб-токенов JSON
Поэтому я недавно пытался создать библиотеку для Arduino для кодирования и декодирования веб-токенов JSON(JWT) с использованием HMAC-SHA256.
Для тех, кто не знаком, JWT состоит из 3 частей - заголовка, тела и подписи. Заголовок и тело в формате JSON.
Заголовок содержит алгоритм хэширования и тип токена, в то время как тело содержит данные, подлежащие передаче.
Заголовок и текст преобразуются в формат base64 и упорядочиваются как "[заголовок].[тело]". Подпись создается путем запуска алгоритма хеширования (в моем случае HMAC-SHA256) в "[заголовке].[тело]" и преобразование результата в формат base64.
Наконец, токен расположен в виде "[заголовок].[тело].[подпись]"
Более подробную информацию можно найти на - https://jwt.io/introduction
До сих пор мне успешно удавалось создавать кодирующую часть. Я хотел проверить код на согласованность, поэтому попытался запустить код на Arduino UNO и продолжал вызывать функцию кодирования в цикле void. Первоначально результаты были такими, как и ожидалось -
Длинная строка текста - это ожидаемый результат. Но внезапно он делает это -
Затем наступает период, когда вывод остается пустым, и, наконец, это происходит-
По какой-то причине печатается только часть подписи. Кроме того, я понятия не имею, каковы последние 2 вывода. Наконец, он на секунду гаснет, а затем повторяет весь процесс
Может ли кто-нибудь, пожалуйста, помочь мне понять, что происходит и как мне это решить?
Это мой код в библиотеке - custom_jwt.h
#ifndef _CUSTOM_JWT_H_
#define _CUSTOM_JWT_H_
#include <Arduino.h>
class CustomJWT{
private:
char* secretKey;
public:
char* header;
char* payload;
char* signature;
String out;
CustomJWT(char* secret);
char* getSecret();
void changeSecret(char* secret);
void encodeJWT(char* string);
void decodeJWT(char* string);
};
#endif //_CUSTOM_JWT_H_
custom_jwt.cpp
#include "custom_jwt.h"
#include "sha256.h"
#include <Arduino.h>
const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char head[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
void decodeblock(unsigned char in[], char *clrstr) {
unsigned char out[4];
out[0] = in[0] << 2 | in[1] >> 4;
out[1] = in[1] << 4 | in[2] >> 2;
out[2] = in[2] << 6 | in[3] >> 0;
out[3] = '\0';
strncat(clrstr, reinterpret_cast<const char *>(out), sizeof(out));
}
void b64_decode(char *b64src, char *clrdst)
{
int c, phase, i;
unsigned char in[4];
char *p;
clrdst[0] = '\0';
phase = 0; i=0;
while(b64src[i]) {
c = (int) b64src[i];
if(c == '=') {
decodeblock(in, clrdst);
break;
}
p = strchr(b64, c);
if(p) {
in[phase] = p - b64;
phase = (phase + 1) % 4;
if(phase == 0) {
decodeblock(in, clrdst);
in[0]=in[1]=in[2]=in[3]=0;
}
}
i++;
}
}
void encodeblock( unsigned char in[], char b64str[], int len ) {
unsigned char out[5];
out[0] = b64[ in[0] >> 2 ];
out[1] = b64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
out[2] = (unsigned char) (len > 1 ? b64[ ((in[1] & 0x0f) << 2) |
((in[2] & 0xc0) >> 6) ] : '=');
out[3] = (unsigned char) (len > 2 ? b64[ in[2] & 0x3f ] : '=');
out[4] = '\0';
strncat(b64str, reinterpret_cast<const char *>(out), sizeof(out));
}
void b64_encode(char *clrstr, char *b64dst) {
unsigned char in[3];
int i, len = 0;
int j = 0;
b64dst[0] = '\0';
while(clrstr[j]) {
len = 0;
for(i=0; i<3; i++) {
in[i] = (unsigned char) clrstr[j];
if(clrstr[j]) {
len++; j++;
}
else in[i] = 0;
}
if( len ) {
encodeblock( in, b64dst, len );
}
}
}
void b64_encode(unsigned char *clrstr, char *b64dst)
{
unsigned char in[3];
int i, len = 0;
int j = 0;
b64dst[0] = '\0';
while(j < 32) {
len = 0;
for(i=0; i<3; i++) {
in[i] = clrstr[j];
if(clrstr[j] && j < 32) {
len++; j++;
}
else in[i] = 0;
}
if( len ) {
encodeblock( in, b64dst, len );
}
}
}
CustomJWT::CustomJWT(char *secret)
{
CustomJWT::secretKey = secret;
}
char * CustomJWT::getSecret()
{
return CustomJWT::secretKey;
}
void CustomJWT::changeSecret(char *secret)
{
CustomJWT::secretKey = secret;
}
void CustomJWT::encodeJWT(char *string)
{
//Create header and body
int len = (strlen(string) + 2)/3*4;
char str[len];
b64_encode(string, str);
while(str[strlen(str) - 1] == '=')
str[strlen(str) - 1] = '\0';
String temp = head;
temp = temp + ".";
temp = temp + str;
//Convert passkey to unsigned int
char* msg1 = CustomJWT::secretKey;
size_t length = strlen(msg1 + 1);
char* beg = msg1;
char* end = msg1 + length + 1;
uint8_t* key = new uint8_t[length + 1];
size_t i = 0;
for (; beg != end; ++beg, ++i)
{
key[i] = (uint8_t)(*beg);
}
//Initialise HMAC
Sha256.initHmac(key, length + 1);
//Convert string to char array
char temp1[temp.length() + 10];
temp.toCharArray(temp1, temp.length() + 10);
//Obtain result
Sha256.print(temp1);
uint8_t* hash = Sha256.resultHmac();
//Encode to b64
len = ((32 + 2)/3)*4;
char str1[len];
b64_encode(hash, str1);
while(str1[strlen(str1) - 1] == '=')
str1[strlen(str1) - 1] = '\0';
temp = temp + ".";
temp = temp + str1;
CustomJWT::out = temp;
}
Это код на Arduino:
#include <custom_jwt.h>
int i;
char key[] = "tester";
char string[] = "{\"temp\":22.5,\"speed\":25.1}";
CustomJWT jwt(key);
void setup()
{
Serial.begin(115200);
}
void loop()
{
jwt.encodeJWT(string);
Serial.println(jwt.out);
}
Я использовал библиотеку SHA256, которую нашел по этой ссылке, с некоторыми незначительными изменениями, как указано здесь, HMAC SHA256 в случае использования Arduino? чтобы он мог компилироваться: https://github.com/Cathedrow/Cryptosuite
Любая помощь будет оценена по достоинству.
@Flight64, 👍1
Обсуждение1 ответ
Лучший ответ:
Как отметил @Majenko в комментариях, проблема возникла из-за временной переменной. Или, скорее, строки в целом, похоже, плохо влияют на память Arduino UNO. После того, как я переписал код без использования каких-либо строк вообще, проблема была устранена, и программа выдала последовательный вывод.
- Как подключить Wi-Fi Shield ESP-12E-ESP8266-UART-WIFI-Wireless-Shield к Arduino
- Глобальные переменные занимают много места в динамической памяти.
- Статус выхода 1 ожидаемое первичное выражение перед ']' Arduino
- Получение всех данных моего объекта JSON из Serial.read() сразу
- Невозможно использовать библиотеку клавиатуры с Arduino UNO даже после смены прошивки.
- Ошибка: "'lcd' does not name a type" при использовании библиотеки LiquidCrystal.
- Последовательная связь от Arduino до ESP8266 NodeMCU работает, но от NodeMCU до Arduino не работает
- Могу ли я запретить библиотеке Stepper удерживать двигатель?
Переполняется ли последовательный буфер tx? Попробуйте
если (Serial.availableForWrite() >= sizeof(jwt.out)) Serial.println(jwt.out);
, @timНет. Не сработало., @Flight64
Может быть, это проблема, связанная с памятью? Причина, по которой поведение соответствует независимо от используемой функции delay ()., @Flight64
Это может быть ваша переменная "temp", из-за которой ваша куча превратится в швейцарский сыр. Вам следует пересмотреть это, чтобы использовать статический буфер., @Majenko
Да, это возможно. Я как раз писал сценарий декодирования JWT. Это работало нормально до тех пор, пока я не подключил струны, после чего у него начались аналогичные проблемы. Я думаю, что мне нужно переписать код, чтобы не использовать строки., @Flight64
Не связаны, но "JWT" означает веб-токены JSON., @Dave Newton
Отмеченный. Я просто это исправлю. Спасибо., @Flight64