由于DES不再安全,现在都流行使用AES加密算法替代DES,Rijndael是AES的实现。
我从网上找到了很多Rijndael的java实现代码,我用了其中的一个,并且写了一个工具类,使得更方便使用它。
https://files.cnblogs.com/jobs/Rijndael.rar
Rijndael_Util.java是我写的,使用方法如下:
String strKey = "欲练神功挥刀子宫";
String plainText = "葵花宝典";
String cipherText = Rijndael_Util.encode(strKey, plainText);
System.out.println(cipherText);
System.out.println(Rijndael_Util.decode(strKey, plainText);
由于Rijindael的算法要求每次加密的数据必须是一个block,blockSize可以是16、24或者32。因此,当需要加密一个byte数组paintBytes时,如果byte数组plainBytes的长度不为blockSize的倍数,则需要补位。此时,就需要一个数值来保留明文byte数组的长度。最初我是用四个byte来保存plainBytes的长度,然后直接放在密文byte数组cipherBytes的最前面。但是我考虑到把直接把明文的长度暴露出来,不是很好,于是,就做了一个处理。
当blockSize为16或者24时,而且plainBytes的长度不为blockSize的倍数,最后一个block的blockSize使用一个长度为blckSize+8的byte数组lastBlockBytes来保存,这样,最后一个block的长度就比普通的block长8个byte,这个8个byte的前4位用来保存plainBytes的长度。
当blockSize为32时,则最后一个block拆为两个block,一个block的长度为16,一个block的长度为24,这样一来,又有多余的8位来保存plainBytes的长度了。
把int变为四个byte和把四个byte读回一个int的实现如下:
bytes[offSet] = (byte) (val >> 24);
bytes[offSet + 1] = (byte) (val >> 16);
bytes[offSet + 2] = (byte) (val >> 8);
bytes[offSet + 3] = (byte) val;
}
return ((bytes[offSet + 0] & 0xff) << 24)
| ((bytes[offSet + 1]) << 16)
| ((bytes[offSet + 2] & 0xff) << 8)
| ((bytes[offSet + 3] & 0xff) << 0);
}
.NET的朋友注意,java中的byte是带符号,而c#中的byte是无符号的。
以前,由于很少写低级的代码,所以对位运算不够熟悉,最初是,把一个int拆成4个byte的算法自己写,但是觉得不够好,后来和flier_lu交流后,flier_lu建议我看java.nio中的ByteBuffer的实现,可能会有收获。我查看后java.nio.Bytes类后,发现了java.nio.Bits的实现比我做的更好一些。java.nio.Bits是一个内部类,不是public,我们不能调用它,但是可以参考他的源码实现。
在这个过程中,我和以往的感觉一样,一个基础类库,开放源码对于使用者会有很大帮助。
最近有人对.NET的前途提出质疑,有人说到关键点上来了:.NET是一个相当封闭的平台。微软对于公开基础类库的源码,在走倒退的道路。以前微软的基础类库MFC是可以查看源码的,你甚至可以调试源码,但是微软提供.NET的基础类库而是不开放源代码的,虽然你可以通过Reflectro或者Mono了解一些基础类库的源码,但这个不能够确定你通过这些途径得到的源码和你正在使用的是一致的。
从.NET转向Java快两年了,越来越对Java的前途充满希望,也很多人一样,对微软的.NET越来越失望。