Android和.NET通用的DES算法

Android和.NET通用的DES算法

/** * DES算法理论 本世纪五十年代以来,密码学研究领域出现了最具代表性的两大成就。其中之一就是1971年美国学者塔奇曼 (Tuchman)和麦耶(Meyer)根据信息论创始人香农(Shannon)提出的「多重加密有效性理论」创立的,后於1977年由美国国家标準局颁布的数据加密标準。 DES密码实际上是Lucifer密码的进一步发展。它是一种採用传统加密方法的区组密码。它的算法是对称的,既可用於加密又可用於解密。 美国国家标準局1973年开始研究除国防部外的其它部门的计算机系统的数据加密标準,於1973年5月15日和1974年8月27日先后两次向公眾发出了徵求加密算法的公告。 加密算法要达到的目的通常称為DES密码算法要求主要為以下四点: 提供高质量的数据保护,防止数据未经授权的洩露和未被察觉的修改;具有相当高的复杂性,使得破译的开销超过可能获得的利益,同时又要便於理解和掌握 DES密码体制的安全性应该不依赖於算法的保密,其安全性仅以加密密钥的保密為基础实现经济,运行有效,并且适用於多种完全不同的应用。 1977年1月,美国政府颁布:採纳IBM公司设计的方案作為非机密数据的正式数据加密标準(DES枣Data Encryption Standard)。 目前在这裡,随著三金工程尤其是金卡工程的啟动,DES算法在POS、ATM、磁卡及智能卡(IC卡)、加油站、高速公路收费站等领域被广泛应用,以此来实现关键数据的保密,如信用卡持卡人的PIN的加密传输,IC卡与POS间的双向认证、金融交易数据包的MAC校验等,均用到DES算法。 DES算法的入口参数有三个:Key、Data、Mode。其中Key為8个字节共64位,是DES算法的工作密钥;Data也為8个字节64位,是要被加密或被解密的数据;Mode為DES的工作方式,有两种:加密或解密。 DES算法是这样工作的:如Mode為加密,则用Key 去把数据Data进行加密, 生成Data的密码形式(64位)作為DES的输出结果;如Mode為解密,则用Key去把密码形式的数据Data解密,还原為Data的明码形式(64位)作為DES的输出结果。在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、MAC等)在公共通信网中传输的安全性和可靠性。 通过定期在通信网络的源端和目的端同时改用新的Key,便能更进一步提高数据的保密性,这正是现在金融交易网络的流行做法。 DES算法详述 DES算法把64位的明文输入块变為64位的密文输出块,它所使用的密钥也是64位,其功能是把输入的64位数据块按位重新组合,并把输出分為L0、R0两部分,每部分各长32位,其置换规则见下表: 58,50,12,34,26,18,10,2,60,52,44,36,28,20,12,4, 62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8, 57,49,41,33,25,17, 9,1,59,51,43,35,27,19,11,3, 61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7, 即将输入的第58位换到第一位,第50位换到第2位,...,依此类推,最后一位是原来的第7位。L0、R0则是换位输出后的两部分,L0是输出的左32位,R0 是右32位,例:设置换前的输入值為D1D2D3......D64,则经过初始置换后的结果為:L0=D550...D8;R0=D57D49...D7。 经过26次迭代运算后。得到L16、R16,将此作為输入,进行逆置换,即得到密文输出。逆置换正好是初始置的逆运算,例如,第1位经过初始置换后,处於第40位,而通过逆置换,又将第40位换回到第1位,其逆置换规则如下表所示: 40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31, 38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29, 36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27, 34,2,42,10,50,18,58 26,33,1,41, 9,49,17,57,25, 放大换位表 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10,11, 12,13,12,13,14,15,16,17,16,17,18,19,20,21,20,21, 22,23,24,25,24,25,26,27,28,29,28,29,30,31,32, 1, 单纯换位表 16,7,20,21,29,12,28,17, 1,15,23,26, 5,18,31,10, 2,8,24,14,32,27, 3, 9,19,13,30, 6,22,11, 4,25, 在f(Ri,Ki)算法描述图中,S1,S2...S8為选择函数,其功能是把6bit数据变為4bit数据。下面给出选择函数Si(i=1,2......8)的功能表: 选择函数Si S1: 14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7, 0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8, 4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0, 15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13, S2: 15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10, 3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5, 0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15, 13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9, S3: 10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8, 13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1, 13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7, 1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12, S4: 7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15, 13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9, 10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4, 3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14, S5: 2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9, 14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6, 4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14, 11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3, S6: 12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11, 10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8, 9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6, 4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13, S7: 4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1, 13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6, 1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2, 6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12, S8: 13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7, 1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2, 7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8, 2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11, 在此以S1為例说明其功能,我们可以看到:在S1中,共有4行数据,命名為0,1、2、3行;每行有16列,命名為0、1、2、3,......,14、15列。 现设输入為: D=D1D2D3D4D5D6 令:列=D2D3D4D5 行=D1D6 然后在S1表中查得对应的数,以4位二进製表示,此即為选择函数S1的输出。下面给出子密钥Ki(48bit)的生成算法 从子密钥Ki的生成算法描述图中我们可以看到:初始Key值為64位,但DES算法规定,其中第8、16、......64位是奇偶校验位,不参与DES运算。故Key 实际可用位数便只有56位。即:经过缩小选择换位表1的变换后,Key 的位数由64 位变成了56位,此56位分為C0、D0两部分,各28位,然后分别进行第1次循环左移,得到C1、D1,将C1(28位)、D1(28位)合併得到56位,再经过缩小选择换位2,从而便得到了密钥K0(48位)。依此类推,便可得到K1、K2、......、K15,不过需要注意的是,16次循环左移对应的左移位数要依据下述规则进行: 循环左移位数 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 以上介绍了DES算法的加密过程。DES算法的解密过程是一样的,区别仅仅在於第一次迭代时用子密钥K15,第二次K14、......,最后一次用K0,算法本身并没有任何变化。 DES算法具有极高安全性,到目前為止,除了用穷举搜索法对DES算法进行攻击外,还没有发现更有效的办法。而56位长的密钥的穷举空间為256,这意味著如果一台计算机的速度是每一秒种检测一百万个密钥,则它搜索完全部密钥就需要将近2285年的时间,可见,这是难以实现的,当然,随著科学技术的发展,当出现超高速计算机后,我们可考虑把DES密钥的长度再增长一些,以此来达到更高的保密程度。 由上述DES算法介绍我们可以看到:DES算法中只用到64位密钥中的其中56位,而第8、16、24、......64位8个位并未参与DES运算,这一点,向我们提出了一个应用上的要求,即DES的安全性是基於除了8,16,24,......64位外的其餘56位的组合变化256才得以保证的。因此,在实际应用中,我们应避开使用第8,16,24,......64位作為有效数据位,而使用其它的56位作為有效数据位,才能保证DES算法安全可靠地发挥作用。如果不瞭解这一点,把密钥Key的8,16,24,..... .64位作為有效数据使用,将不能保证DES加密数据的安全性,对运用DES来达到保密作用的系统產生数据被破译的危险,这正是DES算法在应用上的误区,是各级技术人员、各级领导在使用过程中应绝对避免的,而当今各金融部门及非金融部门,在运用DES工作,掌握DES工作密钥Key的领导、主管们,极易忽略,给使用中貌似安全的系统,留下了被人攻击、被人破译的极大隐患。 DES算法应用误区的验证数据 笔者用Turbo C编写了DES算法程序,并在PC机上对上述的DES 算法的应用误区进行了騅,其验证数据如下: Key: 0x30 0x30 0x30 0x30......0x30(8个字节) Data: 0x31 0x31 0x31 0x31......0x31(8个字节) Mode: Encryption 结果:65 5e a6 28 cf 62 58 5f 如果把上述的Key换為8个字节的0x31,而Data和Mode均不变,则执行DES 后得到的密文完全一样。类似地,用Key:8个0x32和用Key:8个0x33 去加密Data (8 个0x31),二者的图文输出也是相同的:5e c3 ac e9 53 71 3b ba 我们可以得到出结论: Key用0x30与用0x31是一样的; Key用0x32与用0x33是一样的,...... 当Key由8个0x32换成8个0x31后,貌似换成了新的Key,但由於0x30和0x31仅仅是在第8,16,24......64有变化,而DES算法并不使用Key的第8,16,......64位作為Key的有效数据位,故:加密出的结果是一样的。 DES解密的验证数据: Key: 0x31 0x31......0x31(8个0x31) Data: 65 5e a6 28 cf 62 58 5f Mode: Decryption 结果:0x31 0x31......0x31(8个0x31) 由以上看出:DES算法加密与解密均工作正确。唯一需要避免的是:在应用中,避开使用Key的第8,16......64位作為有效数据位,从而便避开了DES 算法在应用中的误区。 避开DES算法应用误区的具体操作 在DES密钥Key的使用、管理及密钥更换的过程中,应绝对避开DES 算法的应用误区,即:绝对不能把Key的第8,16,24......64位作為有效数据位,来对Key 进行管理。这一点,特别推荐给金融银行界及非金融业界的领导及决策者们,尤其是负责管理密钥的人,要对此点予以高度重视。有的银行金融交易网络,利用定期更换DES密钥Key的办法来进一步提高系统的安全性和可靠性,如果忽略了上述应用误区,那麼,更换新密钥将是徒劳的,对金融交易网络的安全运行将是十分危险的,所以更换密钥一定要保证新Key与旧Key真正的不同,即除了第8,16,24,...64位外其它位数据发生了变化,请务必对此保持高度重视!

1,Java源代码

 * @author zy20022630
 */
/**
 * 本类实现的是基本数据类型上的算法运算
 */
public class DESHelper {
	// 密钥
	private String key;
	// 为了字节数组与字符串互换而使用的
	private static final String BASE64_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*-";
	private static final char[] BASE64_CHARSET = BASE64_CHARS.toCharArray();
	// 声明常量字节数组
	/**
	 * DES算法把64位的明文输入块变為64位的密文输出块,它所使用的密钥也是64位, 其功能是把输入的64位数据块按位重新组合,
	 * 并把输出分為L0、R0两部分,每部分各长32位,其置换规则见下表 即将输入的第58位换到第一位,第50位换到第2位,...,依此类推,
	 * 最后一位是原来的第7位。L0、R0则是换位输出后的两部分, L0是输出的左32位,R0 是右32位,
	 * 例:设置换前的输入值為D1D2D3......D64, 则经过初始置换后的结果為:L0=D550...D8;R0=D57D49...D7
	 */
	private static final int[] IP = { // OK
	58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46,
			38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33,
			25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29,
			21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 }; // 64
	/**
	 * 经过26次迭代运算后。得到L16、R16,将此作為输入,进行逆置换,即得到密文输出。
	 * 逆置换正好是初始置的逆运算,例如,第1位经过初始置换后,处於第40位, 而通过逆置换,又将第40位换回到第1位,其逆置换规则如下表所示:
	 */
	private static final int[] IP_1 = { // OK
	40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46,
			14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12,
			52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50,
			18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 }; // 64
	/**
	 * PC1置换
	 */
	private static final int[] PC_1 = { 57, 49, 41, 33, 25, 17, 9, 1, 58, 50,
			42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44,
			36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6,
			61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 }; // 56
	/**
	 * PC2置换
	 */
	private static final int[] PC_2 = { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21,
			10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47,
			55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36,
			29, 32 }; // 48
	/**
	 * 放大换位表
	 */
	private static final int[] E = { // OK
	32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15,
			16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26,
			27, 28, 29, 28, 29, 30, 31, 32, 1 }; // 48
	/**
	 * 单纯换位表
	 */
	private static final int[] P = { // OK
	16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14,
			32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 }; // 32
	/**
	 * 在f(Ri,Ki)算法描述图中,S1,S2...S8為选择函数,其功能是把6bit数据变為4bit数据。
	 * 下面给出选择函数Si(i=1,2......8)的功能表:选择函数Si
	 */
	private static final int[][][] S_Box = {
			{// S_Box[1] OK
			{ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
					{ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
					{ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
					{ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 } },
			{ // S_Box[2] OK
			{ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
					{ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
					{ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
					{ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 } },
			{ // S_Box[3] OK
			{ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
					{ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
					{ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
					{ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 } },
			{ // S_Box[4] OK
			{ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
					{ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },
					{ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
					{ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } },
			{ // S_Box[5] OK
			{ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
					{ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
					{ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
					{ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 } },
			{ // S_Box[6] OK
			{ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
					{ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
					{ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
					{ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 } },
			{ // S_Box[7] OK
			{ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
					{ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
					{ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
					{ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 } },
			{ // S_Box[8] OK
			{ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
					{ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
					{ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
					{ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } } };
	/**
	 * 循环左移位数 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
	 */
	private static final int[] LeftMove = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2,
			2, 2, 2, 1 }; // 左移位置列表

	// 构造函数,初始化密钥
	public DESHelper(String key) {
		this.key = key;
	}

	/**
	 * 
	 * @param des_key
	 *            8个字节的密钥字节数组
	 * @param des_data
	 *            8个字节的数据字节数组
	 * @param flag
	 *            1或0,1为加密,0为解密
	 * @return 8个字节的字节数组
	 */
	private byte[] UnitDes(byte[] des_key, byte[] des_data, int flag) {
		// 检测输入参数格式是否正确,错误直接返回空值(null)
		if ((des_key.length != 8) || (des_data.length != 8)
				|| ((flag != 1) && (flag != 0))) {
			throw new RuntimeException("Data Format Error !");
		}
		int flags = flag;
		// 二进制加密密钥
		int[] keydata = new int[64];
		// 二进制加密数据
		int[] encryptdata = new int[64];
		// 加密操作完成后的字节数组
		byte[] EncryptCode = new byte[8];
		// 密钥初试化成二维数组
		int[][] KeyArray = new int[16][48];
		// 将密钥字节数组转换成二进制字节数组
		keydata = ReadDataToBirnaryIntArray(des_key);
		// 将加密数据字节数组转换成二进制字节数组
		encryptdata = ReadDataToBirnaryIntArray(des_data);
		// 初试化密钥为二维密钥数组
		KeyInitialize(keydata, KeyArray);
		// 执行加密解密操作
		EncryptCode = Encrypt(encryptdata, flags, KeyArray);
		return EncryptCode;
	}

	/**
	 * 初试化密钥为二维密钥数组
	 * 
	 * @param key
	 *            int[64]二进制的密钥数组
	 * @param keyarray
	 *            new int[16][48]
	 */
	private void KeyInitialize(int[] key, int[][] keyarray) {
		int i;
		int j;
		int[] K0 = new int[56];
		// 特别注意:xxx[IP[i]-1]等类似变换
		for (i = 0; i < 56; i++) {
			K0[i] = key[PC_1[i] - 1]; // 密钥进行PC-1变换
		}
		for (i = 0; i < 16; i++) {
			LeftBitMove(K0, LeftMove[i]);
			// 特别注意:xxx[IP[i]-1]等类似变换
			for (j = 0; j < 48; j++) {
				keyarray[i][j] = K0[PC_2[j] - 1]; // 生成子密钥keyarray[i][j]
			}
		}
	}

	/**
	 * 执行加密解密操作
	 * 
	 * @param timeData
	 *            (int[64])二进制加密数据
	 * @param flag
	 *            1或0,1为加密,0为解密
	 * @param keyarray
	 *            new int[16][48]
	 * @return 长度为8的字节数组
	 */
	private byte[] Encrypt(int[] timeData, int flag, int[][] keyarray) {
		int i;
		byte[] encrypt = new byte[8];
		int flags = flag;
		int[] M = new int[64];
		int[] MIP_1 = new int[64];
		// 特别注意:xxx[IP[i]-1]等类似变换
		for (i = 0; i < 64; i++) {
			M[i] = timeData[IP[i] - 1]; // 明文IP变换
		}
		if (flags == 1) { // 加密
			for (i = 0; i < 16; i++) {
				LoopF(M, i, flags, keyarray);// S盒处理
			}
		} else if (flags == 0) { // 解密
			for (i = 15; i > -1; i--) {
				LoopF(M, i, flags, keyarray);// S盒处理
			}
		}
		for (i = 0; i < 64; i++) {
			MIP_1[i] = M[IP_1[i] - 1]; // 进行IP-1运算
		}
		// 将(int[64]二进制数据字节数组,经过IP、S盒、IP-1处理后,得到的新的)int[64]二进制数据字节数组转换成byte[8]的字节数组
		GetEncryptResultOfByteArray(MIP_1, encrypt);
		// 返回加密数据
		return encrypt;
	}

	/**
	 * 转换8个字节长度的数据字节数组为二进制数组 (一个字节转换为8个二进制)
	 * 
	 * @param intdata
	 *            8个字节的数据字节数组
	 * @return 长度为64的二进制数组
	 */
	private int[] ReadDataToBirnaryIntArray(byte[] intdata) {
		int i;
		int j;
		// 将数据转换为二进制数,存储到数组
		int[] IntDa = new int[8];
		for (i = 0; i < 8; i++) {
			IntDa[i] = intdata[i];// intdata[i]为byte,范围是-128~127
			if (IntDa[i] < 0) {// 故:IntDa[i]范围是-128~127
				IntDa[i] += 256;// IntDa[i]永远不会超过256
				IntDa[i] %= 256;// 所以该处不需要取模,取模后结果还是自己
			}
		}
		int[] IntVa = new int[64];
		for (i = 0; i < 8; i++) {
			for (j = 0; j < 8; j++) {
				IntVa[((i * 8) + 7) - j] = IntDa[i] % 2;
				IntDa[i] = IntDa[i] / 2;
			}
		}
		return IntVa;
	}

	/**
	 * int[64]二进制数据字节数组转换成byte[8]的字节数组
	 * 
	 * @param data
	 *            int[64]二进制数据字节数组
	 * @param value
	 *            byte[8] byte[8]的字节数组
	 */
	private void GetEncryptResultOfByteArray(int[] data, byte[] value) {
		int i;
		int j;
		// 将存储64位二进制数据的数组中的数据转换为八个整数(byte)
		for (i = 0; i < 8; i++) {
			for (j = 0; j < 8; j++) {
				value[i] += (byte) (data[(i << 3) + j] << (7 - j));
			}
		}
		for (i = 0; i < 8; i++) {
			value[i] %= 256;
			if (value[i] > 128) {
				value[i] -= 255;
			}
		}
	}

	/**
	 * 左移
	 * 
	 * @param k
	 * @param offset
	 */
	private void LeftBitMove(int[] k, int offset) {
		int i;
		// 循环移位操作函数
		int[] c0 = new int[28];
		int[] d0 = new int[28];
		int[] c1 = new int[28];
		int[] d1 = new int[28];
		for (i = 0; i < 28; i++) {
			c0[i] = k[i];
			d0[i] = k[i + 28];
		}
		if (offset == 1) {
			for (i = 0; i < 27; i++) { // 循环左移一位
				c1[i] = c0[i + 1];
				d1[i] = d0[i + 1];
			}
			c1[27] = c0[0];
			d1[27] = d0[0];
		} else if (offset == 2) {
			for (i = 0; i < 26; i++) { // 循环左移两位
				c1[i] = c0[i + 2];
				d1[i] = d0[i + 2];
			}
			c1[26] = c0[0];
			d1[26] = d0[0];
			c1[27] = c0[1];
			d1[27] = d0[1];
		}
		for (i = 0; i < 28; i++) {
			k[i] = c1[i];
			k[i + 28] = d1[i];
		}
	}

	/**
	 * S盒处理
	 * 
	 * @param M
	 * @param times
	 * @param flag
	 * @param keyarray
	 */
	private void LoopF(int[] M, int times, int flag, int[][] keyarray) {
		int i;
		int j;
		int[] L0 = new int[32];
		int[] R0 = new int[32];
		int[] L1 = new int[32];
		int[] R1 = new int[32];
		int[] RE = new int[48];
		int[][] S = new int[8][6];
		int[] sBoxData = new int[8];
		int[] sValue = new int[32];
		int[] RP = new int[32];
		for (i = 0; i < 32; i++) {
			L0[i] = M[i]; // 明文左侧的初始化
			R0[i] = M[i + 32]; // 明文右侧的初始化
		}
		for (i = 0; i < 48; i++) {
			RE[i] = R0[E[i] - 1]; // 经过E变换扩充,由32位变为48位
			RE[i] = RE[i] + keyarray[times][i]; // 与KeyArray[times][i]按位作不进位加法运算
			if (RE[i] == 2) {
				RE[i] = 0;
			}
		}
		for (i = 0; i < 8; i++) { // 48位分成8组
			for (j = 0; j < 6; j++) {
				S[i][j] = RE[(i * 6) + j];
			}
			// 下面经过S盒,得到8个数
			sBoxData[i] = S_Box[i][(S[i][0] << 1) + S[i][5]][(S[i][1] << 3)
					+ (S[i][2] << 2) + (S[i][3] << 1) + S[i][4]];
			// 8个数变换输出二进制
			for (j = 0; j < 4; j++) {
				sValue[((i * 4) + 3) - j] = sBoxData[i] % 2;
				sBoxData[i] = sBoxData[i] / 2;
			}
		}
		for (i = 0; i < 32; i++) {
			RP[i] = sValue[P[i] - 1]; // 经过P变换
			L1[i] = R0[i]; // 右边移到左边
			R1[i] = L0[i] + RP[i];
			if (R1[i] == 2) {
				R1[i] = 0;
			}
			// 重新合成M,返回数组M
			// 最后一次变换时,左右不进行互换。此处采用两次变换实现不变
			if (((flag == 0) && (times == 0)) || ((flag == 1) && (times == 15))) {
				M[i] = R1[i];
				M[i + 32] = L1[i];
			} else {
				M[i] = L1[i];
				M[i + 32] = R1[i];
			}
		}
	}

	/**
	 * 把一个字节数组的元素拷贝到另一个字节数组中
	 * 
	 * @param src
	 * @param srcPos
	 * @param dest
	 * @param destPos
	 * @param length
	 */
	private void arraycopy(byte[] src, int srcPos, byte[] dest, int destPos,
			int length) {
		if (dest != null && src != null) {// 当两个都不为空时
			byte[] temp = new byte[length];
			for (int i = 0; i < length; i++) {
				temp[i] = src[srcPos + i];
			}
			for (int i = 0; i < length; i++) {
				dest[destPos + i] = temp[i];
			}
		}
	}

	/**
	 * 格式化字节数组,使其的长度为8的倍数,那些不足的部分元素用0填充
	 * 
	 * @return 一个新的字节数组,其长度比原数组长1-8位
	 */
	private byte[] ByteDataFormat(byte[] data) {
		int len = data.length;
		int padlen = 8 - (len % 8);// 要格式化的字节数组的长度与8的倍数的差值
		int newlen = len + padlen;
		byte[] newdata = new byte[newlen];
		arraycopy(data, 0, newdata, 0, len);
		for (int i = len; i < newlen; i++)
			newdata[i] = 0;
		return newdata;
	}

	/**
	 * 加密解密(主要方法)
	 * 
	 * @param des_key
	 *            密钥字节数组
	 * @param des_data
	 *            要处理的数据字节数组
	 * @param flag
	 *            (1或0),1为加密,0为解密
	 * @return 处理后的数据
	 */
	private byte[] DesEncrypt(byte[] des_key, byte[] des_data, int flag) {
		byte[] format_key = ByteDataFormat(des_key);// 补齐密钥字节数组的长度为8的倍数,不足元素用0补
		byte[] format_data = ByteDataFormat(des_data);// 补齐原始数据字节数组的长度为8的倍数,不足元素用0补
		int datalen = format_data.length;// 补齐后的原始数据字节数组的长度
		int unitcount = datalen / 8;// 补齐后的原始数据字节数组长度是8的多少倍
		byte[] result_data = new byte[datalen];// 用于盛放加密后的结果
		// 每一次循环,都操作8个字节(加密解密)
		for (int i = 0; i < unitcount; i++) {
			byte[] tmpkey = new byte[8];// 真正起作用的密钥字节数组,只有8个字节
			byte[] tmpdata = new byte[8];// 用于参与操作的数据字节数组,只有8个字节
			arraycopy(format_key, 0, tmpkey, 0, 8);
			arraycopy(format_data, i * 8, tmpdata, 0, 8);
			byte[] tmpresult = UnitDes(tmpkey, tmpdata, flag);// 执行操作
			arraycopy(tmpresult, 0, result_data, i * 8, 8);
		}
		return result_data;
	}

	/**
	 * DES加密
	 * 
	 * @param data
	 *            原始数据(长度不能超过9999位)
	 * @return 加密后的数据字节数组
	 */
	public String encrypt(String data) {
		String dataLength = data.length() + "";// 原始数据长度
		// 原始数据长度不满四位的加0补满四位
		if (dataLength.length() == 1) {
			dataLength = "000" + dataLength;
		} else if (dataLength.length() == 2) {
			dataLength = "00" + dataLength;
		}
		if (dataLength.length() == 3) {
			dataLength = "0" + dataLength;
		}
		String sbDate = dataLength + data;// 保证原始数据的前4位为该数据的长度
		byte[] bytekey = key.getBytes();// 密钥字节数组
		byte[] bytedata = sbDate.getBytes();// 原始数据字节数组
		byte[] result = new byte[(bytedata.length + 8) - (bytedata.length % 8)];// 能包含原始数据字节数组的长度是8的倍数的最小字节数组
		result = DesEncrypt(bytekey, bytedata, 1);
		return toBase64(result);
	}

	/**
	 * DES解密
	 * 
	 * @param encryptData
	 *            加密后的数据字节数组
	 * @return 还原后的数据字符串
	 */
	public String decrypt(String encryptData) {
		try {
			byte[] encryptByteArray = fromBase64(encryptData);
			byte[] bytekey = key.getBytes();
			byte[] result = new byte[encryptByteArray.length];
			result = DesEncrypt(bytekey, encryptByteArray, 0);
			String deResult = new String(result);
			int dataLength = Integer.parseInt(deResult.substring(0, 4));
			return deResult.substring(4, dataLength + 4);
		} catch (Exception e) {
			return "";
		}
	}

	/**
	 * 字节数组转换为字符串
	 * 
	 * @param buffer
	 * @return
	 */
	private String toBase64(byte[] buffer) {
		int len = buffer.length, pos = len % 3;
		byte b0 = 0, b1 = 0, b2 = 0;
		switch (pos) {
		case 1:
			b2 = buffer[0];
			break;
		case 2:
			b1 = buffer[0];
			b2 = buffer[1];
			break;
		}
		String returnValue = "";
		int c;
		boolean notleading = false;
		do {
			// c = (b0 & 0xFC) >>> 2;
			c = (b0 & 0xFC) >> 2;
			if (notleading || c != 0) {
				returnValue += BASE64_CHARSET[c];
				notleading = true;
			}
			// c = ((b0 & 0x03) << 4) | ((b1 & 0xF0) >>> 4);
			c = ((b0 & 0x03) << 4) | ((b1 & 0xF0) >> 4);
			if (notleading || c != 0) {
				returnValue += BASE64_CHARSET[c];
				notleading = true;
			}
			// c = ((b1 & 0x0F) << 2) | ((b2 & 0xC0) >>> 6);
			c = ((b1 & 0x0F) << 2) | ((b2 & 0xC0) >> 6);
			if (notleading || c != 0) {
				returnValue += BASE64_CHARSET[c];
				notleading = true;
			}
			c = b2 & 0x3F;
			if (notleading || c != 0) {
				returnValue += BASE64_CHARSET[c];
				notleading = true;
			}
			if (pos >= len) {
				break;
			} else {
				try {
					b0 = buffer[pos++];
					b1 = buffer[pos++];
					b2 = buffer[pos++];
				} catch (Exception x) {
					break;
				}
			}
		} while (true);

		if (notleading) {
			return returnValue;
		}
		return "0";
	}

	/**
	 * 字符串转换为字节数组
	 * 
	 * @param str
	 * @return
	 * @throws Exception
	 */
	private byte[] fromBase64(String str) throws Exception {
		int len = str.length();
		if (len == 0) {
			throw new Exception("Empty string");
		}
		byte[] a = new byte[len + 1];
		int i, j;
		for (i = 0; i < len; i++) {
			try {
				a[i] = (byte) BASE64_CHARS.indexOf(str.charAt(i));
			} catch (Exception x) {
				throw new Exception("Illegal character at #" + i);
			}
		}
		i = len - 1;
		j = len;
		try {
			while (true) {
				a[j] = a[i];
				if (--i < 0) {
					break;
				}
				a[j] |= (a[i] & 0x03) << 6;
				j--;
				// a[j] = (byte)((a[i] & 0x3C) >>> 2);
				a[j] = (byte) ((a[i] & 0x3C) >> 2);
				if (--i < 0) {
					break;
				}
				a[j] |= (a[i] & 0x0F) << 4;
				j--;
				// a[j] = (byte)((a[i] & 0x30) >>> 4);
				a[j] = (byte) ((a[i] & 0x30) >> 4);
				if (--i < 0) {
					break;
				}
				a[j] |= (a[i] << 2);
				j--;
				a[j] = 0;
				if (--i < 0) {
					break;
				}
			}
		} catch (Exception ignored) {
		}

		try { // ignore leading 0-bytes
			while (a[j] == 0) {
				j++;
			}
		} catch (Exception x) {
			return new byte[1]; // one 0-byte
		}
		byte[] result = new byte[len - j + 1];
		arraycopy(a, j, result, 0, len - j + 1);
		return result;
	}
}

2,.NET

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace APP.Common
{
    ///<summary><![CDATA[加密解密帮助类]]></summary>
    public class DESHelper
    {
        //密钥
        private String key;
        //为了字节数组与字符串互换而使用的
        private static String BASE64_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*-";
        private static char[] BASE64_CHARSET = BASE64_CHARS.ToCharArray();
        // 声明常量字节数组
        /**
         * DES算法把64位的明文输入块变為64位的密文输出块,它所使用的密钥也是64位,
         * 其功能是把输入的64位数据块按位重新组合,
         * 并把输出分為L0、R0两部分,每部分各长32位,其置换规则见下表
         * 即将输入的第58位换到第一位,第50位换到第2位,...,依此类推,
         * 最后一位是原来的第7位。L0、R0则是换位输出后的两部分,
         * L0是输出的左32位,R0 是右32位,
         * 例:设置换前的输入值為D1D2D3......D64,
         * 则经过初始置换后的结果為:L0=D550...D8;R0=D57D49...D7
         */
        private static int[] IP = {  //OK
            58, 50, 42, 34, 26, 18, 10, 2, 
            60, 52, 44, 36, 28, 20, 12, 4, 
            62, 54, 46, 38, 30, 22, 14, 6, 
            64, 56, 48, 40, 32, 24, 16, 8, 
            57, 49, 41, 33, 25, 17, 9,  1, 
            59, 51, 43, 35, 27, 19, 11, 3, 
            61, 53, 45, 37, 29, 21, 13, 5, 
            63, 55, 47, 39, 31, 23, 15, 7
        }; // 64
        /**
         * 经过26次迭代运算后。得到L16、R16,将此作為输入,进行逆置换,即得到密文输出。
         * 逆置换正好是初始置的逆运算,例如,第1位经过初始置换后,处於第40位,
         * 而通过逆置换,又将第40位换回到第1位,其逆置换规则如下表所示:
         */
        private static int[] IP_1 = {  //OK
            40, 8, 48, 16, 56, 24, 64, 32, 
            39, 7, 47, 15, 55, 23, 63, 31, 
            38, 6, 46, 14, 54, 22, 62, 30, 
            37, 5, 45, 13, 53, 21, 61, 29, 
            36, 4, 44, 12, 52, 20, 60, 28, 
            35, 3, 43, 11, 51, 19, 59, 27, 
            34, 2, 42, 10, 50, 18, 58, 26, 
            33, 1, 41, 9,  49, 17, 57, 25
        }; // 64
        /**
         * PC1置换
         */
        private static int[] PC_1 = {//OK
            57, 49, 41, 33, 25, 17, 9,  
             1, 58, 50, 42, 34, 26, 18, 
            10,  2, 59, 51, 43, 35, 27, 
            19, 11,  3, 60, 52, 44, 36, 
            63, 55, 47, 39, 31, 23, 15,  
             7, 62, 54, 46, 38, 30, 22, 
            14,  6, 61, 53, 45, 37, 29, 
            21, 13,  5, 28, 20, 12,  4
        }; // 56
        /**
         * PC2置换
         */
        private static int[] PC_2 = {//OK
            14, 17, 11, 24,  1,  5, 
             3, 28, 15,  6, 21, 10, 
            23, 19, 12,  4, 26,  8, 
            16,  7, 27, 20, 13,  2, 
            41, 52, 31, 37, 47, 55, 
            30, 40, 51, 45, 33, 48, 
            44, 49, 39, 56, 34, 53, 
            46, 42, 50, 36, 29, 32
        }; // 48
        /**
         * 放大换位表
         */
        private static int[] E = {  //OK
            32,  1,  2,  3,  4,  5, 
            4,   5,  6,  7,  8,  9, 
            8,   9, 10, 11, 12, 13, 
            12, 13, 14, 15, 16, 17, 
            16, 17, 18, 19, 20, 21, 
            20, 21, 22, 23, 24, 25, 
            24, 25, 26, 27, 28, 29, 
            28, 29, 30, 31, 32,  1
        }; // 48
        /**
         * 单纯换位表
         */
        private static int[] P = { //OK
            16,  7, 20, 21, 
            29, 12, 28, 17,
             1, 15, 23, 26, 
             5, 18, 31, 10, 
             2,  8, 24, 14, 
             32, 27, 3,  9, 
             19, 13, 30, 6, 
             22, 11,  4, 25
        }; // 32
        /**
         * 在f(Ri,Ki)算法描述图中,S1,S2...S8為选择函数,其功能是把6bit数据变為4bit数据。
         * 下面给出选择函数Si(i=1,2......8)的功能表:选择函数Si
         */
        private static int[, ,] S_Box = {
            {// S_Box[1]   OK
                { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
                { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
                { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
                { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 }
            },
            { // S_Box[2]  OK
                { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
                { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
                { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
                { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 }
            },
            { // S_Box[3]  OK
                { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
                { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
                { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
                { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 }
            },
            { // S_Box[4]  OK
                { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
                { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },
                { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
                { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 }
            },
            { // S_Box[5] OK
                { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
                { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
                { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
                { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 }
            },
            { // S_Box[6] OK
                { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
                { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
                { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
                { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 }
            },
            { // S_Box[7] OK
                { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
                { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
                { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
                { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 }
            },
            { // S_Box[8] OK
                { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
                { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
                { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
                { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 }
            } 
        };
        /**
         * 循环左移位数 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
         */
        private static int[] LeftMove = {
            1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
        }; // 左移位置列表

        //构造函数,初始化密钥
        public DESHelper(String key)
        {
            this.key = key;
        }

        /**
         * 
         * param des_key 8个字节的密钥字节数组
         * param des_data 8个字节的数据字节数组
         * param flag 1或0,1为加密,0为解密
         * return 8个字节的字节数组
         */
        private sbyte[] UnitDes(sbyte[] des_key, sbyte[] des_data, int flag)
        {
            // 检测输入参数格式是否正确,错误直接返回空值(null)
            if ((des_key.Length != 8) || (des_data.Length != 8) || ((flag != 1) && (flag != 0)))
            {
                throw new Exception("Data Format Error !");
            }
            int flags = flag;
            // 二进制加密密钥
            int[] keydata = new int[64];
            // 二进制加密数据
            int[] encryptdata = new int[64];
            // 加密操作完成后的字节数组
            sbyte[] EncryptCode = new sbyte[8];
            // 密钥初试化成二维数组
            int[,] KeyArray = new int[16, 48];
            // 将密钥字节数组转换成二进制字节数组
            keydata = ReadDataToBirnaryIntArray(des_key);
            // 将加密数据字节数组转换成二进制字节数组
            encryptdata = ReadDataToBirnaryIntArray(des_data);
            // 初试化密钥为二维密钥数组
            KeyInitialize(keydata, KeyArray);
            // 执行加密解密操作
            EncryptCode = Encrypt(encryptdata, flags, KeyArray);
            return EncryptCode;
        }

        /**
         * 初试化密钥为二维密钥数组
         * param key int[64]二进制的密钥数组
         * param keyarray new int[16][48]
         */
        private void KeyInitialize(int[] key, int[,] keyarray)
        {
            int i;
            int j;
            int[] K0 = new int[56];
            // 特别注意:xxx[IP[i]-1]等类似变换
            for (i = 0; i < 56; i++)
            {
                K0[i] = key[PC_1[i] - 1]; // 密钥进行PC-1变换
            }
            for (i = 0; i < 16; i++)
            {
                LeftBitMove(K0, LeftMove[i]);
                // 特别注意:xxx[IP[i]-1]等类似变换
                for (j = 0; j < 48; j++)
                {
                    keyarray[i, j] = K0[PC_2[j] - 1]; // 生成子密钥keyarray[i][j]
                }
            }
        }

        /**
         * 执行加密解密操作
         * param timeData (int[64])二进制加密数据
         * param flag 1或0,1为加密,0为解密
         * param keyarray new int[16][48]
         * return 长度为8的字节数组
         */
        private sbyte[] Encrypt(int[] timeData, int flag, int[,] keyarray)
        {
            int i;
            sbyte[] encrypt = new sbyte[8];
            int flags = flag;
            int[] M = new int[64];
            int[] MIP_1 = new int[64];
            // 特别注意:xxx[IP[i]-1]等类似变换
            for (i = 0; i < 64; i++)
            {
                M[i] = timeData[IP[i] - 1]; // 明文IP变换
            }
            if (flags == 1)
            { // 加密
                for (i = 0; i < 16; i++)
                {
                    LoopF(M, i, flags, keyarray);
                }
            }
            else if (flags == 0)
            { // 解密
                for (i = 15; i > -1; i--)
                {
                    LoopF(M, i, flags, keyarray);
                }
            }
            for (i = 0; i < 64; i++)
            {
                MIP_1[i] = M[IP_1[i] - 1]; // 进行IP-1运算
            }
            //将(int[64]二进制数据字节数组,经过IP、S盒、IP-1处理后,得到的新的)int[64]二进制数据字节数组转换成byte[8]的字节数组
            GetEncryptResultOfByteArray(MIP_1, encrypt);
            // 返回加密数据
            return encrypt;
        }
        /**
         * 转换8个字节长度的数据字节数组为二进制数组
         * (一个字节转换为8个二进制)
         * param intdata 8个字节的数据字节数组
         * return 长度为64的二进制数组
         */
        private int[] ReadDataToBirnaryIntArray(sbyte[] intdata)
        {
            int i;
            int j;
            // 将数据转换为二进制数,存储到数组
            int[] IntDa = new int[8];
            for (i = 0; i < 8; i++)
            {
                IntDa[i] = intdata[i];//intdata[i]为sbyte,范围是-128~127
                if (IntDa[i] < 0)//故:IntDa[i]范围是-128~127
                {
                    IntDa[i] += 256;
                    IntDa[i] %= 256;//所以IntDa[i]永远比256小
                }
            }
            int[] IntVa = new int[64];
            for (i = 0; i < 8; i++)
            {
                for (j = 0; j < 8; j++)
                {
                    IntVa[((i * 8) + 7) - j] = IntDa[i] % 2;
                    IntDa[i] = IntDa[i] / 2;
                }
            }
            return IntVa;
        }
        /**
         * int[64]二进制数据字节数组转换成byte[8]的字节数组
         * @param data int[64]二进制数据字节数组
         * @param value byte[8] byte[8]的字节数组
         */
        private void GetEncryptResultOfByteArray(int[] data, sbyte[] value)
        {
            int i;
            int j;
            // 将存储64位二进制数据的数组中的数据转换为八个整数(byte)
            for (i = 0; i < 8; i++)
            {
                for (j = 0; j < 8; j++)
                {
                    value[i] += (sbyte)(data[(i << 3) + j] << (7 - j));
                }
            }
            for (i = 0; i < 8; i++)
            {
                value[i] = (sbyte)(value[i] % 256);
                //if (value[i] > 128)
                //{
                //    value[i] -= 255;
                //}
            }
        }
        //左移
        private void LeftBitMove(int[] k, int offset)
        {
            int i;
            // 循环移位操作函数
            int[] c0 = new int[28];
            int[] d0 = new int[28];
            int[] c1 = new int[28];
            int[] d1 = new int[28];
            for (i = 0; i < 28; i++)
            {
                c0[i] = k[i];
                d0[i] = k[i + 28];
            }
            if (offset == 1)
            {
                for (i = 0; i < 27; i++)
                { // 循环左移一位
                    c1[i] = c0[i + 1];
                    d1[i] = d0[i + 1];
                }
                c1[27] = c0[0];
                d1[27] = d0[0];
            }
            else if (offset == 2)
            {
                for (i = 0; i < 26; i++)
                { // 循环左移两位
                    c1[i] = c0[i + 2];
                    d1[i] = d0[i + 2];
                }
                c1[26] = c0[0];
                d1[26] = d0[0];
                c1[27] = c0[1];
                d1[27] = d0[1];
            }
            for (i = 0; i < 28; i++)
            {
                k[i] = c1[i];
                k[i + 28] = d1[i];
            }
        }
        //S盒处理
        private void LoopF(int[] M, int times, int flag, int[,] keyarray)
        {
            int i;
            int j;
            int[] L0 = new int[32];
            int[] R0 = new int[32];
            int[] L1 = new int[32];
            int[] R1 = new int[32];
            int[] RE = new int[48];
            int[,] S = new int[8, 6];
            int[] sBoxData = new int[8];
            int[] sValue = new int[32];
            int[] RP = new int[32];
            for (i = 0; i < 32; i++)
            {
                L0[i] = M[i]; // 明文左侧的初始化
                R0[i] = M[i + 32]; // 明文右侧的初始化
            }
            for (i = 0; i < 48; i++)
            {
                RE[i] = R0[E[i] - 1]; // 经过E变换扩充,由32位变为48位
                RE[i] = RE[i] + keyarray[times, i]; // 与KeyArray[times][i]按位作不进位加法运算
                if (RE[i] == 2)
                {
                    RE[i] = 0;
                }
            }
            for (i = 0; i < 8; i++)
            { // 48位分成8组
                for (j = 0; j < 6; j++)
                {
                    S[i, j] = RE[(i * 6) + j];
                }
                // 下面经过S盒,得到8个数
                sBoxData[i] = S_Box[i, ((S[i, 0] << 1) + S[i, 5]), ((S[i, 1] << 3) + (S[i, 2] << 2) + (S[i, 3] << 1) + S[i, 4])];
                // 8个数变换输出二进制
                for (j = 0; j < 4; j++)
                {
                    sValue[((i * 4) + 3) - j] = sBoxData[i] % 2;
                    sBoxData[i] = sBoxData[i] / 2;
                }
            }
            for (i = 0; i < 32; i++)
            {
                RP[i] = sValue[P[i] - 1]; // 经过P变换
                L1[i] = R0[i]; // 右边移到左边
                R1[i] = L0[i] + RP[i];
                if (R1[i] == 2)
                {
                    R1[i] = 0;
                }
                // 重新合成M,返回数组M
                // 最后一次变换时,左右不进行互换。此处采用两次变换实现不变
                if (((flag == 0) && (times == 0)) || ((flag == 1) && (times == 15)))
                {
                    M[i] = R1[i];
                    M[i + 32] = L1[i];
                }
                else
                {
                    M[i] = L1[i];
                    M[i + 32] = R1[i];
                }
            }
        }
        //把一个字节数组的元素拷贝到另一个字节数组中
        private void arraycopy(sbyte[] src, int srcPos, sbyte[] dest, int destPos, int length)
        {
            if (dest != null && src != null)
            {//当两个都不为空时
                sbyte[] temp = new sbyte[length];
                for (int i = 0; i < length; i++)
                {
                    temp[i] = src[srcPos + i];
                }
                for (int i = 0; i < length; i++)
                {
                    dest[destPos + i] = temp[i];
                }
            }
        }
        /**
         * 格式化字节数组,使其的长度为8的倍数,那些不足的部分元素用0填充
         * return 一个新的字节数组,其长度比原数组长1-8位
         */
        private sbyte[] ByteDataFormat(sbyte[] data)
        {
            int len = data.Length;
            int padlen = 8 - (len % 8);
            int newlen = len + padlen;
            sbyte[] newdata = new sbyte[newlen];
            arraycopy(data, 0, newdata, 0, len);
            for (int i = len; i < newlen; i++)
                newdata[i] = 0;
            return newdata;
        }

        /**
         * 加密解密(主要方法)
         * param des_key 密钥
         * param des_data 要处理的数据
         * param flag (1或0),1为加密,0为解密
         * return 处理后的数据
         */
        private sbyte[] DesEncrypt(sbyte[] des_key, sbyte[] des_data, int flag)
        {
            sbyte[] format_key = ByteDataFormat(des_key);//补齐密钥字节数组的长度为8的倍数,不足元素用0补
            sbyte[] format_data = ByteDataFormat(des_data);//补齐原始数据字节数组的长度为8的倍数,不足元素用0补
            int datalen = format_data.Length;//补齐后的原始数据字节数组的长度
            int unitcount = datalen / 8;//补齐后的原始数据字节数组长度是8的多少倍
            sbyte[] result_data = new sbyte[datalen];//用于盛放加密后的结果
            //每一次循环,都操作8个字节(加密解密)
            for (int i = 0; i < unitcount; i++)
            {
                sbyte[] tmpkey = new sbyte[8];//真正起作用的密钥字节数组,只有8个字节
                sbyte[] tmpdata = new sbyte[8];//用于参与操作的数据字节数组,只有8个字节
                arraycopy(format_key, 0, tmpkey, 0, 8);
                arraycopy(format_data, i * 8, tmpdata, 0, 8);
                sbyte[] tmpresult = UnitDes(tmpkey, tmpdata, flag);//执行操作
                arraycopy(tmpresult, 0, result_data, i * 8, 8);
            }
            return result_data;
        }

        /**
         * DES加密
         * @param data 原始数据(长度不能超过9999位)
         * @return 加密后的数据字节数组
         */
        public String encrypt(String data)
        {
            String dataLength = data.Length + "";//原始数据长度
            //原始数据长度不满四位的加0补满四位
            if (dataLength.Length == 1)
            {
                dataLength = "000" + dataLength;
            }
            else if (dataLength.Length == 2)
            {
                dataLength = "00" + dataLength;
            }
            if (dataLength.Length == 3)
            {
                dataLength = "0" + dataLength;
            }
            String sbDate = dataLength + data;//保证原始数据的前4位为该数据的长度
            sbyte[] bytekey = byteArray2sbyteArray(Str2AscArr(key));
            sbyte[] bytedata = byteArray2sbyteArray(Str2AscArr(sbDate));
            sbyte[] result = new sbyte[(bytedata.Length + 8) - (bytedata.Length % 8)];
            result = DesEncrypt(bytekey, bytedata, 1);
            return toBase64(result);
        }

        /**
         * DES解密
         * @param encryptData 加密后的数据字节数组
         * @return 还原后的数据字符串
         */
        public String decrypt(String encryptData)
        {
            try
            {
                sbyte[] encryptByteArray = fromBase64(encryptData);
                sbyte[] bytekey = byteArray2sbyteArray(Str2AscArr(key));
                sbyte[] result = new sbyte[encryptByteArray.Length];
                result = DesEncrypt(bytekey, encryptByteArray, 0);
                String deResult = AscArr2Str(sbyteArray2byteArray(result));
                int dataLength = System.Int32.Parse(deResult.Substring(0, 4));
                String res = deResult.Substring(4, dataLength + 4);
                String[] ress = res.Split('\0');
                return ress[0];
            }
            catch (Exception e)
            {
                return "";
            }
        }

        /**
         * sbyte[]转换成相应的byte[]
         */
        private byte[] sbyteArray2byteArray(sbyte[] byteArray)
        {
            byte[] returnArray = new byte[byteArray.Length];
            for (int i = 0; i < byteArray.Length; i++)
            {
                if (byteArray[i] < 0)
                {
                    returnArray[i] = (byte)(256 + byteArray[i]);
                }
                else
                {
                    returnArray[i] = (byte)byteArray[i];
                }
            }
            return returnArray;
        }

        /**
         * byte[]转换成相应的sbyte[]
         */
        private sbyte[] byteArray2sbyteArray(byte[] byteArray)
        {
            sbyte[] sbyteArray = new sbyte[byteArray.Length];
            for (int i = 0; i < sbyteArray.Length; i++)
            {
                if (byteArray[i] > 127)
                {
                    sbyteArray[i] = (sbyte)(byteArray[i] - 256);
                }
                else
                {
                    sbyteArray[i] = (sbyte)byteArray[i];
                }
            }
            return sbyteArray;
        }


        /**
         * 字节数组转换为字符串
         * @param buffer
         * @return
         */
        private String toBase64(sbyte[] buffer)
        {
            int len = buffer.Length, pos = len % 3;
            sbyte b0 = 0, b1 = 0, b2 = 0;
            switch (pos)
            {
                case 1:
                    b2 = buffer[0];
                    break;
                case 2:
                    b1 = buffer[0];
                    b2 = buffer[1];
                    break;
            }
            String returnValue = "";
            int c;
            bool notleading = false;
            do
            {
                c = (b0 & 0xFC) >> 2;
                if (notleading || c != 0)
                {
                    returnValue += BASE64_CHARSET[c];
                    notleading = true;
                }
                c = ((b0 & 0x03) << 4) | ((b1 & 0xF0) >> 4);
                if (notleading || c != 0)
                {
                    returnValue += BASE64_CHARSET[c];
                    notleading = true;
                }
                c = ((b1 & 0x0F) << 2) | ((b2 & 0xC0) >> 6);
                if (notleading || c != 0)
                {
                    returnValue += BASE64_CHARSET[c];
                    notleading = true;
                }
                c = b2 & 0x3F;
                if (notleading || c != 0)
                {
                    returnValue += BASE64_CHARSET[c];
                    notleading = true;
                }
                if (pos >= len)
                {
                    break;
                }
                else
                {
                    try
                    {
                        b0 = buffer[pos++];
                        b1 = buffer[pos++];
                        b2 = buffer[pos++];
                    }
                    catch (Exception x)
                    {
                        break;
                    }
                }
            } while (true);

            if (notleading)
            {
                return returnValue;
            }
            return "0";
        }

        /**
         * 字符串转换为字节数组
         * @param str
         * @return
         * @throws Exception 
         */
        private sbyte[] fromBase64(String str)
        {
            int len = str.Length;
            if (len == 0)
            {
                throw new Exception("Empty string");
            }
            sbyte[] a = new sbyte[len + 1];
            int i, j;
            for (i = 0; i < len; i++)
            {
                try
                {
                    a[i] = (sbyte)BASE64_CHARS.IndexOf(str.ToCharArray()[i]);
                }
                catch (Exception x)
                {
                    throw new Exception("Illegal character at #" + i);
                }
            }
            i = len - 1;
            j = len;
            try
            {
                while (true)
                {
                    a[j] = a[i];
                    if (--i < 0)
                    {
                        break;
                    }
                    a[j] |= (sbyte)((a[i] & 0x03) << 6);
                    j--;
                    a[j] = (sbyte)((a[i] & 0x3C) >> 2);
                    if (--i < 0)
                    {
                        break;
                    }
                    a[j] |= (sbyte)((a[i] & 0x0F) << 4);
                    j--;
                    a[j] = (sbyte)((a[i] & 0x30) >> 4);
                    if (--i < 0)
                    {
                        break;
                    }
                    a[j] |= (sbyte)((a[i] << 2));
                    j--;
                    a[j] = 0;
                    if (--i < 0)
                    {
                        break;
                    }
                }
            }
            catch (Exception ignored)
            {
            }

            try
            { // ignore leading 0-bytes
                while (a[j] == 0)
                {
                    j++;
                }
            }
            catch (Exception x)
            {
                return new sbyte[1]; // one 0-byte
            }
            sbyte[] result = new sbyte[len - j + 1];
            arraycopy(a, j, result, 0, len - j + 1);
            return result;
        }

        /**
         *  命名缩写:
            Str: unicode string(统一的字符编码标准, 采用双字节对字符进行编码)字符串
            Arr: unicode array(统一的字符编码标准, 采用双字节对字符进行编码)数组
            Hex: 二进制数据
            Hexbin: 二进制数据用ASCII字符表示 例 字符'1'的hex是0x31表示为hexbin是 '3''1' 
            Asc: ASCII
            Uni: UNICODE
         * 
         */

        // Hex与Hexbin的转换
        private void Hexbin2Hex(byte[] bHexbin, byte[] bHex, int nLen)
        {
            for (int i = 0; i < nLen / 2; i++)
            {
                if (bHexbin[2 * i] < 0x41)
                {
                    bHex[i] = Convert.ToByte(((bHexbin[2 * i] - 0x30) << 4) & 0xf0);
                }
                else
                {
                    bHex[i] = Convert.ToByte(((bHexbin[2 * i] - 0x37) << 4) & 0xf0);
                }

                if (bHexbin[2 * i + 1] < 0x41)
                {
                    bHex[i] |= Convert.ToByte((bHexbin[2 * i + 1] - 0x30) & 0x0f);
                }
                else
                {
                    bHex[i] |= Convert.ToByte((bHexbin[2 * i + 1] - 0x37) & 0x0f);
                }
            }
        }
        private byte[] Hexbin2Hex(byte[] bHexbin, int nLen)
        {
            if (nLen % 2 != 0)
                return null;
            byte[] bHex = new byte[nLen / 2];
            Hexbin2Hex(bHexbin, bHex, nLen);
            return bHex;
        }
        private void Hex2Hexbin(byte[] bHex, byte[] bHexbin, int nLen)
        {
            byte c;
            for (int i = 0; i < nLen; i++)
            {
                c = Convert.ToByte((bHex[i] >> 4) & 0x0f);
                if (c < 0x0a)
                {
                    bHexbin[2 * i] = Convert.ToByte(c + 0x30);
                }
                else
                {
                    bHexbin[2 * i] = Convert.ToByte(c + 0x37);
                }
                c = Convert.ToByte(bHex[i] & 0x0f);
                if (c < 0x0a)
                {
                    bHexbin[2 * i + 1] = Convert.ToByte(c + 0x30);
                }
                else
                {
                    bHexbin[2 * i + 1] = Convert.ToByte(c + 0x37);
                }
            }
        }
        private byte[] Hex2Hexbin(byte[] bHex, int nLen)
        {
            byte[] bHexbin = new byte[nLen * 2];
            Hex2Hexbin(bHex, bHexbin, nLen);
            return bHexbin;
        }


        //数组和字符串之间的转化
        private byte[] Str2Arr(String s)
        {
            return (new UnicodeEncoding()).GetBytes(s);
        }
        private string Arr2Str(byte[] buffer)
        {
            return (new UnicodeEncoding()).GetString(buffer, 0, buffer.Length);
        }

        //字符串转换成字节数组
        private byte[] Str2AscArr(String s)
        {
            return System.Text.UnicodeEncoding.Convert(System.Text.Encoding.Unicode, System.Text.Encoding.UTF8, Str2Arr(s));

        }

        private byte[] Str2HexAscArr(String s)
        {
            byte[] hex = Str2AscArr(s);
            byte[] hexbin = Hex2Hexbin(hex, hex.Length);
            return hexbin;
        }
        //字节数组转换成字符串
        private string AscArr2Str(byte[] b)
        {
            return System.Text.UnicodeEncoding.Unicode.GetString(System.Text.Encoding.Convert(System.Text.Encoding.UTF8, System.Text.Encoding.Unicode, b));
        }

        private string HexAscArr2Str(byte[] buffer)
        {
            byte[] b = Hex2Hexbin(buffer, buffer.Length);
            return AscArr2Str(b);
        }
    }

}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值