encodes data according to rfc4648 the data is first transformed to binary and appended with binary digits so that its length becomes a multiple of 6 then each 6 binary digits will match a character in the b64charset string the number of appended binary digits would later determine how many signs should be added the padding for every 2 binary digits added a sign is added in the output we can add any binary digits to make it a multiple of 6 for instance consider the following example aa 0010100100101001 001010 010010 1001 as can be seen above 2 more binary digits should be added so there s 4 possibilities here 00 01 10 or 11 that being said base64 encoding can be used in steganography to hide data in these appended digits from base64 import b64encode a bthis pull request is part of hacktoberfest20 b bhttps tools ietf orghtmlrfc4648 c ba base64encodea b64encodea true base64encodeb b64encodeb true base64encodec b64encodec true base64encodeabc traceback most recent call last typeerror a byteslike object is required not str make sure the supplied data is a byteslike object the padding that will be added later append binarystream with arbitrary binary digits 0 s by default to make its length a multiple of 6 encode every 6 binary digits to their corresponding base64 character decodes data according to rfc4648 this does the reverse operation of base64encode we first transform the encoded data back to a binary stream take off the previously appended binary digits according to the padding at this point we would have a binary stream whose length is multiple of 8 the last step is to convert every 8 bits to a byte from base64 import b64decode a vghpcybwdwxsihjlcxvlc3qgaxmgcgfydcbvzibiywnrdg9izxjmzxn0mjah b ahr0chm6ly90b29scy5pzxrmlm9yzy9odg1sl3jmyzq2ndg c qq base64decodea b64decodea true base64decodeb b64decodeb true base64decodec b64decodec true base64decodeabc traceback most recent call last assertionerror incorrect padding make sure encodeddata is either a string or a byteslike object in case encodeddata is a byteslike object make sure it contains only ascii characters so we convert it to a string object check if the encoded string contains non base64 characters check the padding remove padding if there is one encodes data according to rfc4648 the data is first transformed to binary and appended with binary digits so that its length becomes a multiple of 6 then each 6 binary digits will match a character in the b64_charset string the number of appended binary digits would later determine how many signs should be added the padding for every 2 binary digits added a sign is added in the output we can add any binary digits to make it a multiple of 6 for instance consider the following example aa 0010100100101001 001010 010010 1001 as can be seen above 2 more binary digits should be added so there s 4 possibilities here 00 01 10 or 11 that being said base64 encoding can be used in steganography to hide data in these appended digits from base64 import b64encode a b this pull request is part of hacktoberfest20 b b https tools ietf org html rfc4648 c b a base64_encode a b64encode a true base64_encode b b64encode b true base64_encode c b64encode c true base64_encode abc traceback most recent call last typeerror a bytes like object is required not str make sure the supplied data is a bytes like object the padding that will be added later append binary_stream with arbitrary binary digits 0 s by default to make its length a multiple of 6 encode every 6 binary digits to their corresponding base64 character decodes data according to rfc4648 this does the reverse operation of base64_encode we first transform the encoded data back to a binary stream take off the previously appended binary digits according to the padding at this point we would have a binary stream whose length is multiple of 8 the last step is to convert every 8 bits to a byte from base64 import b64decode a vghpcybwdwxsihjlcxvlc3qgaxmgcgfydcbvzibiywnrdg9izxjmzxn0mjah b ahr0chm6ly90b29scy5pzxrmlm9yzy9odg1sl3jmyzq2ndg c qq base64_decode a b64decode a true base64_decode b b64decode b true base64_decode c b64decode c true base64_decode abc traceback most recent call last assertionerror incorrect padding make sure encoded_data is either a string or a bytes like object in case encoded_data is a bytes like object make sure it contains only ascii characters so we convert it to a string object check if the encoded string contains non base64 characters check the padding remove padding if there is one
B64_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"


def base64_encode(data: bytes) -> bytes:
    
    
    if not isinstance(data, bytes):
        msg = f"a bytes-like object is required, not '{data.__class__.__name__}'"
        raise TypeError(msg)

    binary_stream = "".join(bin(byte)[2:].zfill(8) for byte in data)

    padding_needed = len(binary_stream) % 6 != 0

    if padding_needed:
        
        padding = b"=" * ((6 - len(binary_stream) % 6) // 2)

        
        
        binary_stream += "0" * (6 - len(binary_stream) % 6)
    else:
        padding = b""

    
    return (
        "".join(
            B64_CHARSET[int(binary_stream[index : index + 6], 2)]
            for index in range(0, len(binary_stream), 6)
        ).encode()
        + padding
    )


def base64_decode(encoded_data: str) -> bytes:
    
    
    if not isinstance(encoded_data, bytes) and not isinstance(encoded_data, str):
        msg = (
            "argument should be a bytes-like object or ASCII string, "
            f"not '{encoded_data.__class__.__name__}'"
        )
        raise TypeError(msg)

    
    
    if isinstance(encoded_data, bytes):
        try:
            encoded_data = encoded_data.decode("utf-8")
        except UnicodeDecodeError:
            raise ValueError("base64 encoded data should only contain ASCII characters")

    padding = encoded_data.count("=")

    
    if padding:
        assert all(
            char in B64_CHARSET for char in encoded_data[:-padding]
        ), "Invalid base64 character(s) found."
    else:
        assert all(
            char in B64_CHARSET for char in encoded_data
        ), "Invalid base64 character(s) found."

    
    assert len(encoded_data) % 4 == 0 and padding < 3, "Incorrect padding"

    if padding:
        
        encoded_data = encoded_data[:-padding]

        binary_stream = "".join(
            bin(B64_CHARSET.index(char))[2:].zfill(6) for char in encoded_data
        )[: -padding * 2]
    else:
        binary_stream = "".join(
            bin(B64_CHARSET.index(char))[2:].zfill(6) for char in encoded_data
        )

    data = [
        int(binary_stream[index : index + 8], 2)
        for index in range(0, len(binary_stream), 8)
    ]

    return bytes(data)


if __name__ == "__main__":
    import doctest

    doctest.testmod()