Apache Codec 提供了 org.apache.commons.codec.binary.Base32 类实现 BASE32 加密和解密。
Base32 类提供 RFC4648 定义的 base32 编码和解码。可以使用各种构造函数以下列方式对该类进行参数化:
a、是否使用“base32hex”变量而不是默认的“base32”
b、行长:默认为76。在编码的数据中,不是8倍的行长度实际上仍然是8的倍数。
c、行分隔符:默认为 CRLF (“\r\n”)
这个类直接操作字节流,而不是字符流。
(1)使用 Base32 默认构造方法创建 Base32 对象,然后进行加密解密操作。代码如下:
package com.huangx.codec.base32; import org.apache.commons.codec.binary.Base32; public class Base32Demo { public static void main(String[] args) { 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))); } }
运行上面程序,输出结果如下:
NBSWY3DPEB3W64TMMQ====== hello world
其中,“=”是填充符号,我们可以通过 pad 参数进行指定。如下:
package com.huangx.codec.base32; import org.apache.commons.codec.binary.Base32; public class Base32Demo1 { public static void main(String[] args) { 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
(2)使用带有 useHex 参数的构造方法创建 Base32 对象,如果我们使用 useHex = true,则将使用十六进制字符表。先看 Base32 构造方法的部分代码:
if (useHex) { this.encodeTable = HEX_ENCODE_TABLE; this.decodeTable = HEX_DECODE_TABLE; } else { this.encodeTable = ENCODE_TABLE; this.decodeTable = DECODE_TABLE; }
上面代码根据 useHex 不同,选择不同的解码和编码字符表。其中:HEX_ENCODE_TABLE、HEX_DECODE_TABLE、ENCODE_TABLE 和 DECODE_TABLE 定义如下:
// 该数组是一个查找表,用于将5位正整数索引值转换为 “Base32十六进制字母表” 等效于RFC4648的表4 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', }; // 这个数组是一个查找表,它将从“Base32十六进制字母表”(如RFC 4648的表4中所指定的)提取的Unicode字符转换为对应的5位正整数。 // 不在Base32十六进制字母表但在数组范围内的字符将被转换为-1。 private static final byte[] HEX_DECODE_TABLE = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20-2f 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 30-3f 2-7 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 40-4f A-O 25, 26, 27, 28, 29, 30, 31, // 50-56 P-V -1, -1, -1, -1, -1, -1, -1, -1, -1, // 57-5f Z-_ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 60-6f `-o 25, 26, 27, 28, 29, 30, 31 // 70-76 p-v }; // 这个数组是一个查找表,它将5位正整数索引值转换为RFC 4648的表3中指定的“Base32字母表”等量值。 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', }; // 这个数组是一个查找表,它将从“Base32字母表”(如RFC 4648的表3中所指定的)提取的Unicode字符转换为对应的5位正整数。 // 不在Base32字母表但在数组范围内的字符将被转换为-1。 private static final byte[] DECODE_TABLE = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20-2f -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, // 30-3f 2-7 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4f A-O 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 50-5a P-Z -1, -1, -1, -1, -1, // 5b - 5f -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 60 - 6f a-o 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 70 - 7a p-z/**/ };
因此,使用 useHex = true 和 useHex = false 加密出来的密文是不一样的。示例代码如下:
package com.huangx.codec; import org.apache.commons.codec.binary.Base32; import org.apache.commons.codec.binary.Hex; public class Base32Demo2 { public static void main(String[] args) { String str = "hello world"; Base32 base32; // 加密 base32 = new Base32(false); byte[] bytes = base32.encode(str.getBytes()); System.out.println(Hex.encodeHexString(bytes)); // 加密 base32 = new Base32(true); bytes = base32.encode(str.getBytes()); System.out.println(Hex.encodeHexString(bytes)); } }
运行上面程序,将输出如下结果:
4e42535759334450454233573634544d4d513d3d3d3d3d3d 4431494d4f5233463431524d55534a4343473d3d3d3d3d3d
(3)使用指定 lineLength 的构造方法创建 Base32。其中,lineLength 用于指定每一行编码数据最多为给定长度 (四舍五入至最接近的倍数为8)。如果 lineLength<=0,则输出不会被划分为行(块)。解码时忽略。例如:
package com.huangx.codec; import org.apache.commons.codec.binary.Base32; public class Base32Demo3 { public static void main(String[] args) { 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 hi, welcome administrator
可以看到,Base32 编码结果按照指定的 lineLength 进行换行显示(插入 CRLF 字符)。
(4)使用 lineSeparator 指定每一行编码的数据都将以这个字节序列结束。例如:使用“%%”符号作为行结束符
package com.huangx.codec.base32; import org.apache.commons.codec.binary.Base32; import org.apache.commons.codec.binary.Hex; public class Base32Demo4 { public static void main(String[] args) { 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
如果你指定的 lineSeparator 包含 base32 字符时抛出 IllegalArgumentException 异常。