diff --git a/src/ArduinoJsonJWT.cpp b/src/ArduinoJsonJWT.cpp index 3889fe9..b99a949 100644 --- a/src/ArduinoJsonJWT.cpp +++ b/src/ArduinoJsonJWT.cpp @@ -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); +} diff --git a/src/ArduinoJsonJWT.h b/src/ArduinoJsonJWT.h index d317db6..672c9fc 100644 --- a/src/ArduinoJsonJWT.h +++ b/src/ArduinoJsonJWT.h @@ -1,11 +1,10 @@ #ifndef ArduinoJsonJWT_H #define ArduinoJsonJWT_H -#include "base64.h" - #include #include - +#include +#include #if defined(ESP_PLATFORM) #include #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); diff --git a/src/SecurityManager.cpp b/src/SecurityManager.cpp index 3a1ecae..73596b6 100644 --- a/src/SecurityManager.cpp +++ b/src/SecurityManager.cpp @@ -104,8 +104,10 @@ void SecurityManager::testVerification(AsyncWebServerRequest *request, JsonDocum DynamicJsonDocument parsedJwt(MAX_JWT_SIZE); jwtHandler.parseJWT(accessToken, parsedJwt); if (parsedJwt.is()){ - String username = parsedJwt["username"]; - Serial.println(username); + // authentication successful + AsyncWebServerResponse *response = request->beginResponse(200); + request->send(response); + return; } } // authentication failed diff --git a/src/base64.cpp b/src/base64.cpp deleted file mode 100644 index 2ebaf27..0000000 --- a/src/base64.cpp +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/src/base64.h b/src/base64.h deleted file mode 100644 index fd748d2..0000000 --- a/src/base64.h +++ /dev/null @@ -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 \ No newline at end of file