Converting string to uint8_t array

Hi,
I am trying to get TOTP-Arduino (GitHub - lucadentella/TOTP-Arduino) library working. It works fine when I generate the byte array outside of Arduino, but the goal is to get the secret from a sqlite database/spiffs and then get the TOTP token.

The library needs a input like this:

uint8_t hmacKey[] = {0x53, 0x75, 0x70, 0x65, 0x72, 0x4c, 0x6f, 0x6e, 0x67, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74};

and I have a secret like this:

String secret = "SuperLongSecret";

What is the best approach to achieve this? I am sure I am mixing up some variable scopes and are lost in them at the moment.

Thanks,
bert

That's because a String is a char array wrapped in C++ convenience/bad-news-in-small-ram.

When programming Arduino the best is to ditch bad habits C++ String for char or byte arrays.

char * hmacKey = new char [secret.length()+1];
strcpy (hmacKey, secret.c_str());

alesam:

char * hmacKey = new char [secret.length()+1];

strcpy (hmacKey, secret.c_str());

Be carefull with that; a fixed length c-string will be prefered.

If above code is called repeatedly, it will exhaust memory in no time.

sterretje:
Be carefull with that; a fixed length c-string will be prefered.

If above code is called repeatedly, it will exhaust memory in no time.

Be careful with fixed length c-string . Buffer overrun can crush your program in no time.

If above code is called repeatedly, it will exhaust memory in no time.

Not if it's called locally.

alesam:

char * hmacKey = new char [secret.length()+1];

strcpy (hmacKey, secret.c_str());

Thanks for your feedback. I believe this is helping me to get my string into a char?

Deva_Rishi:
Not if it's called locally.

If you mean what I think that you mean, I think you're wrong. The variable that holds the pointer to dynamically allocated memory goes out of scope; but the memory itself stays allocated.

You can run the below simple test sketch (requires installation of the freeMemory library ( GitHub - mpflaga/Arduino-MemoryFree: basic functions and example to use show used RAM and use less of it.) and observe what happens

#include <MemoryFree.h>

String secret = "SuperLongSecret";

void setup()
{
  Serial.begin(57600);
  Serial.println("'new' test");
  Serial.print("len = ");
  Serial.println(secret.length());
}

void loop()
{
  char * hmacKey = new char [secret.length() + 1];
  strcpy (hmacKey, secret.c_str());

  Serial.print(F("Free RAM = ")); //F function does the same and is now a built in library, in IDE > 1.0.0
  Serial.println(freeMemory(), DEC);  // print how much RAM is available.

  delay(1000);

  if (Serial.available())
  {
    Serial.println("stopping");
    for (;;);
  }


}

Result:

'new' test
len = 15
Free RAM = 1761
Free RAM = 1743
Free RAM = 1725
Free RAM = 1707
Free RAM = 1689
Free RAM = 1671
Free RAM = 1653
Free RAM = 1635
Free RAM = 1617
Free RAM = 1599
Free RAM = 1581
Free RAM = 1563
Free RAM = 1545
Free RAM = 1527
Free RAM = 1509
Free RAM = 1491
Free RAM = 1473
Free RAM = 1455
Free RAM = 1437
stopping

Just create a char array directly instead of a pointer to a char array, the compiler has no problem with a dynamically sized char array inside a function.

  //char * hmacKey = new char [secret.length() + 1];
  char hmacKey[secret.length() + 1];

Alternatively, if possible store the original text in a char array instead of a String.

but the memory itself stays allocated

Then obviously you should destroy it after use.

Alternatively, if possible store the original text in a char array instead of a String.

This definitely the preferred method. I actually use

char macKey[secret.length() + 1];
  secret.toCharArray(macKey, secret.length() + 1);

in reply#3

Be carefull with that; a fixed length c-string will be prefered.

The issue has nothing to do with the fixed or not fixed length, but with dynamic allocation.

david_2018:

  char hmacKey[secret.length() + 1];

Is it compilable?

bert2002:
Thanks for your feedback. I believe this is helping me to get my string into a char?

Yes, and then use it as uint8_t

alesam:
Be careful with fixed length c-string . Buffer overrun can crush your program in no time.

You really do not want to play dynamic allocation in such small memory space as an Uno.
Set up your heap ahead of time if possible.

You are not programming PC's here. They have acres of memory. Most MCU's do not. Uno has 2K ram for everything.

Do you know the term "shotgun the heap"? That's what container classes do for you, there isn't much room to waste but they will waste room.

Thanks for all the feedback and discussion, I am afraid I am still a bit lost. Now the string is a char, but how do I change it into hex array? I think I am more confused than before now :smiley:

The C string is a char array with ASCII text codes (one symbol per char -- letter, number, punctuation, other) that ends with a char == 0.

char oneHundredText[ 4 ] = "100"; // chars '1', '0', '0', 0. The ones in ' ' are print literals, like marks on paper 1 0 0 three different things one after the other.

If I have a text number like "1234", I can read each char in a loop and add them in an int.

not tested at all:

int total; // default is 0
byte index; // to point into the number array
char number[ ] = "1234";
... snip ....

while ( number[ index ] > 0 )
{
total *= 10; // total = total * 10
total += number[ index++ ] - '0'; // assumes digits only
}

print total; // there's your integer, floating point is trickier to get right

bert2002:
Thanks for all the feedback and discussion, I am afraid I am still a bit lost. Now the string is a char, but how do I change it into hex array? I think I am more confused than before now :smiley:

I can't be sure of what these terms mean to you, only guess.

string is never --- a char
string is a series of chars in an array with a char == 0 to mark the end.

If you want chars which are signed 8-bit values to become bytes which are unsigned 8-bit values you just call then that by casting or define a pointer to byte and point it at the string to read bytes instead of chars... this is about making the compiler treat data differently than it was defined as, --- but the data is the same, just treated differently, no converting needed!

I suggest that you study variables in C.

Here's a page from the Arduino main site with links you could resolve a lot of confusion through, including variables.