Java实现DES对称加密算法(附Android下3DES的JNI源码)

Java实现DES对称加密算法

    转载请注明出处:http://blog.csdn.net/wtbee/article/details/11658017

    Sun公司在Java Platform Standard Ed.6中引入了javax.crypto软件包,javax.crypto软件包为加密操作提供类和接口。在此包中定义的加密操作包括加密、密钥生成和密钥协商,以及消息验证码(Message Authentication Code,MAC)生成。 加密支持包括对称密码、非对称密码、块密码和流密码。此包还支持安全流和密封的对象。此包中提供的许多类都是基于提供者的。该类本身定义可以写入应用程序的编程接口。然后可由独立的第三方供应商编写实现本身,并根据需要无缝嵌入。因此,应用程序开发人员可以利用任意数量的基于提供者的实现,而无需添加或重写代码。

    下面将以DES加密算法为例来介绍怎么使用Sun公司提供的开发包来实现常用的DES对称加密算法。起初在网上找了很多java实现DES加密算法的源码,在自己的调试过程当中发现大部分都存在着加解密错误的问题,不同的源码用相同的明文和密钥来测试得到的密文结果是不一致的。所以,我还是回到了利用现成的开发包来实现DES算法的路线上来。长话短说,要实现DES加密算法必须用到javax.crypto包中的Cipher类,此类为加密和解密提供密码功能。它构成了 Java Cryptographic Extension (JCE) 框架的核心。为创建 Cipher 对象,应用程序需调用 Cipher 的 getInstance 方法并将所请求‘转换’的名称传递给它。还可以指定提供者的名称(可选)。‘转换’ 是一个字符串,它描述为产生某种输出而在给定的输入上执行的操作(或一组操作)。‘转换’始终包括加密算法的名称(例如,DES),后面可能跟有一个反馈模式和填充方案。

‘转换’具有以下形式:

  • “算法/模式/填充” 
  • “算法”

(后一种情况下,使用模式和填充方案特定于提供者的默认值)。例如,以下是有效的转换:

     Cipher c =Cipher.getInstance("DES/CBC/PKCS5Padding");

    使用 CFB 和 OFB 之类的模式,Cipher 块可以加密单元中小于该 Cipher 的实际块大小的数据。请求这样一个模式时,可以指定一次处理的位数(可选):将此数添加到模式名称中,正如 "DES/CFB8/NoPadding" 和 "DES/OFB32/PKCS5Padding"转换所示。如果未指定该数,则将使用特定于提供者的默认值。(例如,SunJCE 提供者对 DES 使用默认的 64 位)。因此,通过使用如 CFB8 或 OFB8 的 8 位模式,Cipher 块可以被转换为面向字节的 Cipher 流。

    为了能够独立于平台的相关特性和独立使用加解密的相关功能,在初始化Cipher实例时一般指定为:"DES/CBC/NoPadding",也就是选择无填充模式。接下来我们就要对Cipher对象的实例进行初始化,其init()方法可以有如下形式:

void	init(int opmode, Certificate certificate) 
          用取自给定证书的公钥初始化此 Cipher。
 void	init(int opmode, Certificate certificate, SecureRandom random) 
          用取自给定证书的公钥和随机源初始化此 Cipher。
 void	init(int opmode, Key key) 
          用密钥初始化此 Cipher。
 void	init(int opmode, Key key, AlgorithmParameters params) 
          用密钥和一组算法参数初始化此 Cipher。
 void	init(int opmode, Key key, AlgorithmParameterSpec params) 
          用密钥和一组算法参数初始化此 Cipher。
 void	init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) 
          用一个密钥、一组算法参数和一个随机源初始化此 Cipher。
 void	init(int opmode, Key key, AlgorithmParameters params, SecureRandom random) 
          用一个密钥、一组算法参数和一个随机源初始化此 Cipher。
 void	init(int opmode, Key key, SecureRandom random) 
          用密钥和随机源初始化此 Cipher。

对不同的密码算法我们需选择不同的初始化方法,其中opmode(运行模式)和key(密钥)一般是必须使用的,opmode包括一下四种类型: encryption, decryption, key wrapping , key unwrapping。第三个参数可以不选也可以选择SecureRandom源或者一组算法参数,这里我们使用AlgorithmParameterSpec。IvParameterSpec继承自AlgorithmParameterSpec类,它指定一个初始化向量 (IV)。使用 IV 的例子是反馈模式中的密码,如,CBC 模式中的 DES 和使用OAEP 编码操作的 RSA 密码。 通常我们用一个Byte数组来初始化一个IvParameterSpec对象,如:

IvParameterSpec ivprama = new IvParameterSpec(algorithmprama);

    值得注意的是:初始化一个Cipher对象,它将失去之前所有的获得的状态,也就是说初始化一个Cipher对象等于创建一个新的Cipher对象并初始化它。完成了Key和Cipher的初始化之后,我们就可以用Cipher对象来进行加解密了。下面贴上源码:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;

public class Des_java
{
	private final static String DES = "DES";
	private static byte[] algorithmprama =
	{ 1, 2, 3, 4, 5, 6, 7, 8 };

	public static byte[] encrypt(byte[] src, byte[] key) throws Exception
	{
		IvParameterSpec ivprama = new IvParameterSpec(algorithmprama);
		DESKeySpec dks = new DESKeySpec(key);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
		SecretKey securekey = keyFactory.generateSecret(dks);
		Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
		cipher.init(Cipher.ENCRYPT_MODE, securekey, ivprama); // 用密钥,算法参数初始化Cipher对象
		return cipher.doFinal(src, 0, src.length);
	}

	public static byte[] decrypt(byte[] src, byte[] key) throws Exception
	{
		IvParameterSpec ivprama = new IvParameterSpec(algorithmprama);
		DESKeySpec dks = new DESKeySpec(key);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
		SecretKey securekey = keyFactory.generateSecret(dks);
		Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
		cipher.init(Cipher.DECRYPT_MODE, securekey, ivprama);// 用密钥,算法参数初始化Cipher对象
		return cipher.doFinal(src, 0, src.length);
	}

	public static byte[] setByteEncrypt(byte[] src, byte[] key)
	{
		byte[] cipher = null;
		try
		{
			int length = src.length;
			if (length <= 0)
			{
				return null;
			}
			if (length % 8 == 0)
			{
				cipher = encrypt(src, key);
			} else
			{
				int i = length + 8 - (length % 8);
				byte[] result = new byte[i];
				System.arraycopy(src, 0, result, 0, length);
				for (int j = 0; j < (8 - (length % 8)); j++)
				{
					result[j + length] = 0;
				}
				cipher = encrypt(result, key);
			}
		} catch (Exception e)
		{
			e.printStackTrace();
		}
		return cipher;

	}

	public static byte[] getByteDecrypt(byte[] src, byte[] key)
			throws Exception
	{
		byte[] cipher = null;
		try
		{
			int length = src.length;
			if (length <= 0)
			{
				return null;
			}
			if (length % 8 == 0)
			{
				cipher = decrypt(src, key);
			} else
			{
				int i = length + 8 - (length % 8);
				byte[] result = new byte[i];
				System.arraycopy(src, 0, result, 0, length);
				for (int j = 0; j < (8 - (length % 8)); j++)
				{
					result[j + length] = 0;
				}
				cipher = decrypt(result, key);
			}
		} catch (Exception e)
		{
			e.printStackTrace();
		}
		return cipher;
	}
    该程序可对任意长度的Byte数组进行独立的加密或者解密,最后附上运行效果:


    上面介绍了用Java自带的开发包来编写Des加密算法的过程,然而很多时候我们需要在项目中开发一个通用的加密模块,并且需要与其它平台进行通信,文章开始也提到过这样可能会带来不同平台之间DES加解密的结果存在差异的问题。特别是现在的移动开发越来越注重通信的安全,加密的应用也越来越广泛,如何在现在流行的移动开发中引入数据加密的功能也越来越受到了开发者的重视。现有的对称加密算法中,应用最为广泛、安全级别较高的是大家都很熟悉的3DES加密算法。下面将介绍在Android移动开发中利用JNI技术实现3DES加密算法的通用模块。

    首先,需要用C/C++语言来实现3DES加密算法。目前网络上有很多的实现源码,大家都可以借鉴然后根据需要修改就可以了。

    然后,有了C/C++实现的3DES源码在很多平台下都可以使用,如QT、Windows、甚至于常用的服务器。移动端开发如Android的话也可以使用这个源码来作为加密的一个模块,因为Android为我们提供了很强大的JNI调用平台。由于加解密都是使用的同一C/C++源码,且移动平台的底层也是用C来实现的,所以不同平台之间的加解密是一致的,这就解决了之前提到的那个让人困扰的问题。

    我之前正好开发了这样一个项目,其需要Android应用与服务器之间的通信经过加密传输来保障通信的安全性(涉及到个人隐私的相关信息)。其解决方案如上所述,最终经过大量测试系统一直稳定运行。下面附上源码(有需要的朋友可以下载,有不足的地方还请斧正!):http://download.csdn.net/detail/wtbee/6735777

 

 

 

你可能感兴趣的:(java,des,3des,android应用,加密算法)