前言 简单了解对文本内容或二级制的内容,进行加密解密(也可以理解为编解码)操作。
Base64 编解码 base64 并不该算作一种加密方式,更倾向于他是一种编码方式,将二进制文件进行编码后,方便传输,同时编码后的内容可以进行反编码,恢复内容。
1 2 3 4 5 6 7 8 9 10 11 import org.apache.commons.codec.binary.Base64; private static void basic () { String chinese = "中华人民共和国" ; System.out.println("origin is " + chinese); String encode = Base64.encodeBase64String(chinese.getBytes()); System.out.println("encode --> " + encode); byte [] temp = Base64.decodeBase64(encode); String decode = new String(temp); System.out.println("decode --> " + decode); }
可以非常方便的使用 apache commons-codec 库中的 Base64 工具类进行关于 base64 的编解码工作。
比如在 Web 端常用的图片 base64 编码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private static String imageToBase64 (String path) { String prefix = processPrefix(path); String result = "" ; InputStream input; byte [] data = {}; try { input = new FileInputStream(path); data = new byte [input.available()]; input.read(data); input.close(); } catch (IOException e) { e.printStackTrace(); } result = Base64.encodeBase64String(data); return prefix + result; }
以上便是把图片转换为 String 的 base64 实现,最终结果是类似 “data:image/filetype,xyz” 这样的数据。 这里需要注意的是不同类型的图片(文件),这里 image/filetype
中 filetype 顾名思义是文件类型,因此在转换时需要做特殊处理。
自定义加密/解密 通过以上实现,我们可以了解到,对文件进行编解码就是对文件中对应的输入内容进行一些算法操作,这样的算法操作有不同的目的,有的可能只是想获取文件的唯一标识,比如 MD5 等。有的是为了对输入内容进行一些[干扰],使得常规的解码方式,无法识别对这些进行过干扰的内容,从而实现所谓的加密 。这里就来尝试一下对文件的加密操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public static boolean encryptFile (String filepath, String outputPath,boolean encrypt) { boolean result = false ; File file = new File(filepath); File outputFile = new File(outputPath); outputFile.deleteOnExit(); try { FileInputStream fileInputStream = new FileInputStream(file); FileOutputStream fileOutputStream = new FileOutputStream(outputFile); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); int n; while ((n = bufferedInputStream.read()) != -1 ) { encrypt(bufferedOutputStream,n,encrypt); } bufferedInputStream.close(); bufferedOutputStream.close(); result = true ; } catch (IOException e) { e.printStackTrace(); } return result; }
回归到本质,对文件进行加密/解密,其实就是文件内容通过自定义的方式添加和移除一些干扰项。比如上面的实现,encrypt 操作如果简单的实现为 bufferedOutputStream.write(n);
那么这个过程其实就是一个简单的文件复制操作而已,因此关于文件加解密的重点就是如何实现 encryt 方法。
1 2 3 4 5 6 7 private static void encrypt (BufferedOutputStream bos, int length, boolean encode) throws IOException { if (encode) { bos.write(length - 10 ); } else { bos.write(length + 10 ); } }
可以看到,这里的加密操作还是非常简单的,就是在加密时对输出流的写操作偏移了 10 个长度,对应的解密操作,在对加密过后文件,进行恢复的时候,要进行相应的反向操作。
测试一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Main { private static final String INPUT_FILE = "./resources/poet.txt" ; private static final String MIDDLE_FILE = "./resources/poet_secret.txt" ; private static final String OUTPUT_FILE = "./resources/poet_rollback.txt" ; public static void main (String[] args) { try (MethodCost cost = new MethodCost()) { boolean result = FileEncryptor.encryptFile(INPUT_FILE, MIDDLE_FILE, true ); System.out.println("result is " + result); } try (MethodCost cost = new MethodCost()) { boolean result1 = FileEncryptor.encryptFile(MIDDLE_FILE, OUTPUT_FILE, false ); System.out.println("result1 is " + result1); } simpleTextTest(); } }
1 2 3 4 result is true method cost :3617700 result1 is true method cost :1532200
从总体执行多次的结果来看,加密时间还是比解密长的。
再看一下最终输出的文件
文件变化
poet.txt
1 2 3 先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。 。。。。。
poet_secret.txt
1 �{~ۮ��w�ޥ�岂�}�ڮ��y�ۅ��w��z�ܵv�vx ڱ�۳��ݜ�岂ڮ�ޗ�ܬ�ߑ�岂ڮ�ݕ��vޞ
poet_rollback.txt
1 2 先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。 。。。。。
这里以《出师表》全文作为实例,可以看到加密之后,txt 文本再次打开已经完全变成了乱码,解码之后的文件又恢复到了最初的样子。
总结 文本或二级制文件加密、解密本质上其实都是一样的,都是回归到对编码的再次操作,不同的加密或解密方式,唯一的区别就是编码方式的实现不同而已。