java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java BASE64加解密算法

Java实现BASE64加解密算法的示例代码

作者:Katie。

Base64 编码便是一种常用的方法,它将任意二进制数据编码为可打印的 ASCII 字符,保证在文本环境下不被破坏,本项目将使用 Java 语言,从头实现基于查表法的 Base64 编码与解码工具,需要的朋友可以参考下

1. 项目背景详细介绍

在网络通信、数据存储与传输以及各种协议交互中,二进制数据常常需要以文本形式表现,以便在 HTTP、SMTP、JSON 等纯文本协议中安全传递。Base64 编码便是一种常用的方法,它将任意二进制数据编码为可打印的 ASCII 字符,保证在文本环境下不被破坏。

Java 标准库中已有 java.util.Base64 实现,但手写一套基于查表法(Table-Driven)的 Base64 编解码算法,可以帮助我们:

本项目将使用 Java 语言,从头实现基于查表法的 Base64 编码与解码工具,支持标准 Base64(含 +/= 填充)及 URL 安全变体(-_、无填充)。

2. 项目需求详细介绍

功能需求

Base64 编码

Base64 解码

易用 API

public static String encode(byte[] data, boolean urlSafe);
public static byte[] decode(String b64);

边界与异常处理

非功能需求

性能

可扩展性

易测试

多线程安全

3. 相关技术详细介绍

Base64 编码原理

查表法实现

位运算与字节处理

int b0 = data[i]   & 0xFF;
int b1 = data[i+1] & 0xFF;
int b2 = data[i+2] & 0xFF;
// 组合为 24 位:(b0<<16)|(b1<<8)|b2
// 依次提取 6 位输出

字符编码

异常设计

4. 实现思路详细介绍

4.1 数据结构设计

编码表

private static final char[] ENC = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
private static final char[] ENC_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray();
private static final byte[] DEC = new byte[128]; // 初始化为 -1
// 遍历 ENC,DEC[ENC[i]] = (byte)i
// 同时为 URL 变体字符赋值

4.2 编码流程

初始化:选择 ENCENC_URL

主循环:每次处理 3 字节:

尾部处理:剩余 1 或 2 字节时,补零组合并输出相应字符,最后添加 =(标准模式);

结果拼接:使用 StringBuilder 或预估长度的 char[] 直接写入,避免扩容。

4.3 解码流程

预处理:去掉所有非 Base64 字符(如换行、空格);

填充检测:记录末尾 = 数量,验证长度对 4 的整除;

主循环:每次读 4 个字符:

结果返回:收集到 byte[],或使用 ByteArrayOutputStream 缓冲。

4.4 API 设计

public class Base64Util {
    public static String encode(byte[] data);
    public static String encodeUrlSafe(byte[] data);
    public static byte[] decode(String b64) throws Base64Exception;
}

4.5 扩展与优化

// ==================== 文件:Base64Exception.java ====================
package com.example.base64;
 
/**
 * Base64 编解码异常
 */
public class Base64Exception extends RuntimeException {
    public Base64Exception(String message) {
        super(message);
    }
    public Base64Exception(String message, Throwable cause) {
        super(message, cause);
    }
}
 
// ==================== 文件:Base64Util.java ====================
package com.example.base64;
 
import java.util.Arrays;
 
/**
 * 基于查表法的 Base64 编解码工具,支持标准与 URL 安全模式
 */
public class Base64Util {
    // 标准 Base64 编码表
    private static final char[] ENC = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
    // URL 安全 Base64 编码表
    private static final char[] ENC_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".toCharArray();
    // 解码查表,-1 表示非法字符
    private static final byte[] DEC = new byte[128];
    static {
        Arrays.fill(DEC, (byte)-1);
        for (int i = 0; i < ENC.length; i++) {
            DEC[ENC[i]] = (byte)i;
        }
        for (int i = 0; i < ENC_URL.length; i++) {
            DEC[ENC_URL[i]] = (byte)i;
        }
        DEC['='] = 0;
    }
 
    /**
     * 标准 Base64 编码
     */
    public static String encode(byte[] data) {
        return encode(data, false);
    }
 
    /**
     * URL 安全 Base64 编码(无填充)
     */
    public static String encodeUrlSafe(byte[] data) {
        return encode(data, true);
    }
 
    private static String encode(byte[] data, boolean urlSafe) {
        if (data == null || data.length == 0) return "";
        char[] table = urlSafe ? ENC_URL : ENC;
        int len = data.length;
        int fullGroups = len / 3;
        int remainder = len - 3 * fullGroups;
        int outLen = 4 * ((len + 2) / 3);
        StringBuilder sb = new StringBuilder(outLen);
        int idx = 0;
        // 主循环,每次处理 3 字节
        for (int i = 0; i < fullGroups; i++) {
            int b0 = data[idx++] & 0xFF;
            int b1 = data[idx++] & 0xFF;
            int b2 = data[idx++] & 0xFF;
            sb.append(table[b0 >>> 2]);
            sb.append(table[((b0 & 0x3) << 4) | (b1 >>> 4)]);
            sb.append(table[((b1 & 0xF) << 2) | (b2 >>> 6)]);
            sb.append(table[b2 & 0x3F]);
        }
        // 处理尾部
        if (remainder == 1) {
            int b0 = data[idx++] & 0xFF;
            sb.append(table[b0 >>> 2]);
            sb.append(table[(b0 & 0x3) << 4]);
            if (!urlSafe) {
                sb.append("==");
            }
        } else if (remainder == 2) {
            int b0 = data[idx++] & 0xFF;
            int b1 = data[idx++] & 0xFF;
            sb.append(table[b0 >>> 2]);
            sb.append(table[((b0 & 0x3) << 4) | (b1 >>> 4)]);
            sb.append(table[(b1 & 0xF) << 2]);
            if (!urlSafe) {
                sb.append('=');
            }
        }
        return sb.toString();
    }
 
    /**
     * 自动识别标准或 URL 安全 Base64,解码为原始字节
     */
    public static byte[] decode(String b64) {
        if (b64 == null || b64.isEmpty()) return new byte[0];
        // 去除空白
        String s = b64.trim().replaceAll("\\s", "");
        int len = s.length();
        if ((len & 3) != 0) {
            throw new Base64Exception("Base64 长度非 4 的倍数: " + len);
        }
        // 计算填充数量
        int pad = 0;
        if (len > 0 && s.charAt(len - 1) == '=') pad++;
        if (len > 1 && s.charAt(len - 2) == '=') pad++;
        int outLen = (len * 3) / 4 - pad;
        byte[] out = new byte[outLen];
        int outIdx = 0;
        int inIdx = 0;
        // 主循环,每次处理 4 字符
        for (int i = 0; i < len; i += 4) {
            int c0 = charToValue(s.charAt(i));
            int c1 = charToValue(s.charAt(i+1));
            int c2 = charToValue(s.charAt(i+2));
            int c3 = charToValue(s.charAt(i+3));
            int triple = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3;
            if (outIdx < outLen) out[outIdx++] = (byte)(triple >> 16);
            if (outIdx < outLen) out[outIdx++] = (byte)(triple >> 8);
            if (outIdx < outLen) out[outIdx++] = (byte)triple;
        }
        return out;
    }
 
    private static int charToValue(char c) {
        if (c >= DEC.length || DEC[c] < 0) {
            throw new Base64Exception("非法 Base64 字符: " + c);
        }
        return DEC[c];
    }
}
 
// ==================== 文件:TestBase64Util.java ====================
package com.example.base64;
 
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
 
/**
 * JUnit 单元测试:验证 Base64 编解码功能
 */
public class TestBase64Util {
 
    @Test
    public void testStandardEncodeDecode() {
        String text = "Hello, 世界!";
        byte[] raw = text.getBytes(java.nio.charset.StandardCharsets.UTF_8);
        String enc = Base64Util.encode(raw);
        byte[] dec = Base64Util.decode(enc);
        Assertions.assertEquals(text, new String(dec, java.nio.charset.StandardCharsets.UTF_8));
    }
 
    @Test
    public void testUrlSafe() {
        String text = "abc+/";
        byte[] raw = text.getBytes(java.nio.charset.StandardCharsets.UTF_8);
        String encUrl = Base64Util.encodeUrlSafe(raw);
        Assertions.assertFalse(encUrl.contains("+") || encUrl.contains("/"));
        byte[] dec = Base64Util.decode(encUrl);
        Assertions.assertEquals(text, new String(dec, java.nio.charset.StandardCharsets.UTF_8));
    }
 
    @Test
    public void testEmpty() {
        Assertions.assertArrayEquals(new byte[0], Base64Util.decode(""));
        Assertions.assertEquals("", Base64Util.encode(new byte[0]));
    }
 
    @Test
    public void testInvalid() {
        Assertions.assertThrows(Base64Exception.class, () -> Base64Util.decode("abcd*"));
        Assertions.assertThrows(Base64Exception.class, () -> Base64Util.decode("abc"));
    }
}

5. 代码详细解读

Base64Exception.java

Base64Util.java

6. 项目详细总结

本项目从底层位运算与查表法出发,完整实现了 Base64 编解码功能,具有以下特点:

7. 项目常见问题及解答

Q1:为什么要手写而不直接用 java.util.Base64
A:手写实现有助于深入理解 Base64 原理,并可在受限环境(无库支持)中使用。

Q2:URL 安全模式为什么不加填充?
A:JWT 等场景中常省略填充以缩短长度,读取时可自动补齐。

Q3:如何支持其他字符集的 Base64(如 Base64Url+Padding)?
A:可在 encode 方法中传入自定义字符表,并在解码时提供相应反向查表。

Q4:如何对大文件做流式处理?
A:可将 encode/decode 分块调用,使用 InputStream/OutputStream,在每次块结束时维护少量状态。

8. 扩展方向与性能优化

SIMD 加速

JNI 本地库

缓存优化

自定义变体

并行流水线

以上就是Java实现BASE64加解密算法的示例代码的详细内容,更多关于Java BASE64加解密算法的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文