Base32 是一种数据编码机制,使用 32 个可打印字符(字母 A-Z 和数字 2-7)对任意字节数据进行编码的方案,编码后的字符串不用区分大小写并排除了容易混淆的字符,可以方便地由人类使用并由计算机处理。
它主要用来把二进制数据编码成可见的字符串。它的编码规则是:任意给定一个二进制数据,以 5 个位(bit))为一组进行切分(注意:base64 以 6 个位 (bit) 为一组),对切分而成的每个组进行编码得到 1 个可见字符。Base32 编码表字符集中的字符总数为 2 的 5 次方 32 个,这也是 Base32 名字的由来。
在 Commons Codec 中,通过 Base32、Base32InputStream 和 Base32OutputStream 类实现 base32 编码和解码。
提供 RFC 4648 定义的 Base32 编码和解码。可以使用各种构造函数以以下方式对类进行参数化:
是否使用 “base32hex” 变体而不是默认的 “base32”
行长:默认值76。在编码后的数据中,不是8的倍数的行长度本质上仍然是8的倍数。
行分隔符:默认为CRLF(“\r\n”)
注意:此类直接对字节流进行操作,而不对字符流进行操作;此类也是线程安全的;
构造方法说明
Base32( int lineLength, byte[] lineSeparator, boolean useHex, byte padding, CodecPolicy decodingPolicy)
创建用于解码和编码的 Base32/Base32 十六进制编解码器。编码时,在构造函数中给出了行长和行分隔符。在编码数据中,不是8的倍数的行长实际上仍将是8的倍数。参数说明:
lineLength:每行编码数据最多为给定长度(四舍五入为最接近的8的倍数)。如果 lineLength <= 0,则输出将不会分为几行。解码时忽略。
lineSeparator:每一行编码数据将以此字节序列结尾
useHex:如果为true,则使用 Base32 十六进制字母,否则使用 Base32 字母
padding:用作填充字节的字节
decodingPolicy:解码策略
实例
(1)使用默认构造方法构造 Base32 对象,代码如下:
Base32 base32 = new Base32(); // 加密 byte[] bytes = base32.encode("hello world".getBytes()); System.out.println(new String(bytes)); // 解密 System.out.println(new String(base32.decode(bytes)));
(2)演示指定自定的 padding,使用指定的 padding 去进行填充,代码如下:
// 指定使用 “#” 进行填充 Base32 base32 = new Base32((byte)'#'); // 加密 byte[] bytes = base32.encode("hello world".getBytes()); System.out.println(new String(bytes)); // 解密 System.out.println(new String(base32.decode(bytes)));
输出结果:
NBSWY3DPEB3W64TMMQ###### hello world
(3)演示 useHex 的用法
在正式演示 useHex 的用法之前,我们先看看 Base32 中对 base32 编码字符表映射。源码定义如下:
/** * 该数组是一个查找表,该表将5位正整数索引值转换为RFC 4648表3中指定的 “Base32 Alphabet” 等效项。 */ private static final byte[] ENCODE_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', }; /** * 此数组是一个查找表,该表将5位正整数索引值转换为RFC 4648表4中指定的 “Base32 Hex Alphabet” 等效项。 */ private static final byte[] HEX_ENCODE_TABLE = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', };
实例:分别演示使用和不使用 useHex 选项,代码如下:
String str = "hello world"; // 加密(Base32 Alphabet) Base32 base32 = new Base32(false); byte[] bytes = base32.encode(str.getBytes()); System.out.println(new String(bytes)); // 加密(Base32 Hex Alphabet) base32 = new Base32(true); bytes = base32.encode(str.getBytes()); System.out.println(new String(bytes));
输出结果:
NBSWY3DPEB3W64TMMQ====== D1IMOR3F41RMUSJCCG======
(4)演示行长度的使用,代码如下:
// 指定编码后每行最多显示 16 个字符 Base32 base32 = new Base32(16); // 加密 byte[] bytes = base32.encode("hi, welcome administrator".getBytes()); System.out.println(new String(bytes)); // 解密 System.out.println(new String(base32.decode(bytes)));
输出结果:
NBUSYIDXMVWGG33N MUQGCZDNNFXGS43U OJQXI33S
(5)演示自定义行分隔符,代码如下:
Base32 base32 = new Base32(16, "%%".getBytes()); // 加密 byte[] bytes = base32.encode("hi, welcome administrator".getBytes()); System.out.println(new String(bytes)); // 解密 System.out.println(new String(base32.decode(bytes)));
输出结果:
NBUSYIDXMVWGG33N%%MUQGCZDNNFXGS43U%%OJQXI33S%% hi, welcome administrator
(6)演示 decodingPolicy 解码策略
在演示 Base32 类的解码策略之前,我们先看看策略 CodecPolicy。CodecPolicy 类定义了编码和解码策略。该类是一个枚举类,提供如下两个枚举:
LENIENT:宽松策略
STRICT:严格策略
实例:演示使用严格策略 CodecPolicy.STRICT,代码如下:
/** * 1.指定每行长度 16 字节 * 2.使用 \r\n 作为换行符 * 3.不启用 useHex * 4.填充字符为 # * 5.解密策略为 CodecPolicy.STRICT */ Base32 base32 = new Base32(16, "\r\n".getBytes(), false, (byte)'#', CodecPolicy.STRICT); // 加密 byte[] bytes = base32.encode("Process finished with exit code".getBytes()); System.out.println(new String(bytes)); // 解密 System.out.println(new String(base32.decode(bytes)));
输出结果:
KBZG6Y3FONZSAZTJ NZUXG2DFMQQHO2LU NAQGK6DJOQQGG33E MU######
以流方式(大小不受限制)提供Base32编码和解码。编码时,默认的 lineLength 为 76 个字符,默认的 lineEnding 为CRLF,但是可以使用适当的构造函数来覆盖这些字符。
Base32InputStream 的默认行为是 DECODE,而 Base32OutputStream 的默认行为是ENCODE,但是可以使用其他构造函数来覆盖此行为。
由于此类直接在字节流而不是字符流上运行,因此它被硬编码为仅编码/解码与较低的 127 个 ASCII 图表兼容的字符编码(ISO-8859-1,Windows-1252,UTF-8, 等等)。
当输入字节包含有效编码无法创建的剩余尾随位时,可以设置解码行为。 这些可以是最后一个字符或整个字符中未使用的位。 默认模式是宽容解码。
宽松:任何可能的尾随位都组成8位字节。 其余的将被丢弃。
严格:如果尾随位不是有效编码的一部分,则解码将引发IllegalArgumentException。 最后一个字符中任何未使用的位必须为零。 不允许对整个最终字符进行计数。
启用严格解码后,预计解码后的字节将被重新编码为与原始字节匹配的字节数组,即最终字符不会发生变化。 这要求输入字节使用与编码器相同的填充和字母。
实例:
byte[] bytes = "NBSWY3DPEB3W64TMMQ======".getBytes(); ByteArrayInputStream input = new ByteArrayInputStream(bytes); Base32InputStream base32InputStream = new Base32InputStream(input); // 直接从输入流读取,读取出来的就是明文了 byte[] buffer = new byte[1024]; int len = base32InputStream.read(buffer); System.out.println(new String(buffer, 0, len));
以流方式(大小不受限制)提供Base32编码和解码。编码时,默认的 lineLength 为 76 个字符,默认的 lineEnding 为 CRLF,但是可以使用适当的构造函数来覆盖这些字符。
Base32OutputStream 的默认行为是 ENCODE,而 Base32InputStream 的默认行为是 DECODE。但是可以通过使用其他构造函数来覆盖此行为。
由于此类直接在字节流而不是字符流上运行,因此它被硬编码为仅编码/解码与较低的127个ASCII图表兼容的字符编码(ISO-8859-1,Windows-1252,UTF-8,等等)。
注意:必须在写入最后一个字节后关闭流,否则最后的填充将被忽略,并且结果数据将不完整/不一致。
当输入字节包含有效编码无法创建的剩余尾随位时,可以设置解码行为。这些可以是最后一个字符或整个字符中未使用的位。默认模式是宽容解码。
宽松:任何可能的尾随位都组成8位字节。其余的将被丢弃。
严格:如果尾随位不是有效编码的一部分,则解码将引发 IllegalArgumentException。最后一个字符中任何未使用的位必须为零。不允许对整个最终字符进行计数。
启用严格解码后,预计解码后的字节将被重新编码为与原始字节匹配的字节数组,即最终字符不会发生变化。这要求输入字节使用与编码器相同的填充和字母。
实例:
(1)Base32OutputStream 默认为编码,我们通过 write 方法写入数据时,会自动进行编码。代码如下:
ByteArrayOutputStream output = new ByteArrayOutputStream(); Base32OutputStream base32OutputStream = new Base32OutputStream(output); base32OutputStream.write("hello world".getBytes()); base32OutputStream.close(); // 输出编码字符串 System.out.println(new String(output.toByteArray()));
(2)通过构造函数指定 Base32OutputStream 行为为解码,代码如下:
ByteArrayOutputStream output = new ByteArrayOutputStream(); Base32OutputStream base32OutputStream = new Base32OutputStream(output, false); base32OutputStream.write("NBSWY3DPEB3W64TMMQ======".getBytes()); base32OutputStream.close(); // 输出编码字符串 System.out.println(new String(output.toByteArray()));