5.6 Base64算法实现
对于Base64算法,在Java API文档中,我们看不到有关它的任何身影。其实这种算法并不复杂,我们通过手工都能完成编码解码的演算。但是,Sun公司依旧没有提供相应的实现。开源组织总是在必要的时候弥补Sun公司的缺陷,壮大Java的世界。Bouncy Castle和Commons Codec两大开源组件包,填补了Java 6缺失Base64算法实现的遗憾。但实际上Sun也做了Base64算法的实现,却不能将其公示,这令众多Java开发者倍感疑惑。
在Bouncy Castle和Commons Codec两大开源组件包中,Bouncy Castle提供了一般Base64算法的实现,而Commons Codec还提供了基于RFC 2045相关定义的Base64算法实现。
5.6.1 Bouncy Castle
Bouncy Castle遵循的是一般Base64算法,也就是简单地根据Base64字符映射表做了编码转换。对于本文开篇的那一段神奇的乱码转换,我们先通过Bouncy Castle来做一下实现分析。
Bouncy Castle的Base64类对于编码/解码操作只有简单的两个方法,请读者阅读第4章相关内容。
我们一起来看代码清单5-1,从而了解用于操作Base64算法的实现类Base64Coder。
代码清单5-1 Base64组件1
import org.bouncycastle.util.encoders.Base64;
/**
*Base64组件
*@author梁栋
*@version 1.0
*@since 1.0
*/
public abstract class Base64Coder{
//字符编码
public final static String ENCODING="UTF-8";
/**
*Base64编码
*@param data待编码数据
*@return String编码数据
*@throws Exception
*/
public static String encode(String data)throws Exception{
//执行编码
byte[]b=Base64.encode(data.getBytes(ENCODING));
return new String(b, ENCODING);
}
/**
*Base64解码
*@param data待解码数据
*@return String解码数据
*@throws Exception
*/
public static String decode(String data)throws Exception{
//执行解码
byte[]b=Base64.decode(data.getBytes(ENCODING));
return new String(b, ENCODING);
}
}
Base64算法实现起来就是这么简单,仅用几行代码就完成了编码/解码的调用实现。代码清单5-2是相应的测试用例代码。
代码清单5-2 Base64组件1测试用例
import static org.junit.Assert.*;
import org.junit.Test;
/**
*Base64编码与解码测试类
*@author梁栋
*@version 1.0
*@since 1.0
*/
public class Base64CoderTest{
//测试Base64编码与解码
@Test
public final void test()throws Exception{
String inputStr="Java加密与解密的艺术";
System.err.println("原文:\t"+inputStr);
//进行Base64编码
String code=Base64Coder.encode(inputStr);
System.err.println("编码后:\t"+code);
//进行Base64解码
String outputStr=Base64Coder.decode(code);
System.err.println("解码后:\t"+outputStr);
//验证Base64编码解码一致性
assertEquals(inputStr, outputStr);
}
}
我们终于在控制台中看到了如下信息:
原文:Java加密与解密的艺术
编码后:SmF2YeWKoOWvhuS4juino+WvhueahOiJuuacrw==
解码后:Java加密与解密的艺术
请大家注意,原文经Base64编码后,并没有多出一个回车换行符!请大家注意图5-2中,code变量的值并没有相应的回车换行符(“\r\n")。
图 5-2 Base64 Debug 1
Bouncy Castle未能遵循RFC 2045的相关定义,但在实际使用中,有时候我们恰恰有意需要这么做。如果需要完全遵循RFC 2045,那就使用Commons Codec吧!