Eric Jin
Eric Jin

Reputation: 3924

How do I encode hexadecimal to base64 in python?

If I try to do:

from base64 import b64encode
b64encode('ffffff')

I get this error:

Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    base64.b64encode('ffffff')
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/base64.py", line 58, in b64encode
    encoded = binascii.b2a_base64(s, newline=False)
TypeError: a bytes-like object is required, not 'str'

Because it said bytes-like object I then tried this:

b64encode(bytes('ffffff'))

Which failed.

Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    b64encode(bytes('ffffff'))
TypeError: string argument without an encoding

Finally, using the .encode('utf-8') function:

b64encode('ffffff'.encode('utf-8'))

With incorrect output b'ZmZmZmZm', the correct base64 encoding is ////.

I already know how to decode b64 to hex so don't say how to do that.

Edit: This question got flagged for being the same as converting hex strings to hex bytes. This involves base64.

Upvotes: 1

Views: 5063

Answers (2)

match
match

Reputation: 11060

To fully go from the string ffffff to base64 of the hex value, you need to run it through some encoding and decoding, using the codecs module:

import codecs
# Convert string to hex
hex = codecs.decode('ffffff', 'hex')
# Encode as base64 (bytes)
codecs.encode(hex, 'base64')

For an odd-length string like 0xfffff you need to put a zero at the beginning of the hex string (0x0fffff), otherwise python will give you an error.

Upvotes: 3

Torxed
Torxed

Reputation: 23480

Here's an alternative to using codecs.
This one is a bit less readable, but works great and hopefully teaches you how codecs, hex and integers work. (word of caution, works on odd lengths, but will ignore the odd byte-string-representation)

import struct
s = 'ffffff'
b''.join([struct.pack('B', int(''.join(x), 16)) for x in zip(s[0::2], s[1::2])])

Which should give you b'\xff\xff\xff'.

Your main problem is probably that you think 'ffffff' represents the values 255, 255, 255. Which they don't. They're still in a string format with the letters ff. Subsequently you need to parse/convert the string representation of hex, into actual hex. We can do this by first passing the string through int() which can intemperate hex in string representation format.

You will need to convert each pair of ff individually by doing int('ff', 16) which tells Python to intemperate the string as a base-16 integer (hex-numbers).

And then convert that integer into a bytes like object representing that integer. That's where struct.pack comes in. It's meant for exactly this.

struct.pack('B', 255) # 255 is given to us by int('ff', 16)

Essentially, 'B' tells Python to pack the value 255 into a 1-byte-object, in this case, that gives us b'\xff' which is your end goal. Now, do this for every 2-pair of letters in your original data.


This is more of a manual approach where you'll iterate over 2 characters in the string at a time, and use the above description to bundle them into what you expect them to be. Or just use codecs, either way works.

Expanded version of the above oneliner:

import struct
hex_string = 'ffffff'
result = b''
for pair in zip(hex_string[0::2], hex_string[1::2]):
    value = int(''.join(pair), 16)
    result += struct.pack('B', value)

At the very least, I hope this explains how hex works on a practical level. And how the computer interpenetrates hour humanly readable version of bits and bytes.

Upvotes: 1

Related Questions