Base64 là gì? tại sao lại là 64?

img

Khi lập trình, hay làm sysadmin, một khái niệm đâu đó với tên encode Base64 xuất hiện và không quá khó để dùng:

Lệnh trên Ubuntu Linux:

echo -n PyMi.vn | base64
UHlNaS52bg==

Hay Python3:

>>> import base64
>>> base64.b64encode("PyMi.vn")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.8/base64.py", line 58, in b64encode
    encoded = binascii.b2a_base64(s, newline=False)
TypeError: a bytes-like object is required, not 'str'
>>> base64.b64encode(b"PyMi.vn")
b'UHlNaS52bg=='

một cách nhận diện dữ liệu ở dạng Base64 là gồm ký tự từ A-Z a-z 0-9 và thường kết thúc với một vài dấu =.

Nôm na thì đơn giản, chi tiết hơn sẽ có nhiều điều thú vị hay ho rất chi này nọ.

Base64 cho phép biến dữ liệu binary thành dạng text (ASCII). Ví dụ như 1 file ảnh, logo Python, khi viết HTML có thể dùng thẻ img và đường link:

<img src="https://www.python.org/static/img/python-logo.png">

Nhưng cũng có thể biến file ảnh này dạng text và viết:

<img src="data:image/png;base64,BASE64OFIMAGE">

viết kiểu này có ưu điểm không bị phụ thuộc vào việc link ảnh sống hay chết, vì toàn bộ bức ảnh đã nằm ngay trong file HTML. Chuột phải và copy link của bức ảnh sau để thấy:

Với Base64 thu được khi tải file logo và chạy

base64 python-logo.png

Base64 được dùng phổ biến khi dùng email với từ khóa MIME, để nhúng ảnh, gửi kèm file với email.

Base64 là gì

Theo tài liệu định nghĩa Base64 RFC3548:

The Base 64 encoding is designed to represent arbitrary sequences of octets in a form that requires case sensitivity but need not be humanly readable.

Tại sao lại là 64?

Vì việc encoding sử dụng 64 ký tự (+1 ký tự = để padding).

64 ký tự gồm:

  • 26 ký tự A-Z
  • 26 ký tự a-z
  • 10 ký tự 0-9
  • +/ (hoặc thay bằng -_ khi encode URL)

Cách encode

Biểu diễn nhóm 24-bit đầu vào thành 4 ký tự đầu ra.

24 bit tạo bởi 3 byte (3 * 8 == 24) đặt cạnh nhau từ trái qua phải, sau đó chia làm 4 phần 6 bits, mỗi phần đổi bit ra số rồi tra trong bảng xem ứng với ký tự nào. Do mỗi phần có 6 bit nên có khả năng biểu diễn 2**6 = 64 ký tự.

+--first octet--+-second octet--+--third octet--+
|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
+-----------+---+-------+-------+---+-----------+
|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|
+--1.index--+--2.index--+--3.index--+--4.index--+

Đầu vào luôn cần là bội của 6 bits, nên nếu thiếu ta cần thêm vào đó các bit 0 cho đủ. Ví dụ có 4 ký tự đầu vào = 8 * 4 == 32 bits - (6 bits * 5) = 2 bits. 2 bits nên phải thêm 4 bit 0 vào sau cho đủ 6 bit.

Mỗi 24 bits đầu vào sinh ra 4 ký tự Base64, nên đầu ra nếu thiếu ký tự cần thêm các ký tự = cho đủ bội của 4 phục vụ việc decode - chuyển ngược lại từ Base64 thành binary.

Code Python để encode Base64

Python có sẵn thư viện base64 với function b64encode để biến bytes đầu vào thành dạng text Base64.

Code sau code theo mô tả cách thực hiện Base64 ở trên:

import string
b64 = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'

data = 'PyMi.vn'.encode('utf-8')
bits = []
for c in data:
    print(type(c), c, bin(c))
    bits.extend(bin(c)[2:].zfill(8))

output = []
for i24 in range(0, len(bits), 24):
    g1 = bits[i24:i24+24]
    for i in range(0, len(g1), 6):
        six_bits = g1[i:i+6]
        while len(six_bits) < 6:
            six_bits.append('0')
        n = int(''.join(six_bits), 2)
        output.append(b64[n])
        print(six_bits, n, b64[n])

while len(output) % 4 != 0:
    output.append('=')

print(''.join(output))
print(base64.b64encode(b'PyMi.vn'))

Output

<class 'int'> 80 0b1010000
<class 'int'> 121 0b1111001
<class 'int'> 77 0b1001101
<class 'int'> 105 0b1101001
<class 'int'> 46 0b101110
<class 'int'> 118 0b1110110
<class 'int'> 110 0b1101110
['0', '1', '0', '1', '0', '0'] 20 U
['0', '0', '0', '1', '1', '1'] 7 H
['1', '0', '0', '1', '0', '1'] 37 l
['0', '0', '1', '1', '0', '1'] 13 N
['0', '1', '1', '0', '1', '0'] 26 a
['0', '1', '0', '0', '1', '0'] 18 S
['1', '1', '1', '0', '0', '1'] 57 5
['1', '1', '0', '1', '1', '0'] 54 2
['0', '1', '1', '0', '1', '1'] 27 b
['1', '0', '0', '0', '0', '0'] 32 g
UHlNaS52bg==
b'UHlNaS52bg=='

Tham khảo

https://datatracker.ietf.org/doc/html/rfc3548.html

Đăng ký ngay tại PyMI.vn để học Python tại Hà Nội TP HCM (Sài Gòn), trở thành lập trình viên #python chuyên nghiệp ngay sau khóa học.