You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
51 lines
1.7 KiB
Python
51 lines
1.7 KiB
Python
"""Base32 encoding/decoding
|
|
|
|
For base32 encoding we use rfc4648, no padding, lowercase, prefixed with "b".
|
|
|
|
Base32 character set: 'abcdefghijklmnopqrstuvwxyz234567'
|
|
|
|
The Multibase format adds a "b" prefix to specify this particular encoding.
|
|
We leave the "b" prefix there because we don't want the encoded string
|
|
to start with a number (so we can use it as a URL location).
|
|
|
|
When decoding, we require it to start with a "b" -- no other multibase formats are allowed.
|
|
|
|
The decoding must be strict (it doesn't allow a 1 in place of an i, etc).
|
|
"""
|
|
|
|
from base64 import b32decode, b32encode
|
|
|
|
|
|
def base32_bytes_to_string(bytes_: bytes) -> str:
|
|
"""Encode uint8array bytes to base32 string"""
|
|
|
|
return 'b' + b32encode(bytes_).lower().strip(b'=').decode('utf-8')
|
|
|
|
|
|
def base32_string_to_bytes(string: str) -> bytes:
|
|
"""Decode base32 string to a uint8array of bytes
|
|
|
|
:raises ValidationError: if the string is bad
|
|
"""
|
|
|
|
if not string.startswith("b"):
|
|
raise ValueError(f"can't decode base32 string - it should start with a 'b'. {str}")
|
|
|
|
string = string[1:]
|
|
|
|
# this library combines padding and looseness settings into a single "loose" option, so
|
|
# we have to set "loose: true" in order to handle unpadded inputs.
|
|
# with a custom codec, loose mode:
|
|
# -- allows padding or no padding -- we have to check for this
|
|
# -- does not allow uppercase -- good
|
|
# -- does not allow 1/i substitution -- good
|
|
|
|
# make sure no padding characters are on the end
|
|
if string.endswith("="):
|
|
raise ValueError("can't decode base32 string - it contains padding characters ('=')")
|
|
|
|
pad_length = 8 - len(string) % 8
|
|
string += '=' * pad_length
|
|
|
|
return b32decode(string.upper())
|