1

I am trying some simple code - decode logic using the standard browser functionalities atob() and btoa() and I am encountering behaviors I can not fully understand.

I have written a very simple test case

 it('converts from base64 to ascii', () => {
    const stringA = 'I am Enrico in Asci';
    const stringB = atob(stringA);
    const stringA1 = btoa(stringB);
    console.log('My ASCCI to binary and viceversa', stringA1);
    expect(stringA1).toBe(stringA);
  });

The test case fails. What I see on the console of Chrome is

Expected 'IamEnricoinAscg=' to be 'I am Enrico in Asci'.

Apparently all spaces have gone and end character is wrong. Any help is appreciated.

Picci
  • 16,775
  • 13
  • 70
  • 113
  • 1
    You've got your `atob` and `btoa` the wrong way round. stringB use `btoa` and stringA1 use `atob`... And easy way to remember, think the source as always been binary, even if a string.. Or another way of thinking of it, A = Encoded Base64, B = The Data. Stupid names for Base64 encoding I know.. – Keith Dec 08 '17 at 10:34
  • Yes, it works. Thanks. I was stupidly imagining that `atob` ascii to base64 and viceversa. – Picci Dec 08 '17 at 10:40

3 Answers3

1

Just do it in the proper order ;)

    const stringA = 'I am Enrico in Asci';
    const stringB = btoa(stringA);
    const stringA1 = atob(stringB);
    console.log('stringA', stringA);
    console.log('stringA1', stringA1);
    console.log('equals', stringA === stringA1);
sjahan
  • 5,720
  • 3
  • 19
  • 42
  • `btoa` give a longer string, so the proper order is to first use `atob` and handle (send, download, store) shorter strings. – Dan Froberg Jul 30 '23 at 18:29
0

There is two problems to solve!

  1. The atob() decodes ascii to bytes, where ascii is restricted to six bits, that is Base64. Four six-bit Base64 characters fit exactly into three eight-bit bytes. If it is not a multiple of four the input has to be padded with / characters. You then simply trim the / characters from the output of btoa(). To pad with = is not allowed in atob(), because the parameter has to be Base64 and that character is not included.

  2. The atob() function in JavaScript remove spaces from the input string because Base64 encoding does not support spaces. Allowed characters are A-Z, a-z, 0-9, +, and /. So you can replace the spaces by + and replace it back to space after all is done.

Solution

const stringA = 'I am Enrico in Asci';

//% = modulo = remainder of division by 4. 
//Fill the rest to add up to a group of 4.
const pads = "///".slice(0, 4 - stringA.length % 4);

//replace illegal characters by '+' and add pads.
const stringB = atob(stringA.replaceAll(' ', '+') + pads);
const stringA1 = btoa(stringB);

//replace all '+' and '/' back to ' ' and trim.
const stringA2 = stringA1.replaceAll(/[+\/]/g, ' ').trim();
console.log(stringA === stringA2);

You have to replace illegal characters by +. If you have more than one illegal character you need to send two strings. The second string then has legal Base64 characters for each + to be replaced with its illegal character mapped to those legal Base64 characters (that are indexes into a decoding string). In that way you can have 62 characters more.

Dan Froberg
  • 168
  • 8
-4
const stringA1 = btoa(stringB);

you define constant , there must be var

var stringA1 = btoa(stringB);
  • A string is always constant in Javascript. It can't be changed by indexing. For safety we use `const` when the string is not meant to be replaced. – Dan Froberg Jul 30 '23 at 18:38