当前位置:
代码迷
>>
Android
>> Android跟.NET通用的DES算法
详细解决方案
Android跟.NET通用的DES算法
热度:
111
发布时间:
2016-05-01 18:24:14.0
Android和.NET通用的DES算法
Android和.NET通用的DES算法
1,Java源代码
/** * 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位外其它位数据发生了变化,请务必对此保持高度重视! * @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); } }}
查看全文
相关解决方案
android 读取byte[]中的元素解决方案
android 标题栏兑现方式
android 中Activity向BroadcastReceiver发送数据,该怎么解决
Android 4.0 为什么模拟器老是提示小弟我谷歌拼音输入法已停止
android:getSharedPreferences() 这是哪个类的方法解决思路
android 怎么判断一个程序是否联网
android 大量数据按周分组,该如何解决
android RadioButton如何设置默认选中
ksoap2-android-这个包,连接webService怎么设置超时
android 怎么重新设置锚点
android UI界面设计解决方案
android 图片对象获取的有关问题
android 怎么调用淘宝支付宝接口
Android 沿袭InputMethodService自定义输入法
android 关于服务连接的疑义
android 两个activity如何通信
android 怎么实现对view的放大和缩小
android 教程解决方法
android ID,该如何处理
准备复习2-3个月,看java+android,请问有经验者,怎么看效果最好》
android UI线程与AsyncTask的有关问题
android(java)中的java.net能不能和c#的system.net.sockets进行tcp通信,该如何解决
android ListView 中的onItemClick Intent 没法跳转
android(java) 中文乱码的有关问题
c#c++,android,ios(iphone),php,java视屏课程 散分
android Post文件到ASP.NET的有关问题,能收到参数收不到文件
RIM 替 Android 开发者提供免费的 PlayBook!2月13日前
android 动态设立控件高度
Android test project 编译方法
android -相机使用教程(1)解决方法