Fork of the excellent esp8266-react - https://github.com/rjwats/esp8266-react
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
4.1 KiB

  1. #include "ArduinoJsonJWT.h"
  2. ArduinoJsonJWT::ArduinoJsonJWT(String secret) : _secret(secret) { }
  3. void ArduinoJsonJWT::setSecret(String secret){
  4. _secret = secret;
  5. }
  6. String ArduinoJsonJWT::getSecret(){
  7. return _secret;
  8. }
  9. /*
  10. * ESP32 uses mbedtls, ESP2866 uses bearssl.
  11. *
  12. * Both come with decent HMAC implmentations supporting sha256, as well as others.
  13. *
  14. * No need to pull in additional crypto libraries - lets use what we already have.
  15. */
  16. String ArduinoJsonJWT::sign(String &payload) {
  17. unsigned char hmacResult[32];
  18. {
  19. #if defined(ESP_PLATFORM)
  20. mbedtls_md_context_t ctx;
  21. mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
  22. mbedtls_md_init(&ctx);
  23. mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
  24. mbedtls_md_hmac_starts(&ctx, (unsigned char *) _secret.c_str(), _secret.length());
  25. mbedtls_md_hmac_update(&ctx, (unsigned char *) payload.c_str(), payload.length());
  26. mbedtls_md_hmac_finish(&ctx, hmacResult);
  27. mbedtls_md_free(&ctx);
  28. #else
  29. br_hmac_key_context keyCtx;
  30. br_hmac_key_init(&keyCtx, &br_sha256_vtable, _secret.c_str(), _secret.length());
  31. br_hmac_context hmacCtx;
  32. br_hmac_init(&hmacCtx, &keyCtx, 0);
  33. br_hmac_update(&hmacCtx, payload.c_str(), payload.length());
  34. br_hmac_out(&hmacCtx, hmacResult);
  35. #endif
  36. }
  37. return encode((char *) hmacResult, 32);
  38. }
  39. String ArduinoJsonJWT::buildJWT(JsonObject &payload) {
  40. // serialize, then encode payload
  41. String jwt;
  42. serializeJson(payload, jwt);
  43. jwt = encode(jwt.c_str(), jwt.length());
  44. // add the header to payload
  45. jwt = JWT_HEADER + '.' + jwt;
  46. // add signature
  47. jwt += '.' + sign(jwt);
  48. return jwt;
  49. }
  50. void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument &jsonDocument) {
  51. // clear json document before we begin, jsonDocument wil be null on failure
  52. jsonDocument.clear();
  53. // must have the correct header and delimiter
  54. if (!jwt.startsWith(JWT_HEADER) || jwt.indexOf('.') != JWT_HEADER_SIZE) {
  55. return;
  56. }
  57. // check there is a signature delimieter
  58. int signatureDelimiterIndex = jwt.lastIndexOf('.');
  59. if (signatureDelimiterIndex == JWT_HEADER_SIZE) {
  60. return;
  61. }
  62. // check the signature is valid
  63. String signature = jwt.substring(signatureDelimiterIndex + 1);
  64. jwt = jwt.substring(0, signatureDelimiterIndex);
  65. if (sign(jwt) != signature){
  66. return;
  67. }
  68. // decode payload
  69. jwt = jwt.substring(JWT_HEADER_SIZE + 1);
  70. jwt = decode(jwt);
  71. // parse payload, clearing json document after failure
  72. DeserializationError error = deserializeJson(jsonDocument, jwt);
  73. if (error != DeserializationError::Ok || !jsonDocument.is<JsonObject>()){
  74. jsonDocument.clear();
  75. }
  76. }
  77. String ArduinoJsonJWT::encode(const char *cstr, int inputLen) {
  78. // prepare encoder
  79. base64_encodestate _state;
  80. #if defined(ESP8266)
  81. base64_init_encodestate_nonewlines(&_state);
  82. size_t encodedLength = base64_encode_expected_len_nonewlines(inputLen) + 1;
  83. #elif defined(ESP_PLATFORM)
  84. base64_init_encodestate(&_state);
  85. size_t encodedLength = base64_encode_expected_len(inputLen) + 1;
  86. #endif
  87. // prepare buffer of correct length, returning an empty string on failure
  88. char* buffer = (char*) malloc(encodedLength * sizeof(char));
  89. if (buffer == nullptr) {
  90. return "";
  91. }
  92. // encode to buffer
  93. int len = base64_encode_block(cstr, inputLen, &buffer[0], &_state);
  94. len += base64_encode_blockend(&buffer[len], &_state);
  95. buffer[len] = 0;
  96. // convert to arduino string, freeing buffer
  97. String value = String(buffer);
  98. free(buffer);
  99. buffer=nullptr;
  100. // remove padding and convert to URL safe form
  101. while (value.length() > 0 && value.charAt(value.length() - 1) == '='){
  102. value.remove(value.length() - 1);
  103. }
  104. value.replace('+', '-');
  105. value.replace('/', '_');
  106. // return as string
  107. return value;
  108. }
  109. String ArduinoJsonJWT::decode(String value) {
  110. // convert to standard base64
  111. value.replace('-', '+');
  112. value.replace( '_', '/');
  113. // prepare buffer of correct length
  114. char buffer[base64_decode_expected_len(value.length()) + 1];
  115. // decode
  116. int len = base64_decode_chars(value.c_str(), value.length(), &buffer[0]);
  117. buffer[len] = 0;
  118. // return as string
  119. return String(buffer);
  120. }