From e4030727cc052b0ced624ecabf81f05f0f7f550e Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Mon, 30 Mar 2026 16:26:40 -1000 Subject: [PATCH 1/8] Added a few more ESP32-ism files used by ESPAsyncWebServer --- .../cores/arduino/MD5Builder.cpp | 117 +++++++++++ ArduinoCore-Linux/cores/arduino/MD5Builder.h | 59 ++++++ ArduinoCore-Linux/cores/arduino/cbuf.cpp | 196 ++++++++++++++++++ ArduinoCore-Linux/cores/arduino/cbuf.h | 79 +++++++ .../cores/arduino/libb64/AUTHORS | 7 + .../cores/arduino/libb64/LICENSE | 29 +++ .../cores/arduino/libb64/cdecode.c | 102 +++++++++ .../cores/arduino/libb64/cdecode.h | 38 ++++ .../cores/arduino/libb64/cencode.c | 104 ++++++++++ .../cores/arduino/libb64/cencode.h | 41 ++++ 10 files changed, 772 insertions(+) create mode 100644 ArduinoCore-Linux/cores/arduino/MD5Builder.cpp create mode 100644 ArduinoCore-Linux/cores/arduino/MD5Builder.h create mode 100644 ArduinoCore-Linux/cores/arduino/cbuf.cpp create mode 100644 ArduinoCore-Linux/cores/arduino/cbuf.h create mode 100644 ArduinoCore-Linux/cores/arduino/libb64/AUTHORS create mode 100644 ArduinoCore-Linux/cores/arduino/libb64/LICENSE create mode 100644 ArduinoCore-Linux/cores/arduino/libb64/cdecode.c create mode 100644 ArduinoCore-Linux/cores/arduino/libb64/cdecode.h create mode 100644 ArduinoCore-Linux/cores/arduino/libb64/cencode.c create mode 100644 ArduinoCore-Linux/cores/arduino/libb64/cencode.h diff --git a/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp b/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp new file mode 100644 index 0000000..6cd9060 --- /dev/null +++ b/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp @@ -0,0 +1,117 @@ +/* + MD5Builder - Simple MD5 hash calculations + + Updated for the Pico by Earle F. Philhower, III + + Modified from the ESP8266 version which is + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +static uint8_t hex_char_to_byte(uint8_t c) { + return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) : + (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : + (c >= '0' && c <= '9') ? (c - (uint8_t)'0') : 0; +} + +void MD5Builder::begin(void) { + memset(_buf, 0x00, 16); + br_md5_init(&_ctx); +} + +void MD5Builder::add(const uint8_t * data, const uint16_t len) { + br_md5_update(&_ctx, data, len); +} + +void MD5Builder::addHexString(const char * data) { + uint16_t i, len = strlen(data); + auto tmp = std::unique_ptr {new (std::nothrow) uint8_t[len / 2]}; + + if (!tmp) { + return; + } + + for (i = 0; i < len; i += 2) { + uint8_t high = hex_char_to_byte(data[i]); + uint8_t low = hex_char_to_byte(data[i + 1]); + tmp[i / 2] = (high & 0x0F) << 4 | (low & 0x0F); + } + add(tmp.get(), len / 2); +} + +bool MD5Builder::addStream(Stream &stream, const size_t maxLen) { + const int buf_size = 512; + int maxLengthLeft = maxLen; + + auto buf = std::unique_ptr {new (std::nothrow) uint8_t[buf_size]}; + + if (!buf) { + return false; + } + + int bytesAvailable = stream.available(); + while ((bytesAvailable > 0) && (maxLengthLeft > 0)) { + + // determine number of bytes to read + int readBytes = bytesAvailable; + if (readBytes > maxLengthLeft) { + readBytes = maxLengthLeft; // read only until max_len + } + if (readBytes > buf_size) { + readBytes = buf_size; // not read more the buffer can handle + } + + // read data and check if we got something + int numBytesRead = stream.readBytes(buf.get(), readBytes); + if (numBytesRead < 1) { + return false; + } + + // Update MD5 with buffer payload + br_md5_update(&_ctx, buf.get(), numBytesRead); + + // update available number of bytes + maxLengthLeft -= numBytesRead; + bytesAvailable = stream.available(); + } + + return true; +} + +void MD5Builder::calculate(void) { + br_md5_out(&_ctx, _buf); +} + +void MD5Builder::getBytes(uint8_t * output) const { + memcpy(output, _buf, 16); +} + +void MD5Builder::getChars(char * output) const { + for (uint8_t i = 0; i < 16; i++) { + sprintf(output + (i * 2), "%02x", _buf[i]); + } +} + +String MD5Builder::toString(void) const { + char out[33]; + getChars(out); + return String(out); +} diff --git a/ArduinoCore-Linux/cores/arduino/MD5Builder.h b/ArduinoCore-Linux/cores/arduino/MD5Builder.h new file mode 100644 index 0000000..978d870 --- /dev/null +++ b/ArduinoCore-Linux/cores/arduino/MD5Builder.h @@ -0,0 +1,59 @@ +/* + MD5Builder - Simple MD5 hash calculations + + Updated for the Pico by Earle F. Philhower, III + + Modified from the ESP8266 version which is + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include +#include +#include + +class MD5Builder { +private: + br_md5_context _ctx; + uint8_t _buf[16]; +public: + void begin(void); + void add(const uint8_t * data, const uint16_t len); + void add(const char * data) { + add((const uint8_t*)data, strlen(data)); + } + void add(char * data) { + add((const char*)data); + } + void add(const String& data) { + add(data.c_str()); + } + void addHexString(const char * data); + void addHexString(char * data) { + addHexString((const char*)data); + } + void addHexString(const String& data) { + addHexString(data.c_str()); + } + bool addStream(Stream & stream, const size_t maxLen); + void calculate(void); + void getBytes(uint8_t * output) const; + void getChars(char * output) const; + String toString(void) const; +}; diff --git a/ArduinoCore-Linux/cores/arduino/cbuf.cpp b/ArduinoCore-Linux/cores/arduino/cbuf.cpp new file mode 100644 index 0000000..ef7370a --- /dev/null +++ b/ArduinoCore-Linux/cores/arduino/cbuf.cpp @@ -0,0 +1,196 @@ +/* + cbuf.cpp - Circular buffer implementation + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "cbuf.h" + +cbuf::cbuf(size_t size) : + next(NULL), _size(size+1), _buf(new char[size+1]), _bufend(_buf + size + 1), _begin(_buf), _end(_begin) +{ +} + +cbuf::~cbuf() +{ + delete[] _buf; +} + +size_t cbuf::resizeAdd(size_t addSize) +{ + return resize(_size + addSize); +} + +size_t cbuf::resize(size_t newSize) +{ + + size_t bytes_available = available(); + newSize += 1; + // not lose any data + // if data can be lost use remove or flush before resize + if((newSize < bytes_available) || (newSize == _size)) { + return _size; + } + + char *newbuf = new char[newSize]; + char *oldbuf = _buf; + + if(!newbuf) { + return _size; + } + + if(_buf) { + read(newbuf, bytes_available); + memset((newbuf + bytes_available), 0x00, (newSize - bytes_available)); + } + + _begin = newbuf; + _end = newbuf + bytes_available; + _bufend = newbuf + newSize; + _size = newSize; + + _buf = newbuf; + delete[] oldbuf; + + return _size; +} + +size_t cbuf::available() const +{ + if(_end >= _begin) { + return _end - _begin; + } + return _size - (_begin - _end); +} + +size_t cbuf::size() +{ + return _size; +} + +size_t cbuf::room() const +{ + if(_end >= _begin) { + return _size - (_end - _begin) - 1; + } + return _begin - _end - 1; +} + +int cbuf::peek() +{ + if(empty()) { + return -1; + } + + return static_cast(*_begin); +} + +size_t cbuf::peek(char *dst, size_t size) +{ + size_t bytes_available = available(); + size_t size_to_read = (size < bytes_available) ? size : bytes_available; + size_t size_read = size_to_read; + char * begin = _begin; + if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) { + size_t top_size = _bufend - _begin; + memcpy(dst, _begin, top_size); + begin = _buf; + size_to_read -= top_size; + dst += top_size; + } + memcpy(dst, begin, size_to_read); + return size_read; +} + +int cbuf::read() +{ + if(empty()) { + return -1; + } + + char result = *_begin; + _begin = wrap_if_bufend(_begin + 1); + return static_cast(result); +} + +size_t cbuf::read(char* dst, size_t size) +{ + size_t bytes_available = available(); + size_t size_to_read = (size < bytes_available) ? size : bytes_available; + size_t size_read = size_to_read; + if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) { + size_t top_size = _bufend - _begin; + memcpy(dst, _begin, top_size); + _begin = _buf; + size_to_read -= top_size; + dst += top_size; + } + memcpy(dst, _begin, size_to_read); + _begin = wrap_if_bufend(_begin + size_to_read); + return size_read; +} + +size_t cbuf::write(char c) +{ + if(full()) { + return 0; + } + + *_end = c; + _end = wrap_if_bufend(_end + 1); + return 1; +} + +size_t cbuf::write(const char* src, size_t size) +{ + size_t bytes_available = room(); + size_t size_to_write = (size < bytes_available) ? size : bytes_available; + size_t size_written = size_to_write; + if(_end >= _begin && size_to_write > (size_t) (_bufend - _end)) { + size_t top_size = _bufend - _end; + memcpy(_end, src, top_size); + _end = _buf; + size_to_write -= top_size; + src += top_size; + } + memcpy(_end, src, size_to_write); + _end = wrap_if_bufend(_end + size_to_write); + return size_written; +} + +void cbuf::flush() +{ + _begin = _buf; + _end = _buf; +} + +size_t cbuf::remove(size_t size) +{ + size_t bytes_available = available(); + if(size >= bytes_available) { + flush(); + return 0; + } + size_t size_to_remove = (size < bytes_available) ? size : bytes_available; + if(_end < _begin && size_to_remove > (size_t) (_bufend - _begin)) { + size_t top_size = _bufend - _begin; + _begin = _buf; + size_to_remove -= top_size; + } + _begin = wrap_if_bufend(_begin + size_to_remove); + return available(); +} diff --git a/ArduinoCore-Linux/cores/arduino/cbuf.h b/ArduinoCore-Linux/cores/arduino/cbuf.h new file mode 100644 index 0000000..490352e --- /dev/null +++ b/ArduinoCore-Linux/cores/arduino/cbuf.h @@ -0,0 +1,79 @@ +/* + cbuf.h - Circular buffer implementation + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __cbuf_h +#define __cbuf_h + +#include +#include +#include + +class cbuf +{ +public: + cbuf(size_t size); + ~cbuf(); + + size_t resizeAdd(size_t addSize); + size_t resize(size_t newSize); + size_t available() const; + size_t size(); + + size_t room() const; + + inline bool empty() const + { + return _begin == _end; + } + + inline bool full() const + { + return wrap_if_bufend(_end + 1) == _begin; + } + + int peek(); + size_t peek(char *dst, size_t size); + + int read(); + size_t read(char* dst, size_t size); + + size_t write(char c); + size_t write(const char* src, size_t size); + + void flush(); + size_t remove(size_t size); + + cbuf *next; + +protected: + inline char* wrap_if_bufend(char* ptr) const + { + return (ptr == _bufend) ? _buf : ptr; + } + + size_t _size; + char* _buf; + const char* _bufend; + char* _begin; + char* _end; + +}; + +#endif//__cbuf_h diff --git a/ArduinoCore-Linux/cores/arduino/libb64/AUTHORS b/ArduinoCore-Linux/cores/arduino/libb64/AUTHORS new file mode 100644 index 0000000..af68737 --- /dev/null +++ b/ArduinoCore-Linux/cores/arduino/libb64/AUTHORS @@ -0,0 +1,7 @@ +libb64: Base64 Encoding/Decoding Routines +====================================== + +Authors: +------- + +Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com diff --git a/ArduinoCore-Linux/cores/arduino/libb64/LICENSE b/ArduinoCore-Linux/cores/arduino/libb64/LICENSE new file mode 100644 index 0000000..a6b5606 --- /dev/null +++ b/ArduinoCore-Linux/cores/arduino/libb64/LICENSE @@ -0,0 +1,29 @@ +Copyright-Only Dedication (based on United States law) +or Public Domain Certification + +The person or persons who have associated work with this document (the +"Dedicator" or "Certifier") hereby either (a) certifies that, to the best of +his knowledge, the work of authorship identified is in the public domain of the +country from which the work is published, or (b) hereby dedicates whatever +copyright the dedicators holds in the work of authorship identified below (the +"Work") to the public domain. A certifier, moreover, dedicates any copyright +interest he may have in the associated work, and for these purposes, is +described as a "dedicator" below. + +A certifier has taken reasonable steps to verify the copyright status of this +work. Certifier recognizes that his good faith efforts may not shield him from +liability if in fact the work certified is not in the public domain. + +Dedicator makes this dedication for the benefit of the public at large and to +the detriment of the Dedicator's heirs and successors. Dedicator intends this +dedication to be an overt act of relinquishment in perpetuity of all present +and future rights under copyright law, whether vested or contingent, in the +Work. Dedicator understands that such relinquishment of all rights includes +the relinquishment of all rights to enforce (by lawsuit or otherwise) those +copyrights in the Work. + +Dedicator recognizes that, once placed in the public domain, the Work may be +freely reproduced, distributed, transmitted, used, modified, built upon, or +otherwise exploited by anyone for any purpose, commercial or non-commercial, +and in any way, including by methods that have not yet been invented or +conceived. \ No newline at end of file diff --git a/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c b/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c new file mode 100644 index 0000000..c4712b7 --- /dev/null +++ b/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c @@ -0,0 +1,102 @@ +/* +cdecoder.c - c source to a base64 decoding algorithm implementation + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#include "cdecode.h" +#include + +static int base64_decode_value_signed(int8_t value_in){ + static const int8_t decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; + static const int8_t decoding_size = sizeof(decoding); + value_in -= 43; + if (value_in < 0 || value_in >= decoding_size) return -1; + return decoding[(int)value_in]; +} + +void base64_init_decodestate(base64_decodestate* state_in){ + state_in->step = step_a; + state_in->plainchar = 0; +} + +static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in){ + const int8_t* codechar = code_in; + int8_t* plainchar = plaintext_out; + int8_t fragment; + + *plainchar = state_in->plainchar; + + switch (state_in->step){ + while (1){ + case step_a: + do { + if (codechar == code_in+length_in){ + state_in->step = step_a; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (int8_t)base64_decode_value_signed(*codechar++); + } while (fragment < 0); + *plainchar = (fragment & 0x03f) << 2; + // fall through + case step_b: + do { + if (codechar == code_in+length_in){ + state_in->step = step_b; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (int8_t)base64_decode_value_signed(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x030) >> 4; + *plainchar = (fragment & 0x00f) << 4; + // fall through + case step_c: + do { + if (codechar == code_in+length_in){ + state_in->step = step_c; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (int8_t)base64_decode_value_signed(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x03c) >> 2; + *plainchar = (fragment & 0x003) << 6; + // fall through + case step_d: + do { + if (codechar == code_in+length_in){ + state_in->step = step_d; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (int8_t)base64_decode_value_signed(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x03f); + } + } + /* control should not reach here */ + return plainchar - plaintext_out; +} + +static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out){ + base64_decodestate _state; + base64_init_decodestate(&_state); + int len = base64_decode_block_signed(code_in, length_in, plaintext_out, &_state); + if(len > 0) plaintext_out[len] = 0; + return len; +} + +int base64_decode_value(char value_in){ + return base64_decode_value_signed(*((int8_t *) &value_in)); +} + +int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in){ + return base64_decode_block_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in); +} + +int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out){ + return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out); +} diff --git a/ArduinoCore-Linux/cores/arduino/libb64/cdecode.h b/ArduinoCore-Linux/cores/arduino/libb64/cdecode.h new file mode 100644 index 0000000..44f114f --- /dev/null +++ b/ArduinoCore-Linux/cores/arduino/libb64/cdecode.h @@ -0,0 +1,38 @@ +/* +cdecode.h - c header for a base64 decoding algorithm + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#ifndef BASE64_CDECODE_H +#define BASE64_CDECODE_H + +#define base64_decode_expected_len(n) ((n * 3) / 4) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + step_a, step_b, step_c, step_d +} base64_decodestep; + +typedef struct { + base64_decodestep step; + char plainchar; +} base64_decodestate; + +void base64_init_decodestate(base64_decodestate* state_in); + +int base64_decode_value(char value_in); + +int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); + +int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* BASE64_CDECODE_H */ diff --git a/ArduinoCore-Linux/cores/arduino/libb64/cencode.c b/ArduinoCore-Linux/cores/arduino/libb64/cencode.c new file mode 100644 index 0000000..f5388e5 --- /dev/null +++ b/ArduinoCore-Linux/cores/arduino/libb64/cencode.c @@ -0,0 +1,104 @@ +/* +cencoder.c - c source to a base64 encoding algorithm implementation + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#include "cencode.h" + +void base64_init_encodestate(base64_encodestate* state_in) +{ + state_in->step = step_A; + state_in->result = 0; +} + +char base64_encode_value(char value_in) +{ + static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + if (value_in > 63) { + return '='; + } + return encoding[(int)value_in]; +} + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) +{ + const char* plainchar = plaintext_in; + const char* const plaintextend = plaintext_in + length_in; + char* codechar = code_out; + char result; + char fragment; + + result = state_in->result; + + switch (state_in->step) { + while (1) { + case step_A: + if (plainchar == plaintextend) { + state_in->result = result; + state_in->step = step_A; + return codechar - code_out; + } + fragment = *plainchar++; + result = (fragment & 0x0fc) >> 2; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x003) << 4; + // fall through + case step_B: + if (plainchar == plaintextend) { + state_in->result = result; + state_in->step = step_B; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0f0) >> 4; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x00f) << 2; + // fall through + case step_C: + if (plainchar == plaintextend) { + state_in->result = result; + state_in->step = step_C; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0c0) >> 6; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x03f) >> 0; + *codechar++ = base64_encode_value(result); + } + } + /* control should not reach here */ + return codechar - code_out; +} + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in) +{ + char* codechar = code_out; + + switch (state_in->step) { + case step_B: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + *codechar++ = '='; + break; + case step_C: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + break; + case step_A: + break; + } + *codechar = 0x00; + + return codechar - code_out; +} + +int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out) +{ + base64_encodestate _state; + base64_init_encodestate(&_state); + int len = base64_encode_block(plaintext_in, length_in, code_out, &_state); + return len + base64_encode_blockend((code_out + len), &_state); +} diff --git a/ArduinoCore-Linux/cores/arduino/libb64/cencode.h b/ArduinoCore-Linux/cores/arduino/libb64/cencode.h new file mode 100644 index 0000000..51bb3f3 --- /dev/null +++ b/ArduinoCore-Linux/cores/arduino/libb64/cencode.h @@ -0,0 +1,41 @@ +/* +cencode.h - c header for a base64 encoding algorithm + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#ifndef BASE64_CENCODE_H +#define BASE64_CENCODE_H + +#define base64_encode_expected_len(n) ((((4 * n) / 3) + 3) & ~3) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + step_A, step_B, step_C +} base64_encodestep; + +typedef struct { + base64_encodestep step; + char result; + int stepcount; +} base64_encodestate; + +void base64_init_encodestate(base64_encodestate* state_in); + +char base64_encode_value(char value_in); + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in); + +int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* BASE64_CENCODE_H */ From 23d95dbb793c434fe8120f244fcd933083d0d3ed Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Wed, 1 Apr 2026 09:53:07 -1000 Subject: [PATCH 2/8] Fix problems with MD5Builder and cbuf * Eliminated MD5Builder's dependency on BearSSL by copying publicly-available md5 code directly into MD5Builder and adjusting it to use class variables instead of a separate context structure. * Fixed the well-known off-by-one size bug in the cbuf code that was copied from the ESP32 Arduino code. The sizes returned by all methods now reflect that actual data capacity of the buffer, without counting the sentinel byte that should be hidden. I asked for multiple AI reviews of the new code and also verified that it is compatible with the one use of cbuf in ESPAsyncWebServer --- .../cores/arduino/MD5Builder.cpp | 251 ++++++++++++++++-- ArduinoCore-Linux/cores/arduino/MD5Builder.h | 11 +- ArduinoCore-Linux/cores/arduino/cbuf.cpp | 11 +- 3 files changed, 238 insertions(+), 35 deletions(-) diff --git a/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp b/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp index 6cd9060..93de39c 100644 --- a/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp +++ b/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp @@ -26,40 +26,209 @@ #include #include -static uint8_t hex_char_to_byte(uint8_t c) { - return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) : - (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : - (c >= '0' && c <= '9') ? (c - (uint8_t)'0') : 0; +/* + * Constants defined by the MD5 algorithm + */ +#define A 0x67452301 +#define B 0xefcdab89 +#define C 0x98badcfe +#define D 0x10325476 + +static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; + +static uint32_t K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; + +/* + * Padding used to make the size (in bits) of the input congruent to 448 mod 512 + */ +static uint8_t PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* + * Bit-manipulation functions defined by the MD5 algorithm + */ +#ifdef F +#undef F +#endif +#define F(X, Y, Z) ((X & Y) | (~X & Z)) +#define G(X, Y, Z) ((X & Z) | (Y & ~Z)) +#define H(X, Y, Z) (X ^ Y ^ Z) +#define I(X, Y, Z) (Y ^ (X | ~Z)) + +/* + * Rotates a 32-bit word left by n bits + */ +static inline uint32_t rotateLeft(uint32_t x, uint32_t n){ + return (x << n) | (x >> (32 - n)); } -void MD5Builder::begin(void) { - memset(_buf, 0x00, 16); - br_md5_init(&_ctx); +/* + * Step on 512 bits of input with the main MD5 algorithm. + */ +static void md5Step(uint32_t *buffer, uint32_t *input){ + uint32_t AA = buffer[0]; + uint32_t BB = buffer[1]; + uint32_t CC = buffer[2]; + uint32_t DD = buffer[3]; + + uint32_t E; + + unsigned int j; + + for(unsigned int i = 0; i < 64; ++i){ + switch(i / 16){ + case 0: + E = F(BB, CC, DD); + j = i; + break; + case 1: + E = G(BB, CC, DD); + j = ((i * 5) + 1) % 16; + break; + case 2: + E = H(BB, CC, DD); + j = ((i * 3) + 5) % 16; + break; + default: + E = I(BB, CC, DD); + j = (i * 7) % 16; + break; + } + + uint32_t temp = DD; + DD = CC; + CC = BB; + BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]); + AA = temp; + } + + buffer[0] += AA; + buffer[1] += BB; + buffer[2] += CC; + buffer[3] += DD; } -void MD5Builder::add(const uint8_t * data, const uint16_t len) { - br_md5_update(&_ctx, data, len); +/* + * Add some amount of input to the context + * + * If the input fills out a block of 512 bits, apply the algorithm (md5Step) + * and save the result in the buffer. Also updates the overall size. + */ +void MD5Builder::add(const uint8_t* input_buffer, const size_t input_len) { + uint32_t input[16]; + size_t offset = _size % 64; + _size += input_len; + + // Copy each byte in input_buffer into the next space in our context input + for(size_t i = 0; i < input_len; ++i){ + _input[offset++] = (uint8_t)*(input_buffer + i); + + // If we've filled our context input, copy it into our local array input + // then reset the offset to 0 and fill in a new buffer. + // Every time we fill out a chunk, we run it through the algorithm + // to enable some back and forth between cpu and i/o + if(offset % 64 == 0){ + for(unsigned int j = 0; j < 16; ++j){ + // Convert to little-endian + // The local variable `input` our 512-bit chunk separated into 32-bit words + // we can use in calculations + input[j] = (uint32_t)(_input[(j * 4) + 3]) << 24 | + (uint32_t)(_input[(j * 4) + 2]) << 16 | + (uint32_t)(_input[(j * 4) + 1]) << 8 | + (uint32_t)(_input[(j * 4)]); + } + md5Step(_buffer, input); + offset = 0; + } + } +} + +static bool hex_char_to_nibble(uint8_t c, uint8_t& nibble) { + if (c >= 'a' && c <= 'f') { + nibble = c - ((uint8_t)'a' - 0xA); + return true; + } + if (c >= 'A' && c <= 'F') { + nibble = c - ((uint8_t)'A' - 0xA); + return true; + } + if (c >= '0' && c <= '9') { + nibble = c - (uint8_t)'0'; + return true; + } + return false; +} + +void MD5Builder::begin(void) { + _size = 0; + + _buffer[0] = (uint32_t)A; + _buffer[1] = (uint32_t)B; + _buffer[2] = (uint32_t)C; + _buffer[3] = (uint32_t)D; } void MD5Builder::addHexString(const char * data) { - uint16_t i, len = strlen(data); - auto tmp = std::unique_ptr {new (std::nothrow) uint8_t[len / 2]}; + size_t len = strlen(data); - if (!tmp) { + // Require an even number of hex characters; odd lengths cannot form full bytes. + if ((len == 0) || (len % 2 != 0)) { return; } - for (i = 0; i < len; i += 2) { - uint8_t high = hex_char_to_byte(data[i]); - uint8_t low = hex_char_to_byte(data[i + 1]); - tmp[i / 2] = (high & 0x0F) << 4 | (low & 0x0F); + constexpr size_t chunk_size = 64; + uint8_t tmp[chunk_size]; + size_t byte_count = len / 2; + + for (size_t processed = 0; processed < byte_count;) { + size_t remaining = byte_count - processed; + size_t this_chunk = (remaining > chunk_size) ? chunk_size : remaining; + + for (size_t i = 0; i < this_chunk; ++i) { + size_t hex_index = (processed + i) * 2; + uint8_t high; + uint8_t low; + + if (!hex_char_to_nibble(static_cast(data[hex_index]), high) || + !hex_char_to_nibble(static_cast(data[hex_index + 1]), low)) { + return; + } + + tmp[i] = static_cast((high << 4) | low); + } + + add(tmp, this_chunk); + processed += this_chunk; } - add(tmp.get(), len / 2); } bool MD5Builder::addStream(Stream &stream, const size_t maxLen) { const int buf_size = 512; - int maxLengthLeft = maxLen; + size_t maxLengthLeft = maxLen; auto buf = std::unique_ptr {new (std::nothrow) uint8_t[buf_size]}; @@ -67,11 +236,11 @@ bool MD5Builder::addStream(Stream &stream, const size_t maxLen) { return false; } - int bytesAvailable = stream.available(); + size_t bytesAvailable = stream.available(); while ((bytesAvailable > 0) && (maxLengthLeft > 0)) { // determine number of bytes to read - int readBytes = bytesAvailable; + size_t readBytes = bytesAvailable; if (readBytes > maxLengthLeft) { readBytes = maxLengthLeft; // read only until max_len } @@ -80,13 +249,13 @@ bool MD5Builder::addStream(Stream &stream, const size_t maxLen) { } // read data and check if we got something - int numBytesRead = stream.readBytes(buf.get(), readBytes); + size_t numBytesRead = stream.readBytes(buf.get(), readBytes); if (numBytesRead < 1) { return false; } // Update MD5 with buffer payload - br_md5_update(&_ctx, buf.get(), numBytesRead); + add(buf.get(), numBytesRead); // update available number of bytes maxLengthLeft -= numBytesRead; @@ -96,17 +265,49 @@ bool MD5Builder::addStream(Stream &stream, const size_t maxLen) { return true; } +/* + * Pad the current input to get to 448 bytes, append the size in bits to the very end, + * and save the result of the final iteration into digest. + */ void MD5Builder::calculate(void) { - br_md5_out(&_ctx, _buf); + uint32_t input[16]; + size_t offset = _size % 64; + size_t padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset; + + // Fill in the padding and undo the changes to size that resulted from the update + add(PADDING, padding_length); + _size -= padding_length; + + // Do a final update (internal to this function) + // Last two 32-bit words are the two halves of the size (converted from bytes to bits) + for(unsigned int j = 0; j < 14; ++j){ + input[j] = (uint32_t)(_input[(j * 4) + 3]) << 24 | + (uint32_t)(_input[(j * 4) + 2]) << 16 | + (uint32_t)(_input[(j * 4) + 1]) << 8 | + (uint32_t)(_input[(j * 4)]); + } + uint64_t bit_length = _size * 8ULL; + input[14] = (uint32_t)(bit_length); + input[15] = (uint32_t)(bit_length >> 32); + + md5Step(_buffer, input); + + // Move the result into digest (convert from little-endian) + for(unsigned int i = 0; i < 4; ++i){ + _digest[(i * 4) + 0] = (uint8_t)((_buffer[i] & 0x000000FF)); + _digest[(i * 4) + 1] = (uint8_t)((_buffer[i] & 0x0000FF00) >> 8); + _digest[(i * 4) + 2] = (uint8_t)((_buffer[i] & 0x00FF0000) >> 16); + _digest[(i * 4) + 3] = (uint8_t)((_buffer[i] & 0xFF000000) >> 24); + } } void MD5Builder::getBytes(uint8_t * output) const { - memcpy(output, _buf, 16); + memcpy(output, _digest, 16); } void MD5Builder::getChars(char * output) const { for (uint8_t i = 0; i < 16; i++) { - sprintf(output + (i * 2), "%02x", _buf[i]); + sprintf(output + (i * 2), "%02x", _digest[i]); } } diff --git a/ArduinoCore-Linux/cores/arduino/MD5Builder.h b/ArduinoCore-Linux/cores/arduino/MD5Builder.h index 978d870..c6a5a2d 100644 --- a/ArduinoCore-Linux/cores/arduino/MD5Builder.h +++ b/ArduinoCore-Linux/cores/arduino/MD5Builder.h @@ -2,6 +2,7 @@ MD5Builder - Simple MD5 hash calculations Updated for the Pico by Earle F. Philhower, III + Updated for Linux by Mitch Bradley Modified from the ESP8266 version which is Copyright (c) 2015 Hristo Gochkov. All rights reserved. @@ -26,15 +27,17 @@ #include #include -#include +#include class MD5Builder { private: - br_md5_context _ctx; - uint8_t _buf[16]; + uint64_t _size; // Size of input in bytes + uint32_t _buffer[4]; // Current accumulation of hash + uint8_t _input[64]; // Input to be used in the next step + uint8_t _digest[16]; // Result of algorithm public: void begin(void); - void add(const uint8_t * data, const uint16_t len); + void add(const uint8_t * data, const size_t len); void add(const char * data) { add((const uint8_t*)data, strlen(data)); } diff --git a/ArduinoCore-Linux/cores/arduino/cbuf.cpp b/ArduinoCore-Linux/cores/arduino/cbuf.cpp index ef7370a..c427630 100644 --- a/ArduinoCore-Linux/cores/arduino/cbuf.cpp +++ b/ArduinoCore-Linux/cores/arduino/cbuf.cpp @@ -21,7 +21,7 @@ #include "cbuf.h" cbuf::cbuf(size_t size) : - next(NULL), _size(size+1), _buf(new char[size+1]), _bufend(_buf + size + 1), _begin(_buf), _end(_begin) + next(NULL), _size(size), _buf(new char[size+1]), _bufend(_buf + size + 1), _begin(_buf), _end(_begin) { } @@ -39,14 +39,13 @@ size_t cbuf::resize(size_t newSize) { size_t bytes_available = available(); - newSize += 1; // not lose any data // if data can be lost use remove or flush before resize if((newSize < bytes_available) || (newSize == _size)) { return _size; } - char *newbuf = new char[newSize]; + char *newbuf = new char[newSize+1]; char *oldbuf = _buf; if(!newbuf) { @@ -60,7 +59,7 @@ size_t cbuf::resize(size_t newSize) _begin = newbuf; _end = newbuf + bytes_available; - _bufend = newbuf + newSize; + _bufend = newbuf + newSize + 1; _size = newSize; _buf = newbuf; @@ -85,9 +84,9 @@ size_t cbuf::size() size_t cbuf::room() const { if(_end >= _begin) { - return _size - (_end - _begin) - 1; + return _size - (_end - _begin); } - return _begin - _end - 1; + return _begin - _end; } int cbuf::peek() From 8103815674d677868d7198bc2cf353c90f32dba4 Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Wed, 1 Apr 2026 12:03:52 -1000 Subject: [PATCH 3/8] This time for sure on cbuf --- ArduinoCore-Linux/cores/arduino/cbuf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ArduinoCore-Linux/cores/arduino/cbuf.cpp b/ArduinoCore-Linux/cores/arduino/cbuf.cpp index c427630..cde66ba 100644 --- a/ArduinoCore-Linux/cores/arduino/cbuf.cpp +++ b/ArduinoCore-Linux/cores/arduino/cbuf.cpp @@ -73,7 +73,7 @@ size_t cbuf::available() const if(_end >= _begin) { return _end - _begin; } - return _size - (_begin - _end); + return _size + 1 - (_begin - _end); } size_t cbuf::size() @@ -86,7 +86,7 @@ size_t cbuf::room() const if(_end >= _begin) { return _size - (_end - _begin); } - return _begin - _end; + return _begin - _end - 1; } int cbuf::peek() From 5210bf0a430a4d8f4d0512e81aadcd1ff8cdeca3 Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Wed, 1 Apr 2026 12:05:37 -1000 Subject: [PATCH 4/8] Corrected comment about digest input size --- ArduinoCore-Linux/cores/arduino/MD5Builder.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp b/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp index 93de39c..6c2384b 100644 --- a/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp +++ b/ArduinoCore-Linux/cores/arduino/MD5Builder.cpp @@ -266,8 +266,9 @@ bool MD5Builder::addStream(Stream &stream, const size_t maxLen) { } /* - * Pad the current input to get to 448 bytes, append the size in bits to the very end, - * and save the result of the final iteration into digest. + * Pad the current input so its length is congruent to 448 bits (56 bytes) modulo 512 bits, + * then append the size in bits to the very end, and save the result of the final iteration + * into digest. */ void MD5Builder::calculate(void) { uint32_t input[16]; From 905a6c99e50ccbb3d47eb3da855c4b122c731f9e Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Wed, 1 Apr 2026 15:18:03 -0700 Subject: [PATCH 5/8] Update ArduinoCore-Linux/cores/arduino/libb64/cencode.c Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ArduinoCore-Linux/cores/arduino/libb64/cencode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ArduinoCore-Linux/cores/arduino/libb64/cencode.c b/ArduinoCore-Linux/cores/arduino/libb64/cencode.c index f5388e5..ec11f98 100644 --- a/ArduinoCore-Linux/cores/arduino/libb64/cencode.c +++ b/ArduinoCore-Linux/cores/arduino/libb64/cencode.c @@ -11,6 +11,7 @@ void base64_init_encodestate(base64_encodestate* state_in) { state_in->step = step_A; state_in->result = 0; + state_in->stepcount = 0; } char base64_encode_value(char value_in) From f92d828efc3cce0645bb94542ed37245639baeb2 Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Wed, 1 Apr 2026 15:18:45 -0700 Subject: [PATCH 6/8] Update ArduinoCore-Linux/cores/arduino/libb64/cdecode.c Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ArduinoCore-Linux/cores/arduino/libb64/cdecode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c b/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c index c4712b7..67d70d6 100644 --- a/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c +++ b/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c @@ -94,9 +94,9 @@ int base64_decode_value(char value_in){ } int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in){ - return base64_decode_block_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in); + return base64_decode_block_signed((const int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in); } int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out){ - return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out); + return base64_decode_chars_signed((const int8_t *) code_in, length_in, (int8_t *) plaintext_out); } From c36c93fe6a11c615b5e5508200539dba44963f8b Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Wed, 1 Apr 2026 15:36:54 -0700 Subject: [PATCH 7/8] Update ArduinoCore-Linux/cores/arduino/cbuf.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ArduinoCore-Linux/cores/arduino/cbuf.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ArduinoCore-Linux/cores/arduino/cbuf.cpp b/ArduinoCore-Linux/cores/arduino/cbuf.cpp index cde66ba..c253f76 100644 --- a/ArduinoCore-Linux/cores/arduino/cbuf.cpp +++ b/ArduinoCore-Linux/cores/arduino/cbuf.cpp @@ -48,10 +48,6 @@ size_t cbuf::resize(size_t newSize) char *newbuf = new char[newSize+1]; char *oldbuf = _buf; - if(!newbuf) { - return _size; - } - if(_buf) { read(newbuf, bytes_available); memset((newbuf + bytes_available), 0x00, (newSize - bytes_available)); From 8321cc6046a99895975c7a61931af071b43c9c73 Mon Sep 17 00:00:00 2001 From: Mitch Bradley Date: Wed, 1 Apr 2026 15:44:15 -0700 Subject: [PATCH 8/8] Update ArduinoCore-Linux/cores/arduino/libb64/cdecode.c Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ArduinoCore-Linux/cores/arduino/libb64/cdecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c b/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c index 67d70d6..561986e 100644 --- a/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c +++ b/ArduinoCore-Linux/cores/arduino/libb64/cdecode.c @@ -90,7 +90,7 @@ static int base64_decode_chars_signed(const int8_t* code_in, const int length_in } int base64_decode_value(char value_in){ - return base64_decode_value_signed(*((int8_t *) &value_in)); + return base64_decode_value_signed((int8_t)value_in); } int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in){