Skip to content

Commit 75a6b17

Browse files
authored
Merge pull request #12 from pennam/chex
Refactor hex library
2 parents c83ddf2 + c661fd4 commit 75a6b17

File tree

11 files changed

+217
-23
lines changed

11 files changed

+217
-23
lines changed

extras/test/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@ set(TEST_SRCS
2626
src/crc32/test_crc32.cpp
2727
src/crc16/test_crc16.cpp
2828
src/sha256/test_sha256.cpp
29+
src/hex/test_hex.cpp
2930
)
3031

3132
set(TEST_DUT_SRCS
3233
../../src/crc/crc32.cpp
3334
../../src/crc/crc16.cpp
34-
../../src/sha256/SHA256.cpp
3535
../../src/sha256/sha2.c
36+
../../src/hex/chex.h
3637
)
3738

3839
##########################################################################

extras/test/src/hex/test_hex.cpp

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
This file is part of the Arduino_CloudUtils library.
3+
4+
Copyright (c) 2024 Arduino SA
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
#include <catch2/catch_test_macros.hpp>
12+
13+
#include <hex/chex.h>
14+
15+
SCENARIO( "HEX encoding test" ) {
16+
/* check all possible 16-bit values in network byte order */
17+
unsigned i;
18+
for(i = 0; i <= 0xffff; ++i){
19+
/* encode to hex string using our implementation */
20+
const unsigned char org[2] = {(unsigned char)(i>>8), (unsigned char)i};
21+
char hex[5] = {0,0,0,0,0};
22+
chex_encode(hex, sizeof(hex), org, sizeof(org));
23+
24+
/* decode from hex string using a function from the standard library */
25+
unsigned char bin[2] = {0,0};
26+
int n = sscanf(hex, "%02hhx%02hhx", bin, bin+1);
27+
REQUIRE(n == sizeof(bin));
28+
29+
/* decoded matches the original */
30+
REQUIRE(memcmp(org, bin, sizeof(bin)) == 0);
31+
}
32+
REQUIRE(i == 0x10000);
33+
}
34+
35+
SCENARIO( "HEX decoding test" ) {
36+
/* check all possible 16-bit values in network byte order */
37+
unsigned i;
38+
for(i = 0; i <= 0xffff; ++i){
39+
/* encode to hex string using a function from the standard library */
40+
char hex[5] = {0,0,0,0,0};
41+
snprintf(hex, sizeof(hex), "%02hhX%02hhx", (unsigned char)(i>>8), (unsigned char)i);
42+
43+
/* decode from hex string using our implementation */
44+
unsigned char bin[2];
45+
unsigned n = chex_decode(bin, sizeof(bin), hex, sizeof(hex));
46+
REQUIRE(n == sizeof(bin));
47+
48+
/* decoded matches the original */
49+
const unsigned char org[2] = {(unsigned char)(i>>8), (unsigned char)i};
50+
REQUIRE(memcmp(org, bin, sizeof(bin)) == 0);
51+
}
52+
REQUIRE(i == 0x10000);
53+
}

src/Arduino_HEX.h

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
#pragma once
1111

1212
#include "./hex/hex.h"
13+
using namespace hex;

src/bpid/bpid.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ namespace arduino { namespace bpid {
4141
uint8_t out[SHA256::HASH_SIZE];
4242
arduino::sha256::sha256(data, sizeof(data), out);
4343
return arduino::hex::encode(out, sizeof(out));
44-
return String("");
4544
}
4645

4746
}} // arduino::bpid

src/bpid/csn.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
#include "csn.h"
12+
#include "hex/hex.h"
1213

1314
namespace arduino { namespace csn {
1415

@@ -22,7 +23,7 @@ namespace arduino { namespace csn {
2223
return false;
2324
}
2425
SecureElement se;
25-
if (!se.begin() || !se.serialNumber(in)) {
26+
if (!se.begin() || !arduino::hex::decode(se.serialNumber(), in, size)) {
2627
return false;
2728
}
2829
return true;

src/bpid/csn.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,21 @@
2424
defined(ARDUINO_OPTA) || \
2525
defined(ARDUINO_GIGA)
2626
#include <Arduino_SecureElement.h>
27-
#define CRYPTO_SN_SIZE 0
27+
#define CRYPTO_SN_SIZE 9
2828
#elif defined(ARDUINO_PORTENTA_C33) || \
2929
defined(ARDUINO_NICLA_VISION)
3030
#include <Arduino_SecureElement.h>
31-
#define CRYPTO_SN_SIZE 0
31+
#define CRYPTO_SN_SIZE 18
3232
#elif defined(ARDUINO_UNOR4_WIFI)
3333
#include <Arduino_SecureElement.h>
34-
#define CRYPTO_SN_SIZE 0
34+
#define CRYPTO_SN_SIZE 6
3535
#else
3636
#define CRYPTO_SN_SIZE 0
3737
#endif
3838

3939
namespace arduino { namespace csn {
4040
/*
41-
* This library contains the methods to get board microcontroller id
41+
* This library contains the methods to get crypto serial number
4242
*/
4343

4444
bool get(uint8_t *in, uint32_t size);

src/bpid/ucid.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212

1313
#include <Arduino.h>
1414

15-
#if defined(ARDUINO_SAMD_NANO_33_IOT) || \
16-
defined(ARDUINO_SAMD_MKRWIFI1010) || \
17-
defined(ARDUINO_SAMD_MKRGSM1400) || \
18-
defined(ARDUINO_SAMD_MKRWAN1300) || \
19-
defined(ARDUINO_SAMD_MKRWAN1310) || \
20-
defined(ARDUINO_SAMD_MKRNB1500) || \
15+
#if defined(ARDUINO_SAMD_NANO_33_IOT) || \
16+
defined(ARDUINO_SAMD_MKRWIFI1010) || \
17+
defined(ARDUINO_SAMD_MKRGSM1400) || \
18+
defined(ARDUINO_SAMD_MKRWAN1300) || \
19+
defined(ARDUINO_SAMD_MKRWAN1310) || \
20+
defined(ARDUINO_SAMD_MKRNB1500) || \
2121
defined(ARDUINO_SAMD_MKR1000)
2222
#define UC_UID_SIZE 16
2323
#elif defined(ARDUINO_PORTENTA_H7_M7) || \

src/hex/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# chex
2+
3+
[chex.h](chex.h) file implement hex encoding/decoding basic functions by Tero 'stedo' Liukko under a MIT license. https://github.com/stedonet/chex

src/hex/chex.h

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
MIT License
3+
4+
Copyright (c) 2022 Tero 'stedo' Liukko. https://github.com/stedonet/chex
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.
23+
*/
24+
25+
#ifndef STEDO_CHEX_H
26+
#define STEDO_CHEX_H
27+
28+
/**
29+
* @brief check whether given ASCII character is a hexadecimal digit
30+
* @param[in] h ASCII character to decode
31+
* @return TRUE if h is hexadecimal, FALSE otherwise
32+
**/
33+
#pragma GCC diagnostic push
34+
#pragma GCC diagnostic ignored "-Wunused-function"
35+
static unsigned chex_isxdigit(unsigned h){
36+
unsigned char n09 = h - '0';
37+
unsigned char nAF = (h | 0x20) - 'a';
38+
return (n09 <= (9 - 0)) || (nAF <= (0xf - 0xa));
39+
}
40+
#pragma GCC diagnostic pop
41+
42+
/**
43+
* @brief encode nibble to hexadecimal ASCII character
44+
* @param[in] nibble value to encode
45+
* @return hexadecimal ASCII value
46+
* @note the four most significant bits are ignored
47+
**/
48+
static char chex_toxdigit(unsigned nibble){
49+
const char* lut = "0123456789abcdef";
50+
return lut[nibble & 0xf];
51+
}
52+
53+
54+
/**
55+
* @brief decode a single case-insensitive hexadecimal ASCII character to its decimal value
56+
* @param[in] h ASCII character to decode
57+
* @return decimal value of the input
58+
* @note the input is assumed to be a valid
59+
**/
60+
static unsigned char chex_fromxdigit(unsigned h){
61+
return ((h & 0xf) + (h >> 6) * 9);
62+
}
63+
64+
65+
/**
66+
* @brief encode an array of bytes to an array of hexadecimal ASCII characters
67+
* @param[out] hex buffer to write to
68+
* @param[in] hlen maximum number of characters to write
69+
* @param[in] bin array of bytes to encode
70+
* @param[in] blen number of bytes to encode
71+
* @return number of characters written
72+
* @note null terminator is not included in the output
73+
**/
74+
static unsigned chex_encode(char* hex, unsigned hlen, const void* bin, unsigned blen){
75+
const unsigned char* b = (const unsigned char*)bin;
76+
unsigned i, j;
77+
for(i = 0, j = 0; (i < blen) && (j+1 < hlen); ++i, j+=2){
78+
hex[j+0] = chex_toxdigit(b[i]>>4);
79+
hex[j+1] = chex_toxdigit(b[i]>>0);
80+
}
81+
return j;
82+
}
83+
84+
85+
/**
86+
* @brief decode an array of hexadecimal ASCII characters to an array of bytes
87+
* @param[out] bin buffer to write to
88+
* @param[in] blen maximum number of bytes to write
89+
* @param[in] hex array of hex characters to decode
90+
* @param[in] hlen number of hex characters to decode
91+
* @return number of bytes written
92+
* @note hex input is assumed valid and its length a multiple of two
93+
**/
94+
static unsigned chex_decode(void* bin, unsigned blen, const char* hex, unsigned hlen){
95+
unsigned i, j;
96+
for(i = 0, j = 0; (i < blen) && (j+1 < hlen); ++i, j+=2){
97+
unsigned char hi = chex_fromxdigit(hex[j+0]);
98+
unsigned char lo = chex_fromxdigit(hex[j+1]);
99+
((unsigned char*)bin)[i] = (hi << 4) | lo;
100+
}
101+
return i;
102+
}
103+
104+
#endif /* STEDO_CHEX_H */

src/hex/hex.cpp

+20-8
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,30 @@
99
*/
1010

1111
#include "hex.h"
12+
#include "chex.h"
1213

1314
namespace arduino { namespace hex {
1415

15-
String encode(uint8_t* in, uint32_t size) {
16-
String out;
17-
out.reserve((size * 2) + 1);
16+
String encode(const uint8_t* in, uint32_t size) {
17+
char out[(size * 2) + 1];
18+
unsigned int byteNumber;
19+
byteNumber = chex_encode(out, sizeof(out), in, size);
20+
out[byteNumber] = 0;
21+
return String(out);
22+
}
23+
24+
String encodeUpper(const uint8_t* in, uint32_t size) {
25+
String out = encode(in, size);
26+
out.toUpperCase();
27+
return out;
28+
}
1829

19-
char *ptr = out.begin();
20-
for (uint32_t i = 0; i < size; i++) {
21-
ptr += sprintf(ptr, "%02X", in[i]);
22-
}
23-
return String(out.c_str());
30+
bool decode(const String in, uint8_t* out, uint32_t size) {
31+
unsigned int byteNumber;
32+
byteNumber = chex_decode(out, size, in.begin(), in.length());
33+
Serial.println(byteNumber);
34+
Serial.println(in.length());
35+
return byteNumber * 2 == in.length();
2436
}
2537

2638
}} // arduino::hex

src/hex/hex.h

+22-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,29 @@
1414

1515
namespace arduino { namespace hex {
1616
/*
17-
* This library contains the methods to get board provisioning id
17+
* This library contains the methods to hex encode a buffer into a String
18+
* and vice-versa
1819
*/
1920

20-
String encode(uint8_t* in, uint32_t size);
21+
String encode(const uint8_t* in, uint32_t size);
22+
String encodeUpper(const uint8_t* in, uint32_t size);
23+
24+
bool decode(const String in, uint8_t* out, uint32_t size);
25+
26+
class THEXT {
27+
28+
public:
29+
static inline String encode(const uint8_t* in, uint32_t size) {
30+
return arduino::hex::encode(in, size);
31+
}
32+
static inline String encodeUpper(const uint8_t* in, uint32_t size) {
33+
return arduino::hex::encodeUpper(in, size);
34+
}
35+
36+
static inline bool decode(const String in, uint8_t* out, uint32_t size) {
37+
return arduino::hex::decode(in, out, size);
38+
}
39+
40+
};
2141

2242
}} // arduino::hex

0 commit comments

Comments
 (0)