use SDK provided encoder, rather than pulling in library

This commit is contained in:
Rick Watson 2019-05-11 15:11:11 +01:00
parent a4220d631d
commit e63a8c4b75
5 changed files with 63 additions and 241 deletions

View File

@ -14,7 +14,7 @@ void ArduinoJsonJWT::setSecret(String secret){
* No need to pull in additional crypto libraries - lets use what we already have.
*/
String ArduinoJsonJWT::sign(String &payload) {
unsigned char hmacResult[32];
unsigned char hmacResult[33];
{
#if defined(ESP_PLATFORM)
mbedtls_md_context_t ctx;
@ -34,43 +34,15 @@ String ArduinoJsonJWT::sign(String &payload) {
br_hmac_out(&hmacCtx, hmacResult);
#endif
}
return encode(hmacResult, 32);
}
String ArduinoJsonJWT::decode(unsigned char * value) {
// create buffer of approperate length
size_t decodedLength = decode_base64_length(value) + 1;
char decoded[decodedLength];
// decode
decode_base64(value, (unsigned char *) decoded);
decoded[decodedLength-1] = 0;
// return as arduino string
return String(decoded);
}
String ArduinoJsonJWT::encode(unsigned char * value , int length) {
int encodedIndex = encode_base64_length(length);
// encode
char encoded[encodedIndex];
encode_base64(value, length, (unsigned char *) encoded);
// trim padding
while (encoded[--encodedIndex] == '=') {
encoded[encodedIndex] = 0;
}
// return as string
return String(encoded);
hmacResult[32] = 0;
return encode(String((char *) hmacResult));
}
String ArduinoJsonJWT::buildJWT(JsonObject &payload) {
// serialize, then encode payload
String jwt;
serializeJson(payload, jwt);
jwt = encode((unsigned char *) jwt.c_str(), jwt.length());
jwt = encode(jwt);
// add the header to payload
jwt = JWT_HEADER + '.' + jwt;
@ -108,7 +80,7 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument &jsonDocument) {
// decode payload
jwt = jwt.substring(JWT_HEADER_SIZE + 1);
jwt = decode((unsigned char *) jwt.c_str());
jwt = decode(jwt);
// parse payload, clearing json document after failure
DeserializationError error = deserializeJson(jsonDocument, jwt);
@ -116,3 +88,52 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument &jsonDocument) {
jsonDocument.clear();
}
}
String ArduinoJsonJWT::encode(String value) {
// prepare encoder
base64_encodestate _state;
#if defined(ESP8266)
base64_init_encodestate_nonewlines(&_state);
size_t encodedLength = base64_encode_expected_len_nonewlines(value.length()) + 1;
#elif defined(ESP_PLATFORM)
base64_init_encodestate(&_state);
size_t encodedLength = base64_encode_expected_len(value.length()) + 1;
#endif
// prepare buffer of correct length
char buffer[encodedLength];
// encode to buffer
int len = base64_encode_block(value.c_str(), value.length(), &buffer[0], &_state);
len += base64_encode_blockend(&buffer[len], &_state);
buffer[len] = 0;
// convert to arduino string
value = String(buffer);
// remove padding and convert to URL safe form
while (value.charAt(value.length() - 1) == '='){
value.remove(value.length() - 1);
}
value.replace('+', '-');
value.replace('/', '_');
// return as string
return value;
}
String ArduinoJsonJWT::decode(String value) {
// convert to standard base64
value.replace('-', '+');
value.replace( '_', '/');
// prepare buffer of correct length
char buffer[base64_decode_expected_len(value.length()) + 1];
// decode
int len = base64_decode_chars(value.c_str(), value.length(), &buffer[0]);
buffer[len] = 0;
// return as string
return String(buffer);
}

View File

@ -1,11 +1,10 @@
#ifndef ArduinoJsonJWT_H
#define ArduinoJsonJWT_H
#include "base64.h"
#include <Arduino.h>
#include <ArduinoJson.h>
#include <libb64/cdecode.h>
#include <libb64/cencode.h>
#if defined(ESP_PLATFORM)
#include <mbedtls/md.h>
#else
@ -24,8 +23,9 @@ private:
const String JWT_HEADER = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
String sign(String &value);
String encode(unsigned char * value, int length);
String decode(unsigned char * value);
static String encode(String value);
static String decode(String value);
public:
ArduinoJsonJWT(String secret);

View File

@ -104,8 +104,10 @@ void SecurityManager::testVerification(AsyncWebServerRequest *request, JsonDocum
DynamicJsonDocument parsedJwt(MAX_JWT_SIZE);
jwtHandler.parseJWT(accessToken, parsedJwt);
if (parsedJwt.is<JsonObject>()){
String username = parsedJwt["username"];
Serial.println(username);
// authentication successful
AsyncWebServerResponse *response = request->beginResponse(200);
request->send(response);
return;
}
}
// authentication failed

View File

@ -1,124 +0,0 @@
#include "base64.h"
unsigned char binary_to_base64(unsigned char v) {
// Capital letters - 'A' is ascii 65 and base64 0
if(v < 26) return v + 'A';
// Lowercase letters - 'a' is ascii 97 and base64 26
if(v < 52) return v + 71;
// Digits - '0' is ascii 48 and base64 52
if(v < 62) return v - 4;
// '+' is ascii 43 and base64 62
if(v == 62) return '-';
// '/' is ascii 47 and base64 63
if(v == 63) return '_';
return 64;
}
unsigned char base64_to_binary(unsigned char c) {
// Capital letters - 'A' is ascii 65 and base64 0
if('A' <= c && c <= 'Z') return c - 'A';
// Lowercase letters - 'a' is ascii 97 and base64 26
if('a' <= c && c <= 'z') return c - 71;
// Digits - '0' is ascii 48 and base64 52
if('0' <= c && c <= '9') return c + 4;
// '+' is ascii 43 and base64 62
if(c == '-') return 62;
// '/' is ascii 47 and base64 63
if(c == '_') return 63;
return 255;
}
unsigned int encode_base64_length(unsigned int input_length) {
return (input_length + 2)/3*4;
}
unsigned int decode_base64_length(unsigned char input[]) {
unsigned char *start = input;
while(base64_to_binary(input[0]) < 64) {
++input;
}
unsigned int input_length = input - start;
unsigned int output_length = input_length/4*3;
switch(input_length % 4) {
default: return output_length;
case 2: return output_length + 1;
case 3: return output_length + 2;
}
}
unsigned int encode_base64(unsigned char input[], unsigned int input_length, unsigned char output[]) {
unsigned int full_sets = input_length/3;
// While there are still full sets of 24 bits...
for(unsigned int i = 0; i < full_sets; ++i) {
output[0] = binary_to_base64( input[0] >> 2);
output[1] = binary_to_base64((input[0] & 0x03) << 4 | input[1] >> 4);
output[2] = binary_to_base64((input[1] & 0x0F) << 2 | input[2] >> 6);
output[3] = binary_to_base64( input[2] & 0x3F);
input += 3;
output += 4;
}
switch(input_length % 3) {
case 0:
output[0] = '\0';
break;
case 1:
output[0] = binary_to_base64( input[0] >> 2);
output[1] = binary_to_base64((input[0] & 0x03) << 4);
output[2] = '=';
output[3] = '=';
output[4] = '\0';
break;
case 2:
output[0] = binary_to_base64( input[0] >> 2);
output[1] = binary_to_base64((input[0] & 0x03) << 4 | input[1] >> 4);
output[2] = binary_to_base64((input[1] & 0x0F) << 2);
output[3] = '=';
output[4] = '\0';
break;
}
return encode_base64_length(input_length);
}
unsigned int decode_base64(unsigned char input[], unsigned char output[]) {
unsigned int output_length = decode_base64_length(input);
// While there are still full sets of 24 bits...
for(unsigned int i = 2; i < output_length; i += 3) {
output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4;
output[1] = base64_to_binary(input[1]) << 4 | base64_to_binary(input[2]) >> 2;
output[2] = base64_to_binary(input[2]) << 6 | base64_to_binary(input[3]);
input += 4;
output += 3;
}
switch(output_length % 3) {
case 1:
output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4;
break;
case 2:
output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4;
output[1] = base64_to_binary(input[1]) << 4 | base64_to_binary(input[2]) >> 2;
break;
}
return output_length;
}

View File

@ -1,77 +0,0 @@
/**
* Adapted from https://github.com/Densaugeo/base64_arduino
*/
/**
* Base64 encoding and decoding of strings. Uses '+' for 62, '\' for 63, '=' for padding
* This has been modified to use '-' for 62, '_' for 63 as per the JWT specification
*/
#ifndef BASE64_H_INCLUDED
#define BASE64_H_INCLUDED
/* binary_to_base64:
* Description:
* Converts a single byte from a binary value to the corresponding base64 character
* Parameters:
* v - Byte to convert
* Returns:
* ascii code of base64 character. If byte is >= 64, then there is not corresponding base64 character
* and 255 is returned
*/
unsigned char binary_to_base64(unsigned char v);
/* base64_to_binary:
* Description:
* Converts a single byte from a base64 character to the corresponding binary value
* Parameters:
* c - Base64 character (as ascii code)
* Returns:
* 6-bit binary value
*/
unsigned char base64_to_binary(unsigned char v);
/* encode_base64_length:
* Description:
* Calculates length of base64 string needed for a given number of binary bytes
* Parameters:
* input_length - Amount of binary data in bytes
* Returns:
* Number of base64 characters needed to encode input_length bytes of binary data
*/
unsigned int encode_base64_length(unsigned int input_length);
/* decode_base64_length:
* Description:
* Calculates number of bytes of binary data in a base64 string
* Parameters:
* input - Base64-encoded null-terminated string
* Returns:
* Number of bytes of binary data in input
*/
unsigned int decode_base64_length(unsigned char input[]);
/* encode_base64:
* Description:
* Converts an array of bytes to a base64 null-terminated string
* Parameters:
* input - Pointer to input data
* input_length - Number of bytes to read from input pointer
* output - Pointer to output string. Null terminator will be added automatically
* Returns:
* Length of encoded string in bytes (not including null terminator)
*/
unsigned int encode_base64(unsigned char input[], unsigned int input_length, unsigned char output[]);
/* decode_base64:
* Description:
* Converts a base64 null-terminated string to an array of bytes
* Parameters:
* input - Pointer to input string
* output - Pointer to output array
* Returns:
* Number of bytes in the decoded binary
*/
unsigned int decode_base64(unsigned char input[], unsigned char output[]);
#endif // ifndef