diff --git a/extras/test/CMakeLists.txt b/extras/test/CMakeLists.txt index 0916ea6..2fb0dd0 100644 --- a/extras/test/CMakeLists.txt +++ b/extras/test/CMakeLists.txt @@ -26,13 +26,14 @@ set(TEST_SRCS src/crc32/test_crc32.cpp src/crc16/test_crc16.cpp src/sha256/test_sha256.cpp + src/hex/test_hex.cpp ) set(TEST_DUT_SRCS ../../src/crc/crc32.cpp ../../src/crc/crc16.cpp - ../../src/sha256/SHA256.cpp ../../src/sha256/sha2.c + ../../src/hex/chex.h ) ########################################################################## diff --git a/extras/test/src/hex/test_hex.cpp b/extras/test/src/hex/test_hex.cpp new file mode 100644 index 0000000..7e3a0d3 --- /dev/null +++ b/extras/test/src/hex/test_hex.cpp @@ -0,0 +1,53 @@ +/* + This file is part of the Arduino_CloudUtils library. + + Copyright (c) 2024 Arduino SA + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#include + +#include + +SCENARIO( "HEX encoding test" ) { + /* check all possible 16-bit values in network byte order */ + unsigned i; + for(i = 0; i <= 0xffff; ++i){ + /* encode to hex string using our implementation */ + const unsigned char org[2] = {(unsigned char)(i>>8), (unsigned char)i}; + char hex[5] = {0,0,0,0,0}; + chex_encode(hex, sizeof(hex), org, sizeof(org)); + + /* decode from hex string using a function from the standard library */ + unsigned char bin[2] = {0,0}; + int n = sscanf(hex, "%02hhx%02hhx", bin, bin+1); + REQUIRE(n == sizeof(bin)); + + /* decoded matches the original */ + REQUIRE(memcmp(org, bin, sizeof(bin)) == 0); + } + REQUIRE(i == 0x10000); +} + +SCENARIO( "HEX decoding test" ) { + /* check all possible 16-bit values in network byte order */ + unsigned i; + for(i = 0; i <= 0xffff; ++i){ + /* encode to hex string using a function from the standard library */ + char hex[5] = {0,0,0,0,0}; + snprintf(hex, sizeof(hex), "%02hhX%02hhx", (unsigned char)(i>>8), (unsigned char)i); + + /* decode from hex string using our implementation */ + unsigned char bin[2]; + unsigned n = chex_decode(bin, sizeof(bin), hex, sizeof(hex)); + REQUIRE(n == sizeof(bin)); + + /* decoded matches the original */ + const unsigned char org[2] = {(unsigned char)(i>>8), (unsigned char)i}; + REQUIRE(memcmp(org, bin, sizeof(bin)) == 0); + } + REQUIRE(i == 0x10000); +} diff --git a/src/Arduino_HEX.h b/src/Arduino_HEX.h index 4ea9af0..c99ca04 100644 --- a/src/Arduino_HEX.h +++ b/src/Arduino_HEX.h @@ -10,3 +10,4 @@ #pragma once #include "./hex/hex.h" +using namespace hex; diff --git a/src/bpid/bpid.cpp b/src/bpid/bpid.cpp index 4c11130..44a3eda 100644 --- a/src/bpid/bpid.cpp +++ b/src/bpid/bpid.cpp @@ -41,7 +41,6 @@ namespace arduino { namespace bpid { uint8_t out[SHA256::HASH_SIZE]; arduino::sha256::sha256(data, sizeof(data), out); return arduino::hex::encode(out, sizeof(out)); - return String(""); } }} // arduino::bpid diff --git a/src/bpid/csn.cpp b/src/bpid/csn.cpp index f0e312a..2e547f9 100644 --- a/src/bpid/csn.cpp +++ b/src/bpid/csn.cpp @@ -9,6 +9,7 @@ */ #include "csn.h" +#include "hex/hex.h" namespace arduino { namespace csn { @@ -22,7 +23,7 @@ namespace arduino { namespace csn { return false; } SecureElement se; - if (!se.begin() || !se.serialNumber(in)) { + if (!se.begin() || !arduino::hex::decode(se.serialNumber(), in, size)) { return false; } return true; diff --git a/src/bpid/csn.h b/src/bpid/csn.h index 47ef85d..795c07e 100644 --- a/src/bpid/csn.h +++ b/src/bpid/csn.h @@ -24,21 +24,21 @@ defined(ARDUINO_OPTA) || \ defined(ARDUINO_GIGA) #include - #define CRYPTO_SN_SIZE 0 + #define CRYPTO_SN_SIZE 9 #elif defined(ARDUINO_PORTENTA_C33) || \ defined(ARDUINO_NICLA_VISION) #include - #define CRYPTO_SN_SIZE 0 + #define CRYPTO_SN_SIZE 18 #elif defined(ARDUINO_UNOR4_WIFI) #include - #define CRYPTO_SN_SIZE 0 + #define CRYPTO_SN_SIZE 6 #else #define CRYPTO_SN_SIZE 0 #endif namespace arduino { namespace csn { /* - * This library contains the methods to get board microcontroller id + * This library contains the methods to get crypto serial number */ bool get(uint8_t *in, uint32_t size); diff --git a/src/bpid/ucid.h b/src/bpid/ucid.h index 4fca022..560f3b3 100644 --- a/src/bpid/ucid.h +++ b/src/bpid/ucid.h @@ -12,12 +12,12 @@ #include -#if defined(ARDUINO_SAMD_NANO_33_IOT) || \ - defined(ARDUINO_SAMD_MKRWIFI1010) || \ - defined(ARDUINO_SAMD_MKRGSM1400) || \ - defined(ARDUINO_SAMD_MKRWAN1300) || \ - defined(ARDUINO_SAMD_MKRWAN1310) || \ - defined(ARDUINO_SAMD_MKRNB1500) || \ +#if defined(ARDUINO_SAMD_NANO_33_IOT) || \ + defined(ARDUINO_SAMD_MKRWIFI1010) || \ + defined(ARDUINO_SAMD_MKRGSM1400) || \ + defined(ARDUINO_SAMD_MKRWAN1300) || \ + defined(ARDUINO_SAMD_MKRWAN1310) || \ + defined(ARDUINO_SAMD_MKRNB1500) || \ defined(ARDUINO_SAMD_MKR1000) #define UC_UID_SIZE 16 #elif defined(ARDUINO_PORTENTA_H7_M7) || \ diff --git a/src/hex/README.md b/src/hex/README.md new file mode 100644 index 0000000..31f1d17 --- /dev/null +++ b/src/hex/README.md @@ -0,0 +1,3 @@ +# chex + +[chex.h](chex.h) file implement hex encoding/decoding basic functions by Tero 'stedo' Liukko under a MIT license. https://github.com/stedonet/chex \ No newline at end of file diff --git a/src/hex/chex.h b/src/hex/chex.h new file mode 100644 index 0000000..692e911 --- /dev/null +++ b/src/hex/chex.h @@ -0,0 +1,104 @@ +/* +MIT License + +Copyright (c) 2022 Tero 'stedo' Liukko. https://github.com/stedonet/chex + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef STEDO_CHEX_H +#define STEDO_CHEX_H + +/** + * @brief check whether given ASCII character is a hexadecimal digit + * @param[in] h ASCII character to decode + * @return TRUE if h is hexadecimal, FALSE otherwise +**/ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +static unsigned chex_isxdigit(unsigned h){ + unsigned char n09 = h - '0'; + unsigned char nAF = (h | 0x20) - 'a'; + return (n09 <= (9 - 0)) || (nAF <= (0xf - 0xa)); +} +#pragma GCC diagnostic pop + +/** + * @brief encode nibble to hexadecimal ASCII character + * @param[in] nibble value to encode + * @return hexadecimal ASCII value + * @note the four most significant bits are ignored +**/ +static char chex_toxdigit(unsigned nibble){ + const char* lut = "0123456789abcdef"; + return lut[nibble & 0xf]; +} + + +/** + * @brief decode a single case-insensitive hexadecimal ASCII character to its decimal value + * @param[in] h ASCII character to decode + * @return decimal value of the input + * @note the input is assumed to be a valid +**/ +static unsigned char chex_fromxdigit(unsigned h){ + return ((h & 0xf) + (h >> 6) * 9); +} + + +/** + * @brief encode an array of bytes to an array of hexadecimal ASCII characters + * @param[out] hex buffer to write to + * @param[in] hlen maximum number of characters to write + * @param[in] bin array of bytes to encode + * @param[in] blen number of bytes to encode + * @return number of characters written + * @note null terminator is not included in the output +**/ +static unsigned chex_encode(char* hex, unsigned hlen, const void* bin, unsigned blen){ + const unsigned char* b = (const unsigned char*)bin; + unsigned i, j; + for(i = 0, j = 0; (i < blen) && (j+1 < hlen); ++i, j+=2){ + hex[j+0] = chex_toxdigit(b[i]>>4); + hex[j+1] = chex_toxdigit(b[i]>>0); + } + return j; +} + + +/** + * @brief decode an array of hexadecimal ASCII characters to an array of bytes + * @param[out] bin buffer to write to + * @param[in] blen maximum number of bytes to write + * @param[in] hex array of hex characters to decode + * @param[in] hlen number of hex characters to decode + * @return number of bytes written + * @note hex input is assumed valid and its length a multiple of two +**/ +static unsigned chex_decode(void* bin, unsigned blen, const char* hex, unsigned hlen){ + unsigned i, j; + for(i = 0, j = 0; (i < blen) && (j+1 < hlen); ++i, j+=2){ + unsigned char hi = chex_fromxdigit(hex[j+0]); + unsigned char lo = chex_fromxdigit(hex[j+1]); + ((unsigned char*)bin)[i] = (hi << 4) | lo; + } + return i; +} + +#endif /* STEDO_CHEX_H */ diff --git a/src/hex/hex.cpp b/src/hex/hex.cpp index a5c33fa..8631126 100644 --- a/src/hex/hex.cpp +++ b/src/hex/hex.cpp @@ -9,18 +9,30 @@ */ #include "hex.h" +#include "chex.h" namespace arduino { namespace hex { - String encode(uint8_t* in, uint32_t size) { - String out; - out.reserve((size * 2) + 1); + String encode(const uint8_t* in, uint32_t size) { + char out[(size * 2) + 1]; + unsigned int byteNumber; + byteNumber = chex_encode(out, sizeof(out), in, size); + out[byteNumber] = 0; + return String(out); + } + + String encodeUpper(const uint8_t* in, uint32_t size) { + String out = encode(in, size); + out.toUpperCase(); + return out; + } - char *ptr = out.begin(); - for (uint32_t i = 0; i < size; i++) { - ptr += sprintf(ptr, "%02X", in[i]); - } - return String(out.c_str()); + bool decode(const String in, uint8_t* out, uint32_t size) { + unsigned int byteNumber; + byteNumber = chex_decode(out, size, in.begin(), in.length()); + Serial.println(byteNumber); + Serial.println(in.length()); + return byteNumber * 2 == in.length(); } }} // arduino::hex diff --git a/src/hex/hex.h b/src/hex/hex.h index d3f94c5..8d85c39 100644 --- a/src/hex/hex.h +++ b/src/hex/hex.h @@ -14,9 +14,29 @@ namespace arduino { namespace hex { /* - * This library contains the methods to get board provisioning id + * This library contains the methods to hex encode a buffer into a String + * and vice-versa */ - String encode(uint8_t* in, uint32_t size); + String encode(const uint8_t* in, uint32_t size); + String encodeUpper(const uint8_t* in, uint32_t size); + + bool decode(const String in, uint8_t* out, uint32_t size); + + class THEXT { + + public: + static inline String encode(const uint8_t* in, uint32_t size) { + return arduino::hex::encode(in, size); + } + static inline String encodeUpper(const uint8_t* in, uint32_t size) { + return arduino::hex::encodeUpper(in, size); + } + + static inline bool decode(const String in, uint8_t* out, uint32_t size) { + return arduino::hex::decode(in, out, size); + } + + }; }} // arduino::hex