Base64 encoding và decoding trong Java 8

Trong bài này, chúng ta sẽ cùng tìm hiểu chức năng mã hóa (encode) và giải mã (decode) theo chuẩn Base64 trong Java 8 và sử dụng thư viện Apache Commons Code.

1. Giới thiệu

1.2. Encode và Decode là gì?

Encode và Decode là những khái niệm dùng để chỉ đến việc chuyển đổi dữ liệu cho hai mục đích khác nhau lưu trữ và sử dụng.

Encode thông thường sẽ tạo ra dữ liệu phục phụ cho việc lưu trữ, ngược lại Decode sẽ chuyển đổi dữ liệu lưu trữ thành dữ liệu sử dụng trong chương trình. Hai quá trình này ngược nhau và khác nhau trong từng hệ ứng dụng, cách thức cài đặt, dữ liệu,…

1.3. Base64 là gì?

Base64 là một chương trình mã hóa chuỗi ký tự bằng cách dùng thay thế các ký tự trong bảng mã ASCII 8 bit thông dụng thành bảng mã 6 bit. Ký tự 64 trong Base64 là đại diện cho 64 ký tự (A-Za-z0-9+/) trong bãng mã ASCII.

Chuẩn Base64 là một tập hợp gồm các ký tự (theo đúng thứ tự) : từ A đến Z, từ a đến z, từ 0 đến 9, dấu +, dấu /. Tổng cộng là 64 ký tự biểu diễn 64 giá trị từ 0 đến 63. Như vậy, ký tự từ A đến Z biểu diễn cho các giá trị từ 0 đến 25, từ a đến z biểu diễn cho giá trị từ 26 đến 51, từ 0 đến 9 biểu diễn cho giá trị từ 52 đến 61, dấu + biểu diễn cho giá trị 62, dấu / biểu diễn cho giá trị 63.

Một ký tự biểu diễn theo mã ASCII sẽ dùng 8 bits. Một ký tự theo Base64 sẽ dùng 6 bits. Như vậy, một file ở dạng Base64 sẽ có kích thước lớn hơn khi ở dạng ASCII. Cụ thể, sẽ lớn gấp 4/3 lần (8 bits/6 bits).

Để chuyển đổi file sang dạng Base64, ta thực hiện theo các bước như sau :

  1. Đọc nội dung file dưới dạng bit.
  2. Cứ 6 bits ta tách thành một nhóm để xử lý.
  3. Tra bảng mã Base64, mỗi nhóm 6 bits sẽ có giá trị tương ứng với một ký tự.
  4. Ghi ra file các ký tự đó.

Chi tiết các bạn có thể tham khảo thêm theo các link bên dưới:

2. Base64 encoding và decoding trong Java 8

Java 8 thêm lớp mới java.util.Base64, nó được sử dụng để hỗ trợ mã hóa và giải mã văn bản trong Base64. Chúng ta có thể sử dụng Base64.Encoder để mã hóa một mảng byte hoặc String và Base64.Decoder để giải mã một mảng byte được mã hóa base64 hoặc String trong Java 8.

Lớp Base64 cung cấp 3 loại encode và decode sau:

  • Basic : đầu ra được ánh xạ tới một tập hợp các ký tự nằm trong A-Za-z0-9 + /. Bộ mã hóa không thêm bất kỳ nguồn cấp dữ liệu nào vào đầu ra và bộ giải mã từ chối bất kỳ ký tự nào khác ngoài A-Za-z0-9 + /.
  • URL và Filename Safe: Nó sử dụng bảng chữ cái Base64 được chỉ định bởi Java trong RFC 4648 cho các hoạt động mã hóa và giải mã. Bộ mã hóa (encoder) không thêm bất kỳ ký tự phân tách dòng nào. Bộ giải mã (decoder) từ chối dữ liệu chứa các ký tự nằm ngoài bảng chữ cái Base64. Kết quả là một URL hoặc FileName an toàn (A-Za-z0-9+_), không chứa dấu /.
  • MIME : Nó sử dụng bảng chữ cái Base64 như được chỉ định trong RFC 2045 cho các hoạt động mã hóa và giải mã. Đầu ra được mã hóa phải được thể hiện bằng các dòng không quá 76 ký tự và sử dụng ký tự \r\n làm dấu phân tách dòng. Không có dấu tách dòng được thêm vào cuối đầu ra được mã hóa. Tất cả các dấu tách dòng hoặc các ký tự khác không được tìm thấy trong bảng chữ cái Base64 đều bị bỏ qua trong thao tác giải mã.

2.1. Ví dụ sử dụng Base64 Basic

String str = "VietMX Coder";
String encodedString = Base64.getEncoder().encodeToString(str.getBytes());
System.out.println(encodedString); // R1AgQ29kZXI=
 
byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
String decodedString = new String(decodedBytes);
System.out.println(decodedString); // GP Coder
 
String encodedStringWithoutPadding =
Base64.getEncoder().withoutPadding().encodeToString(str.getBytes());
System.out.println(encodedStringWithoutPadding); // R1AgQ29kZXI

Trong mã hóa Base64, độ dài của chuỗi được mã hóa đầu ra phải là bội số của 3. Nếu không đủ, đầu ra sẽ được đệm bằng các ký tự pad bổ sung (dấu =).

2.2. Ví dụ sử dụng Base64 URL

String url = "https://www.maixuanviet.com/4144-base64-encoding-va-decoding-trong-java-8/";
String encodedUrl = Base64.getUrlEncoder().encodeToString(url.getBytes());
System.out.println(encodedUrl);
// aHR0cHM6Ly9ncGNvZGVyLmNvbS80MTQ0LWJhc2U2NC1lbmNvZGluZy12YS1kZWNvZGluZy10cm9uZy1qYXZhLTgv
 
byte[] decodedBytes = Base64.getUrlDecoder().decode(encodedUrl);
String decodedUrl = new String(decodedBytes);
System.out.println(decodedUrl);
// https://www.maixuanviet.com/4144-base64-encoding-va-decoding-trong-java-8/

2.3. Ví dụ sử dụng Base64 MIME

Base64 MIME tương tự như Basic, ngoại trừ độ dài của mỗi dòng không quá 76 ký tự và kết thúc là ký tự xuống dòng \r\n .

StringBuilder sb = new StringBuilder();
for (int count = 0; count < 10; ++count) {
    sb.append(UUID.randomUUID().toString());
}
 
String str = sb.toString();
String encodedMime = Base64.getMimeEncoder().encodeToString(str.getBytes());
System.out.println(encodedMime);
 
byte&#91;&#93; decodedBytes = Base64.getMimeDecoder().decode(encodedMime);
String decodedMime = new String(decodedBytes);
System.out.println(decodedMime.equals(str)); // true
&#91;/code&#93;
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>Output của encoder:</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->

Njk2YWI0OGEtZjM5Mi00OWMyLWEyODctNzY2ZWFiYWViYTA1NjEyNGJmMTEtOGJkZS00MTM1LWE2
OTktZmY2Y2U2OWM5NDAxNjA4ODlkYjctM2U2MS00YmZjLWFiYTktODRkYjY1M2E5YTI0MDUyNmFj
ZmQtNWY0Ny00YWE5LWEyYmQtYjMyNDJjYjEzMGRmZTNlNmQ3MTctYTQ4NC00MDljLWI5MWEtYWYz
ZWFiNDI1NGU5ZmM4N2MwYzItMmY2ZC00MjVlLTljNjMtODFmNWVmMzM3NDZhZjViMmE1NmUtYTc4
Ny00YzE3LTg4OTItOGE3NjgxYmQxZmYyMjgxMGY3YzUtNTQ1OC00MzUzLWFhNTctOTM2YTk2MDNi
NWM1MjgwODUxM2UtY2FjOS00MzM4LWJkYjktNjIwMDIwZDNmMTNlNTAyMDJkN2MtYWYxNS00ZGFh
LWI0ZmQtMWUyYzg2ZWY5Mzgx

Trong ví dụ trên tôi có sử dụng phương thức java.util.UUID.randomUUID() để sinh ra một chuỗi ngẫu nhiên có độ dài 32 ký tự (128 bit) được biểu diễn ở hệ hệ thập lục phân (hex: 0-9A-F) và 4 ký tự phân tách ().

Ví dụ:

123e4567-e89b-12d3-a456-556642440000

Tham khảo thêm về UUID: http://www.baeldung.com/java-uuid

3. Sử dụng thư viện Apache Common Codec

Nếu không sử dụng Java 8, chúng ta có thể sử dụng một thư viện khác để thay thế là Apache common codec. Các bạn có thể download tại đây: https://mvnrepository.com/artifact/commons-codec/commons-codec

Thư viện Apache Common Codec cung cấp một số phương thức khởi tạo sau:

  • Base64 (boolean urlSafe) : tạ chuỗi Base64 API bằng cách kiểm soát chế độ an toàn URL/ FileName.
  • Base64 (int lineLength) : tạo chuỗi Base64 API trong một chế độ không an toàn URL và kiểm soát độ dài của dòng (mặc định là 76). Tương tự như Java 8 Base64 MIME.
  • Base64 (int lineLength, byte [] lineSeparator) : tạo chuỗi Base64 API bằng cách chấp nhận một dấu tách dòng phụ,mặc định là CRLF (\r\n).

Ví dụ:

private static void base() {
    Base64 base64 = new Base64();
 
    String str = "GP Coder";
    String encodedString = new String(base64.encode(str.getBytes()));
    System.out.println(encodedString); // R1AgQ29kZXI=
 
    byte[] decodedBytes = encodedString.getBytes();
    String decodedString = new String(base64.decode(decodedBytes));
    System.out.println(decodedString); // GP Coder
}
 
private static void url() {
    Base64 base64 = new Base64(true);
    String url = "https://www.maixuanviet.com/4144-base64-encoding-va-decoding-trong-java-8/";
    String encodedString = new String(base64.encode(url.getBytes()));
    System.out.println(encodedString);
    // aHR0cHM6Ly9ncGNvZGVyLmNvbS80MTQ0LWJhc2U2NC1lbmNvZGluZy12YS1kZWNvZGluZy10cm9u
    // Zy1qYXZhLTgv // There is a new line because it is more than 76 characters by default
 
    byte[] decodedBytes = encodedString.getBytes();
    String decodedString = new String(base64.decode(decodedBytes));
    System.out.println(decodedString);
    // https://www.maixuanviet.com/4144-base64-encoding-va-decoding-trong-java-8/
}