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);
}
}
}