转载地址:http://blog.csdn.net/ligaoyang/article/details/6867356
问题:
看了一下openssl enc命令的帮助信息,发现他的【in】参数只能接收一个文件,对这个文件加密后,输出一个新的加密后的文件。并不接收字符串作为加密对象。
客户给出的方案是,在磁盘上建立一个文件,将动态的字符串写入文件中,然后调用openssl enc加密,再读取加密后的文件,将加密后的数据发送给另外一个系统。完成这个操作后,建立的文件以及openssl输出的文件就没有用了,还需要将这些垃圾文件删除。
虽可行,但是涉及到并发访问以及文件操作,会很麻烦。
解决方案:
几经辗转,终于被我找到一个雅一点的解决方案,不会涉及到并发访问,也没有文件操作。
概要:
这里首先对 openssl enc 的参数【in】和【out】做一下深入的了解。
【in】参数接收一个文件作为加密对象,其实他还可以从标准输入读取数据。而且缺省就是从标准输入读取数据。
【out】参数会输出一个加密后的文件,他也一样可以将加密数据输出到标准输出设备上,而且缺省就是标准输出。
注意:从标准输入读取数据,并非就是在【in】参数后面直接输入加密的字符串,有兴趣的童鞋可以试一下,如果在【in】参数后面直接输入字符串,系统会毫不犹豫的告诉你:“加密的字符串“: No such file or directory
要实现从标准输入读取数据,需要使用管道命令 “|”。稍后会讲解。
OK,数据输入问题解决了。
因为不想涉及文件操作,所以我会将加密后的数据输出到标准输出上,然后从Java程序中捕获输出流,并读取加密数据。
下面就详细讲解实现过程
实现:
先对管道命令做个简单的介绍。基本格式是:command1| command2
简而言之,就是将命令【command1】的输出作为命令【command2】的输入。前提是【command2】必须可以接收标准输入。
第一步:Openssl命令的实现
- echo -E "{0}" | openssl aes-128-cbc -e -kfile {1} -base64
1. {0}就是要加密的数据,因为是动态的,我会在命令执行前,将它替换为真实的数据。
2.命令【ehco】就是向标准输出设备输出引号中的内容。这里将使用管道命令”|“将【echo】命令的输出作为【openssl】命令的输入。
注意:参数【-E】的作用是将引号的内容原本输出,而不做转义处理。否则,如果加密数据中含有特殊字符,会导致命令执行失败。
3.命令中没有【out】参数,命令的执行结果会缺省的输出到标准输出上。
4.参数【-kfile】是加密口令,它也必须接收一个文件参数。但是openssl也提供了非文件口令的参数 :【-k ”加密口令“】。加密口令是固定的,所以这里使用【-kefile】的方式,也便于将来管理员修改加密口令。{1}也会在执行命令前,被替换为真实的口令文件名。这不是本文的重点,有所了解即可。
第二部:在Java程序中调用Shell命令
- /**
- * 数据加密处理
- *
- * @param data 要加密的数据
- * @param commonKey 加密口令文件名
- * @return 加密数据
- */
- public static final synchronized String encryption(String data, String commonKey){
- // 加密后的数据定义
- String encryptionData = "";
- try {
- // 加密命令
- String encryption = "echo -E \"{0}\" | openssl aes-128-cbc -e -kfile {1} -base64";
- // 替换命令中占位符
- encryption = MessageFormat.format(encryption, data, commonKey);
- String[] sh = new String[]{"/bin/sh", "-c", encryption};
- // Execute Shell Command
- ProcessBuilder pb = new ProcessBuilder(sh);
- Process p = pb.start();
- encryptionData = getShellOut(p);
- } catch (Exception e) {
- throw new EncryptionException(e);
- }
- return encryptionData;
- }
第三部:在Java程序中捕获Shell命令的输出流,并读取加密数据
- /**
- * 读取输出流数据
- *
- * @param p 进程
- * @return 从输出流中读取的数据
- * @throws IOException
- */
- public static final String getShellOut(Process p) throws IOException{
- StringBuilder sb = new StringBuilder();
- BufferedInputStream in = null;
- BufferedReader br = null;
- try {
- in = new BufferedInputStream(p.getInputStream());
- br = new BufferedReader(new InputStreamReader(in));
- String s;
- while ((s = br.readLine()) != null) {
- // 追加换行符
- sb.append(ConstantUtil.LINE_SEPARATOR);
- sb.append(s);
- }
- } catch (IOException e) {
- throw e;
- } finally {
- br.close();
- in.close();
- }
- return sb.toString();
- }
到此为止,就完成了Java调用openssl命令,实现内存中加密的功能。