32

Needing to convert a Base64 string to Hexadecimal with javascript.

Example:

var base64Value = "oAAABTUAAg=="

Need conversion method

Output (Decoded data (hexadecimal)) A0000005350002

I know this is correct because I can use this website http://tomeko.net/online_tools/base64.php?lang=en

and punch in Base64 string of oAAABTUAAg== and get A0000005350002

What have I tried?

https://github.com/carlo/jquery-base64
https://jsfiddle.net/gabrieleromanato/qaght/

I have found a lot of questions

Klesun
  • 12,280
  • 5
  • 59
  • 52

5 Answers5

54

Why not try the following code?:

const buffer = Buffer.from(rawData, 'base64');
const bufString = buffer.toString('hex');
Ommadawn
  • 2,450
  • 3
  • 24
  • 48
user11429314
  • 549
  • 4
  • 2
  • 3
    Not only is this much cleaner but this is the correct answer for node backend code because atob is not available without an npm module. – ScottWasserman May 20 '19 at 18:08
36

atob() then charCodeAt() will give you binary & toString(16) will give you hex.

function base64ToHex(str) {
  const raw = atob(str);
  let result = '';
  for (let i = 0; i < raw.length; i++) {
    const hex = raw.charCodeAt(i).toString(16);
    result += (hex.length === 2 ? hex : '0' + hex);
  }
  return result.toUpperCase();
}

console.log(base64ToHex("oAAABTUAAg=="));
Snowman
  • 31,411
  • 46
  • 180
  • 303
user3094755
  • 1,561
  • 16
  • 20
  • Here is a one liner to reverse using es6: hexToB64 = hex => btoa(String.fromCharCode(...Array.apply(null, Array(hex.length / 2)).map((_,i) => parseInt(hex[i*2] + hex[i*2+1],16)))) – SlimSim Aug 07 '17 at 01:11
  • For node users - var raw = new Buffer(base64, 'base64').toString('binary'); – m4heshd Apr 15 '18 at 20:46
  • 1
    Get hex in node 10: Buffer.from(base64, 'base64').toString('hex') – fast Apr 24 '19 at 13:00
9

Here is my vanilla JavaScript solution that does not use atob and Buffer. Supports separator, suitable for binary data and React Native, relatively high performance.

Usage :

base64ToHex( 'MTIzYWJjIDotKQ==', '-' )
// returns '31-32-33-61-62-63-20-3a-2d-29'

Code :

/* Convert base64 data to hex string.  https://stackoverflow.com/a/57909068/893578
 *   txt : Base64 string.
 *   sep : Hex separator, e.g. '-' for '1a-2b-3c'.  Default empty.
 */
const base64ToHex = ( () => {
   // Lookup tables
   const values = [], output = [];

   // Main converter
   return function base64ToHex ( txt, sep = '' ) {
      if ( output.length <= 0 ) populateLookups();
      const result = [];
      let v1, v2, v3, v4;
      for ( let i = 0, len = txt.length ; i < len ; i += 4 ) {
         // Map four chars to values.
         v1 = values[ txt.charCodeAt( i   ) ];
         v2 = values[ txt.charCodeAt( i+1 ) ];
         v3 = values[ txt.charCodeAt( i+2 ) ];
         v4 = values[ txt.charCodeAt( i+3 ) ];
         // Split and merge bits, then map and push to output.
         result.push(
            output[ ( v1 << 2) | (v2 >> 4) ],
            output[ ((v2 & 15) << 4) | (v3 >> 2) ],
            output[ ((v3 &  3) << 6) |  v4 ]
         );
      }
      // Trim result if the last values are '='.
      if ( v4 === 64 ) result.splice( v3 === 64 ? -2 : -1 );
      return result.join( sep );
   };

   function populateLookups () {
      const keys = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
      for ( let i = 0 ; i < 256 ; i++ ) {
         output.push( ( '0' + i.toString( 16 ) ).slice( -2 ) );
         values.push( 0 );
      }
      for ( let i = 0 ; i <  65 ; i++ )
         values[ keys.charCodeAt( i ) ] = i;
   }
} )();

Demo:

const [ txt, b64, hex, sep ] = document.querySelectorAll( 'input, select' );

function txtOnInput ({ target: { value }}) {
   hex.value = base64ToHex( b64.value = btoa( value ), sep.value ).toUpperCase();
}

function b64OnInput ({ target: { value }}) {
   hex.value = base64ToHex( value, sep.value ).toUpperCase();
   txt.value = atob( value );
}

txtOnInput({target:txt});

// Different coding style, same result.
function base64ToHex ( txt, sep = '' ) {
   let { val, out } = base64ToHex, v1, v2, v3, v4, result = [];
   if ( ! base64ToHex.val ) { // Populate lookup tables.
      out = base64ToHex.out = [];
      val = base64ToHex.val = Array( 255 ).fill( 0 );
      const keys = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
      for ( let i = 0 ; i < 256 ; i++ ) out.push( ( '0' + i.toString(16) ).slice( -2 ) );
      for ( let i = 0 ; i <  65 ; i++ ) val[ keys.charCodeAt( i ) ] = i;
   }
   for ( let i = 0, len = txt.length ; i < len ; i += 4 ) {
      v1 = val[ txt.charCodeAt( i   ) ]; // Map four chars to values.
      v2 = val[ txt.charCodeAt( i+1 ) ];
      v3 = val[ txt.charCodeAt( i+2 ) ];
      v4 = val[ txt.charCodeAt( i+3 ) ];
      result.push( out[ (v1 << 2) | (v2 >> 4) ], // Split values, map to output.
                   out[ ((v2 & 15) << 4) | (v3 >> 2) ],
                   out[ ((v3 & 3) << 6) | v4 ] );
   } // After loop ended: Trim result if the last values are '='.
   if ( v4 === 64 ) result.splice( v3 === 64 ? -2 : -1 );
   return result.join( sep ); // Array is fast.  String append = lots of copying.
}
label { display: block; height: 1em; }
input, select { position: absolute; left: 5em; width: calc( 100% - 6em ) }
input[readonly] { background: #D8D8D8; }
<label>Ascii <input oninput='txtOnInput(event)' value='123abc :-)'></label><br>
<label>Base64 <input oninput='b64OnInput(event)'></label><br>
<label>Hex    <input readonly></label><br>
<label> <select onchange='txtOnInput({target:txt})'>
<option value=''>(None)<option value=' ' selected>(Space)<option value='-'>-</select></label><br>

Note: this is done for geisterfurz007 because react-native-fs yields base64 for binary files, and (s)he needs to turn that into hex string. Not that I am happy with the efficiency of existing snippets...

Sheepy
  • 17,324
  • 4
  • 45
  • 69
6

Assuming you want the hexadecimal representation as a string, the window.atob function (available in most modern browsers) is your first step - it will convert your base64 string to an ASCII string, where each character represents one byte.

At this point you split the string, grab the character code of each character, then convert that to a left-padded base-16 string.

function base64ToBase16(base64) {
  return window.atob(base64)
      .split('')
      .map(function (aChar) {
        return ('0' + aChar.charCodeAt(0).toString(16)).slice(-2);
      })
     .join('')
     .toUpperCase(); // Per your example output
}

console.log(base64ToBase16("oAAABTUAAg==")); // "A0000005350002"

(Or try it on JSBin)

Community
  • 1
  • 1
Brad Buchanan
  • 1,475
  • 1
  • 15
  • 22
2

Try

[...atob(base64Value)].map(c=> c.charCodeAt(0).toString(16).padStart(2,0)).join``

let base64Value = "oAAABTUAAg=="

let h= [...atob(base64Value)].map(c=> c.charCodeAt(0).toString(16).padStart(2,0)).join``

console.log( h.toUpperCase() );
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345