I am trying to decode an re-encode a bytesytring using passlibs base64 encoding:
from passlib.utils import binary
engine = binary.Base64Engine(binary.HASH64_CHARS)
s2 = engine.encode_bytes(engine.decode_bytes(b"1111111111111111111111w"))
print(s2)
This prints b'1111111111111111111111A' which is of course not what I expected. The last character is different.
Where is my mistake? Is this a bug?
No, it's not a bug.
In all variants of Base64, every encoded character represents just 6 bits and depending on the number of bytes encoded you can end up with 0, 2 or 4 insignificant bits on the end.
In this case the encoded string
1111111111111111111111wis 23 characters long, that means 23*6 = 138 bits which can be decoded to 17 bytes (136 bits) + 2 insignifcant bits.The encoding you use here is not Base64 but Hash64
In the character map
HASH64_CHARS = u("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")we find
Aon index 12 (001100) andwon index 60 (111100)Now the 'trick' here is, that
binary.Base64Engine(binary.HASH64_CHARS)has a default parameterbig=False, which means that the encoding is done in little endian format by default.In your example it means that
wis001111andAis001100. During decoding the last two bits are cut off as they are not needed as explained above. When you encode it again,Ais taken as the first character in the character map that can be used two encode0011plus two insignifiant bits.