1

So I have been recently been trying to create a library for Arduino to encode and decode JSON Web tokens(JWT) using HMAC-SHA256.

For those unfamiliar, JWT has 3 parts - The header, body and signature. The header and body are in JSON format.
The header contains the hashing algorithm and token type while The body contains the data to be transmitted.
The header and body are converted to base64 format and arranged as "[header].[body]". The signature is created by running the hashing algorithm (HMAC-SHA256 in my case) on the "[header].[body]" and converting the result to base64 format.
Finally, the token is arranged as "[header].[body].[signature]"
More information can be found on - https://jwt.io/introduction

So far, I successfully managed to create the encoding part. I wanted to test the code for consistency, so I tried to run the code on an Arduino UNO and kept on calling the encoding function in void loop. Initially, the results were as expected -
enter image description here

The long line of text is the expected output. But suddenly, it does this -
enter image description here

Then there is a period where the output is blank and finally, this comes-
enter image description here

For some reason, only the signature part gets printed. Also, I have no idea what the last 2 outputs are. Finally, it goes blank for a second and then repeats the entire process
Can anyone please help me in figuring out what is going on and how do I solve it?

This is my code in the library- 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;
}

This is the code on the 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);
}

I have used the SHA256 library that I found in this link with some minor modifications as mentioned here HMAC SHA256 in Arduino use case? so that it can compile: https://github.com/Cathedrow/Cryptosuite

Any help will be appreciated.

7
  • Is the Serial tx buffer overrunning? Try if (Serial.availableForWrite() >= sizeof(jwt.out)) Serial.println(jwt.out);
    – tim
    Jun 29 at 11:33
  • Nope. Didn't work.
    – Flight64
    Jun 29 at 13:16
  • Could it be a memory related issue? Cause the behavior is consistent irrespective the delay() used.
    – Flight64
    Jun 29 at 14:12
  • 3
    It could be your temp variable causing your heap to turn into swiss cheese. You should re-factor that to use a static buffer.
    – Majenko
    Jun 29 at 16:00
  • Yeah, that is possible. I was just writing the JWT decoding script. It worked fine until I got strings involved after which it started showing similar problems. I think I need to rewrite the code to not use strings.
    – Flight64
    Jun 29 at 17:39
1

As @Majenko had pointed out in the comments, it was temp variable causing the problem. Or rather, strings in general seem to have a bad effect on the memory of the Arduino UNO. After I rewrote the code without using any strings at all, the problem was fixed and the program gave a consistent output.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.