Linux下Java程序调用Openssl命令实现内存中加密数据

项目需求:

对一段动态字符串使用openssl加密,并且将加密后的数据发送给另外一个系统。

问题:

看了一下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命令,实现内存中加密的功能。

你可能感兴趣的:(Linux)