Question

I am trying to convert a base64 string back to a GUID style hex number in python and having issues.

Base64 encoded string is: bNVDIrkNbEySjZ90ypCLew==

And I need to get it back to: 2243d56c-0db9-4c6c-928d-9f74ca908b7b

I can do it with the following PHP code but can't work out how to to it in Python

function Base64ToGUID($guid_b64) {
    $guid_bin = base64_decode($guid_b64);

    return join('-', array(
      bin2hex(strrev(substr($guid_bin, 0, 4))),
      bin2hex(strrev(substr($guid_bin, 4, 2))),
      bin2hex(strrev(substr($guid_bin, 6, 2))),
      bin2hex(substr($guid_bin, 8, 2)),
      bin2hex(substr($guid_bin, 10, 6))
    ));
  }

Here is the GUIDtoBase64 version:

function GUIDToBase64($guid) {
    $guid_b64 = '';
    $guid_parts = explode('-', $guid);

    foreach ($guid_parts as $k => $part) {
      if ($k < 3)
        $part = join('', array_reverse(str_split($part, 2)));

      $guid_b64 .= pack('H*', $part);
    }

    return base64_encode($guid_b64);
  }

Here are some of the results using some of the obvious and not so obvious options:

import base64
import binascii
>>> base64.b64decode("bNVDIrkNbEySjZ90ypCLew==")
'l\xd5C"\xb9\rlL\x92\x8d\x9ft\xca\x90\x8b{'
>>> binascii.hexlify(base64.b64decode("bNVDIrkNbEySjZ90ypCLew=="))
'6cd54322b90d6c4c928d9f74ca908b7b'
Was it helpful?

Solution

Python port of the existing function (bitstring required)

import bitstring, base64

def base64ToGUID(b64str):
  s = bitstring.BitArray(bytes=base64.b64decode(b64str)).hex
  def rev2(s_):
    def chunks(n):
      for i in xrange(0, len(s_), n):
          yield s_[i:i+n]
    return "".join(list(chunks(2))[::-1])
  return "-".join([rev2(s[:8]),rev2(s[8:][:4]),rev2(s[12:][:4]),s[16:][:4],s[20:]])

assert base64ToGUID("bNVDIrkNbEySjZ90ypCLew==") == "2243d56c-0db9-4c6c-928d-9f74ca908b7b"

OTHER TIPS

First off, the b64 string and the resultant GUID doesn't match if we decode properly.

>>> import uuid
>>> import base64
>>> u = uuid.UUID("2243d56c-0db9-4c6c-928d-9f74ca908b7b")
>>> u
UUID('2243d56c-0db9-4c6c-928d-9f74ca908b7b')
>>> u.bytes
'"C\xd5l\r\xb9Ll\x92\x8d\x9ft\xca\x90\x8b{'
>>> base64.b64encode(u.bytes)
'IkPVbA25TGySjZ90ypCLew=='
>>> b = base64.b64decode('bNVDIrkNbEySjZ90ypCLew==')
>>> u2 = uuid.UUID(bytes=b)
>>> print u2
6cd54322-b90d-6c4c-928d-9f74ca908b7b

The base64 encoded version of the resultant GUID you posted is wrong. I'm not sure I understand the way you're encoding the GUID in the first place.

Python has in its arsenal all the tools required for you to be able to answer this problem. However, here's the rough scratching I did in a python terminal:

import uuid
import base64

base64_guid = "bNVDIrkNbEySjZ90ypCLew=="
bin_guid = base64.b64decode(base64_guid)
guid = uuid.UUID(bytes=bin_guid)
print guid

This code should give you enough of a hint to build your own functions. Don't forget, the python shell gives you a powerful tool to test and play with code and ideas. I would investigate using something like IPython notebooks.

I needed to do this to decode a BASE64 UUID that had been dumped from Mongodb. Originally the field had been created by Mongoose. The code I used, based on the code by @tpatja is here:

def base64ToGUID(b64str):
  try:
    bytes=base64.urlsafe_b64decode(b64str)
  except Exception as e:
    print("Can't decode base64 ", e)
  s = bitstring.BitArray(bytes).hex
  return "-".join([s[:8],s[8:][:4],s[12:][:4],s[16:][:4],s[20:]])

Based on good answers above, I wrote a version that does not require the bitstring package and includes validations and support for more input options.

import base64
import regex
import uuid

from typing import Optional


def to_uuid(obj) -> Optional[uuid.UUID]:
    if obj is None:
        return None
    elif isinstance(obj, uuid.UUID):
        return obj
    elif isinstance(obj, str):
        if regex.match(r'[0-9a-fA-F]{8}[-]{0,1}[0-9a-fA-F]{4}[-]{0,1}[0-9a-fA-F]{4}[-]{0,1}[0-9a-fA-F]{4}[-]{0,1}[0-9a-fA-F]{12}', obj):
            return uuid.UUID(hex=obj)
        elif regex.match(r'[0-9a-zA-Z\+\/]{22}[\=]{2}', obj):
            b64_str = base64.b64decode(obj).hex()
            uid_str = '-'.join([b64_str[:8], b64_str[8:][:4], b64_str[12:][:4], b64_str[16:][:4], b64_str[20:]])
            return uuid.UUID(hex=uid_str)
        raise ValueError(f'{obj} is not a valid uuid/guid')
    else:
        raise ValueError(f'{obj} is not a valid uuid/guid')
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top