加密方法总集
第一:什么是加密?
加密,是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使获得了已加密的信息,但因不知解密的方法,仍然无法了解信息的内容。大体上分为双向加密和单向加密,而双向加密又分为对称加密和非对称加密(有些资料将加密直接分为对称加密和非对称加密)。
第二:分类
单向加密
MD5加密(Message-Digest Algorithm 5):Message-Digest泛指字节串(Message)的Hash变换,
其实就是加强版的Hash算法(签名),MD5将任意长度的“字节串”变换成一个128bit的大整数,
并且这是一个不可逆的变换过程。
MD5的典型应用:对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例 子,
你将一段话写在一个叫readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案
,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算
MD5时就会发现。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就
是所谓的数字签名应用。
Java实现:
package com.taikang.util; import java.security.MessageDigest; public class MD5Util { private static ThreadLocal<MessageDigest> messageDigestHolder = new ThreadLocal<MessageDigest>(); public final static String MD5(String s) { char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; try { byte[] btInput = s.getBytes(); //获得MD5摘要算法的 MessageDigest 对象 MessageDigest mdInst = MessageDigest.getInstance("MD5"); //使用指定的字节更新摘要 mdInst.update(btInput); //获得密文 byte[] md = mdInst.digest(); //把密文转换成十六进制的字符串形式 int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new String(str); } catch (Exception e) { e.printStackTrace(); return null; } } /*** * * @Title: byteHEX * @Description: * @author wujl * @param ib * @return String 返回类型 */ private static String byteHEX(byte ib) { char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; char[] ob = new char[2]; ob[0] = hexDigits[(ib >>> 4) & 0X0F]; ob[1] = hexDigits[ib & 0X0F]; String s = new String(ob); return s; } /*** * * @Title: getMD5Format * @Description: 计算MD5并转换为32字节明文显示串 * @author wujl * @param data * @return String 返回类型 */ public static String getMD5Format(String data) { try { MessageDigest message = messageDigestHolder.get(); if (message == null) { message = java.security.MessageDigest.getInstance("MD5"); messageDigestHolder.set(message); } message.update(data.getBytes("UTF-8")); byte[] b = message.digest(); String digestHexStr = ""; for (int i = 0; i < 16; i++) { digestHexStr += byteHEX(b[i]); } return digestHexStr; } catch (Exception e) { return null; } } /** * 计算MD5并转换为32字节明文显示串 * @param data * @return */ public static String getMD5Format(String[] data) { try { MessageDigest message = messageDigestHolder.get(); if (message == null) { message = java.security.MessageDigest.getInstance("MD5"); messageDigestHolder.set(message); } for (int i = 0; i < data.length; i++) { message.update(data[i].getBytes("UTF-8")); } byte[] b = message.digest(); String digestHexStr = ""; for (int i = 0; i < 16; i++) { digestHexStr += byteHEX(b[i]); } return digestHexStr; } catch (Exception e) { return null; } } public static void main(String[] args) { System.out.print(MD5Util.MD5("password").length()); System.out.println(); System.out.println(MD5Util.MD5("sdfasdfasdfasdfasdfasdfasf").length()); } }
SHA-1加密:SHA-1是一种数据加密算法,该算法的思想是接收一段明文,然后以一种不可逆的
方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信 息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证
代码)的过程。
原理:单向散列函数的安全性在于其产生散列值的操作过程具有较强的单向性。如果在输入序
列中嵌入密码,那么任何人在不知道密码的情况下都不能产生正确的散列值,从而保证了其安全 性。SHA将输入流按照每块512位(64个字节)进行分块,并产生20个字节的被称为信息认证代码
或信息摘要的输出。该算法输入报文的长度不限,产生的输出是一个160位的报文摘要。输入是按 512 位的分组进行处理的。SHA-1是不可逆的、防冲突,并具有良好的雪崩效应。通过散列算法可 实现数字签名实现,数字签名的原理是将要传送的明文通过一种函数运算(Hash)转换成报文摘要 (不同的明文对应不同的报文摘要),报文摘要加密后与明文一起传送给接受方,接受方将接受的明 文产生新的报文摘要与发送方的发来报文摘要解密比较,比较结果一致表示明文未被改动,如果不 一致表示明文已被篡改。
MAC (信息认证代码)就是一个散列结果,其中部分输入信息是密码,只有知道这个密码的参与者 才能再次计算和验证MAC码的合法性。
Java实现:
package com.taikang.util; import java.security.MessageDigest; /** * SHA1 * */ public class SHA1Util { private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** * Takes the raw bytes from the digest and formats them correct. * * @param bytes * the raw bytes from the digest. * @return the formatted bytes. */ private static String getFormattedText(byte[] bytes) { int len = bytes.length; StringBuilder buf = new StringBuilder(len * 2); // 把密文转换成十六进制的字符串形式 for (int j = 0; j < len; j++) { buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]); buf.append(HEX_DIGITS[bytes[j] & 0x0f]); } return buf.toString(); } public static final String encode(String str){ if (str == null) { return null; } try { MessageDigest messageDigest = MessageDigest.getInstance("SHA1"); messageDigest.update(str.getBytes()); return getFormattedText(messageDigest.digest()); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) { String str = encode("阿伯才的覆盖"); System.out.println(str); } }
SHA1原理代码:
package com.taikang.util; /** * SHA1 加密工具类 输出大写 * @author 刘光英 * @version V1.0 创建时间:2014-12-29 下午6:55:46 */ public class SHA1 { private final int[] abcde = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; // 摘要数据存储数组 private int[] digestInt = new int[5]; // 计算过程中的临时数据存储数组 private int[] tmpData = new int[80]; // 计算sha-1摘要 private int process_input_bytes(byte[] bytedata) { // 初试化常量 System.arraycopy(abcde, 0, digestInt, 0, abcde.length); // 格式化输入字节数组,补10及长度数据 byte[] newbyte = byteArrayFormatData(bytedata); // 获取数据摘要计算的数据单元个数 int MCount = newbyte.length / 64; // 循环对每个数据单元进行摘要计算 for (int pos = 0; pos < MCount; pos++) { // 将每个单元的数据转换成16个整型数据,并保存到tmpData的前16个数组元素中 for (int j = 0; j < 16; j++) { tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4)); } // 摘要计算函数 encrypt(); } return 20; } // 格式化输入字节数组格式 private byte[] byteArrayFormatData(byte[] bytedata) { // 补0数量 int zeros = 0; // 补位后总位数 int size = 0; // 原始数据长度 int n = bytedata.length; // 模64后的剩余位数 int m = n % 64; // 计算添加0的个数以及添加10后的总长度 if (m < 56) { zeros = 55 - m; size = n - m + 64; } else if (m == 56) { zeros = 63; size = n + 8 + 64; } else { zeros = 63 - m + 56; size = (n + 64) - m + 64; } // 补位后生成的新数组内容 byte[] newbyte = new byte[size]; // 复制数组的前面部分 System.arraycopy(bytedata, 0, newbyte, 0, n); // 获得数组Append数据元素的位置 int l = n; // 补1操作 newbyte[l++] = (byte) 0x80; // 补0操作 for (int i = 0; i < zeros; i++) { newbyte[l++] = (byte) 0x00; } // 计算数据长度,补数据长度位共8字节,长整型 long N = (long) n * 8; byte h8 = (byte) (N & 0xFF); byte h7 = (byte) ((N >> 8) & 0xFF); byte h6 = (byte) ((N >> 16) & 0xFF); byte h5 = (byte) ((N >> 24) & 0xFF); byte h4 = (byte) ((N >> 32) & 0xFF); byte h3 = (byte) ((N >> 40) & 0xFF); byte h2 = (byte) ((N >> 48) & 0xFF); byte h1 = (byte) (N >> 56); newbyte[l++] = h1; newbyte[l++] = h2; newbyte[l++] = h3; newbyte[l++] = h4; newbyte[l++] = h5; newbyte[l++] = h6; newbyte[l++] = h7; newbyte[l++] = h8; return newbyte; } private int f1(int x, int y, int z) { return (x & y) | (~x & z); } private int f2(int x, int y, int z) { return x ^ y ^ z; } private int f3(int x, int y, int z) { return (x & y) | (x & z) | (y & z); } private int f4(int x, int y) { return (x << y) | x >>> (32 - y); } // 单元摘要计算函数 private void encrypt() { for (int i = 16; i <= 79; i++) { tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14] ^ tmpData[i - 16], 1); } int[] tmpabcde = new int[5]; for (int i1 = 0; i1 < tmpabcde.length; i1++) { tmpabcde[i1] = digestInt[i1]; } for (int j = 0; j <= 19; j++) { int tmp = f4(tmpabcde[0], 5) + f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[j] + 0x5a827999; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int k = 20; k <= 39; k++) { int tmp = f4(tmpabcde[0], 5) + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[k] + 0x6ed9eba1; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int l = 40; l <= 59; l++) { int tmp = f4(tmpabcde[0], 5) + f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[l] + 0x8f1bbcdc; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int m = 60; m <= 79; m++) { int tmp = f4(tmpabcde[0], 5) + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[m] + 0xca62c1d6; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int i2 = 0; i2 < tmpabcde.length; i2++) { digestInt[i2] = digestInt[i2] + tmpabcde[i2]; } for (int n = 0; n < tmpData.length; n++) { tmpData[n] = 0; } } // 4字节数组转换为整数 private int byteArrayToInt(byte[] bytedata, int i) { return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16) | ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff); } // 整数转换为4字节数组 private void intToByteArray(int intValue, byte[] byteData, int i) { byteData[i] = (byte) (intValue >>> 24); byteData[i + 1] = (byte) (intValue >>> 16); byteData[i + 2] = (byte) (intValue >>> 8); byteData[i + 3] = (byte) intValue; } // 将字节转换为十六进制字符串 private static String byteToHexString(byte ib) { char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; char[] ob = new char[2]; ob[0] = Digit[(ib >>> 4) & 0X0F]; ob[1] = Digit[ib & 0X0F]; String s = new String(ob); return s; } // 将字节数组转换为十六进制字符串 private static String byteArrayToHexString(byte[] bytearray) { String strDigest = ""; for (int i = 0; i < bytearray.length; i++) { strDigest += byteToHexString(bytearray[i]); } return strDigest; } // 计算sha-1摘要,返回相应的字节数组 public byte[] getDigestOfBytes(byte[] byteData) { process_input_bytes(byteData); byte[] digest = new byte[20]; for (int i = 0; i < digestInt.length; i++) { intToByteArray(digestInt[i], digest, i * 4); } return digest; } // 计算sha-1摘要,返回相应的十六进制字符串 public String getDigestOfString(byte[] byteData) { return byteArrayToHexString(getDigestOfBytes(byteData)); } public static void main(String[] args) { String data = "阿伯才的覆盖"; System.out.println(data); String digest = new SHA1().getDigestOfString(data.getBytes()); System.out.println(digest); // System.out.println(ToMD5.convertSHA1(data).toUpperCase()); } }
HMAC:密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),HMAC运算 利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。
定义HMAC需要一个加密用散列函数(表示为H,可以是MD5或者SHA-1)和一个密钥K。我们用B来表
示数据块的字节数。(以上所提到的散列函数的分割数据块字长B=64),用L来表示散列函数的输出数
据字节数(MD5中L=16,SHA-1中L=20)。鉴别密钥的长度可以是小于等于数据块字长的任何正整数值。 应用程序中使用的密钥长度若是比B大,则首先用使用散列函数H作用于它,然后用H输出的L长度字符
串作为在HMAC中实际使用的密钥。一般情况下,推荐的最小密钥K长度是L个字节。
原理:
算法公式 : HMAC(K,M)=H(K⊕opad∣H(K⊕ipad∣M))
H 代表所采用的HASH算法(如SHA-256或者MD5)
K 代表认证密码
Ko 代表HASH算法的密文
M 代表一个消息输入
B 代表H中所处理的块大小,这个大小是处理块大小,而不是输出hash的大小
如,SHA-1和SHA-256 B = 64
SHA-384和SHA-512 B = 128
L 表示hash的大小
Opad 用0x5c重复B次
Ipad 用0x36重复B次
Apad 用0x878FE1F3重复(L/4)次
原理Java实现:
package com.taikang.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.json.JSONObject; /** * * 项目名称:wxwallet * 类名称: HMACMD5Util * 类描述: 调用方授权认证方法为MD5-HMAC,签名方法为(来自RFC2104) HMAC(K,m)=H((K⊕opad)│H((K⊕ipad)│m) ) * 创建人:caoyuchuan * 创建时间:2015年1月5日 下午5:53:15 * @version */ public class HMACMD5Util { private static final String CHARSET_UTF8 = "UTF-8"; protected static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; private static byte[] md5(byte[] str) throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str); return md.digest(); } public static String getHmacMd5StrByUTF8(String skey, String sdata) { byte[] hmacMd5Bytes = {}; try { hmacMd5Bytes = HMACMD5Util.getHmacMd5Bytes(skey, sdata, null); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return HMACMD5Util.bufferToHex(hmacMd5Bytes, 0, hmacMd5Bytes.length); } public static byte[] getHmacMd5Bytes(String skey, String sdata, String charset) throws NoSuchAlgorithmException, UnsupportedEncodingException { if (null == charset) { charset = CHARSET_UTF8; } return HMACMD5Util.getHamcMd5Bytes(skey.getBytes(charset), sdata.getBytes(charset)); } public static byte[] getHamcMd5Bytes(byte[] skey, byte[] sdata) throws NoSuchAlgorithmException, UnsupportedEncodingException { byte[] key = skey; byte[] data = sdata; int length = 64; byte[] ipad = new byte[length]; byte[] opad = new byte[length]; for (int i = 0; i < 64; i++) { ipad[i] = 0x36; opad[i] = 0x5C; } byte[] actualKey = key; // Actual key. byte[] keyArr = new byte[length]; // Key bytes of 64 bytes length if (key.length > length) { actualKey = md5(key); } for (int i = 0; i < actualKey.length; i++) { keyArr[i] = actualKey[i]; } if (actualKey.length < length) { for (int i = actualKey.length; i < keyArr.length; i++) keyArr[i] = 0x00; } byte[] kIpadXorResult = new byte[length]; for (int i = 0; i < length; i++) { kIpadXorResult[i] = (byte) (keyArr[i] ^ ipad[i]); } byte[] firstAppendResult = new byte[kIpadXorResult.length + data.length]; for (int i = 0; i < kIpadXorResult.length; i++) { firstAppendResult[i] = kIpadXorResult[i]; } for (int i = 0; i < data.length; i++) { firstAppendResult[i + keyArr.length] = data[i]; } byte[] firstHashResult = md5(firstAppendResult); byte[] kOpadXorResult = new byte[length]; for (int i = 0; i < length; i++) { kOpadXorResult[i] = (byte) (keyArr[i] ^ opad[i]); } byte[] secondAppendResult = new byte[kOpadXorResult.length + firstHashResult.length]; for (int i = 0; i < kOpadXorResult.length; i++) { secondAppendResult[i] = kOpadXorResult[i]; } for (int i = 0; i < firstHashResult.length; i++) { secondAppendResult[i + keyArr.length] = firstHashResult[i]; } byte[] hmacMd5Bytes = md5(secondAppendResult); return hmacMd5Bytes; } public static String bufferToHex(byte bytes[], int m, int n) { StringBuffer stringbuffer = new StringBuffer(2 * n); int k = m + n; for (int l = m; l < k; l++) { appendHexPair(bytes[l], stringbuffer); } return stringbuffer.toString(); } private static void appendHexPair(byte bt, StringBuffer stringbuffer) { char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>> // 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同 char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换 stringbuffer.append(c0); stringbuffer.append(c1); } public static void main(String[] args) throws Exception { // Post请求 String toString = ""; JSONObject object = new JSONObject(); object.put("msg", "Hello"); toString = object.toString(); byte bt = 0x78; System.out.println(bt); StringBuffer sb = new StringBuffer(); appendHexPair(bt, sb); System.out.println(sb.toString()); // byte[] rdata = getHmacMd5Bytes("thismustkeepsecret", toString); // String str = bufferToHex(rdata, 0, rdata.length); // System.out.println("获取加密结果"+str); } public static byte[] InputStreamToByte(InputStream is) throws IOException { ByteArrayOutputStream bytestream = new ByteArrayOutputStream(); try { byte[] buffer = new byte[1024];// 1k bytes buffer int size = is.read(buffer, 0, 1024); while (size > 0) { bytestream.write(buffer, 0, size); size = is.read(buffer, 0, 1024); } return bytestream.toByteArray(); } finally { is.close(); bytestream.close(); } } }
HMAC应用:
hmac主要应用在身份验证中,它的使用方法是这样的:
1. 客户端发出登录请求(假设是浏览器的GET请求)
2. 服务器返回一个随机值,并在会话中记录这个随机值
3. 客户端将该随机值作为密钥,用户密码进行hmac运算,然后提交给服务器
4. 服务器读取用户数据库中的用户密码和步骤2中发送的随机值做与客户端一样的hmac运算,
然后与用户发送的结果比较,如果结果一致则验证用户合法
在这个过程中,可能遭到安全攻击的是服务器发送的随机值和用户发送的hmac结果,而对于截获
了这两个值的黑客而言这两个值是没有意义的,绝无获取用户密码的可能性,随机值的引入使hmac
只在当前会话中有效,大大增强了安全性和实用性。大多数的语言都实现了hmac算法,比如php的 mhash、python的hmac.py、java的MessageDigest类,在web验证中使用hmac也是可行的,用js
进行md5运算的速度也是比较快的。
盐值加密
实际上,上面的实例在现实使用中还存在着一个不小的问题。虽然md5算法是不可逆的,但是因为
它对同一个字符串计算的结果是唯一的,所以一些人可能会使用“字典攻击”的方式来攻破md5加密
的系统。这虽然属于暴力解密,却十分有效,因为大多数系统的用户密码都不回很长。
实际上,大多数系统都是用admin作为默认的管理员登陆密码,所以,当我们在数据库中看 到“21232f297a57a5a743894a0e4a801fc3”时,就可以意识到admin用户使用的密码了。因此,
md5在处理这种常用字符串时,并不怎么奏效。为了解决这个问题,我们可以使用盐值加密“salt- source”。
修改配置文件:
<authentication-provider> <password-encoder hash="md5"> <salt-source user-property="username"/> </password-encoder> <jdbc-user-service data-source-ref="dataSource"/> </authentication-provider> 在password-encoder下添加了salt-source,并且指定使用username作为盐值。
盐值的原理非常简单,就是先把密码和盐值指定的内容合并在一起,再使用md5对合并后的内容进行演 算,这样一来,就算密码是一个很常见的字符串,再加上用户名,最后算出来的md5值就没那么容易猜出 来了。因为攻击者不知道盐值的值,也很难反算出密码原文。
我们这里将每个用户的username作为盐值,最后数据库中的密码部分就变成了这样:
INSERT INTO USERS VALUES('admin','ceb4f32325eda6142bd65215f4c0f371',TRUE) INSERT INTO USERS VALUES('user','47a733d60998c719cf3526ae7d106d13',TRUE)
双向加密
对称加密:
DES加密:
Java实现:
package com.taikang.util; import java.io.UnsupportedEncodingException; public class DesEncrypts { public DesEncrypts() { } public static String getMd5String(String desstring) { String strkey = "seaway"; int flag=1; return getMd5String(desstring,strkey,flag); } public static String getMd5String(String desstring,String strkey,int flag) { DesEncrypts tdes = new DesEncrypts(); tdes.getKey(strkey); if(flag == 1) return tdes.getDesString(desstring); else if(flag == 0) return tdes.getEncString(desstring); else throw new RuntimeException("�ӽ������Ͳ���ȷ��"); } private byte[] UnitDes(byte des_key[], byte des_data[], int flag) { if(des_key.length != 8 || des_data.length != 8 || flag != 1 && flag != 0) { throw new RuntimeException("Data Format Error !"); } else { 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; } } private void KeyInitialize(int key[], int keyarray[][]) { int K0[] = new int[56]; for(int i = 0; i < 56; i++) K0[i] = key[PC_1[i] - 1]; for(int i = 0; i < 16; i++) { LeftBitMove(K0, LeftMove[i]); for(int j = 0; j < 48; j++) keyarray[i][j] = K0[PC_2[j] - 1]; } } private byte[] Encrypt(int timeData[], int flag, int keyarray[][]) { byte encrypt[] = new byte[8]; int flags = flag; int M[] = new int[64]; int MIP_1[] = new int[64]; for(int i = 0; i < 64; i++) M[i] = timeData[IP[i] - 1]; if(flags == 1) { for(int i = 0; i < 16; i++) LoopF(M, i, flags, keyarray); } else if(flags == 0) { for(int i = 15; i > -1; i--) LoopF(M, i, flags, keyarray); } for(int i = 0; i < 64; i++) MIP_1[i] = M[IP_1[i] - 1]; GetEncryptResultOfByteArray(MIP_1, encrypt); return encrypt; } private int[] ReadDataToBirnaryIntArray(byte intdata[]) { int IntDa[] = new int[8]; for(int i = 0; i < 8; i++) { IntDa[i] = intdata[i]; if(IntDa[i] < 0) { IntDa[i] += 256; IntDa[i] %= 256; } } int IntVa[] = new int[64]; for(int i = 0; i < 8; i++) { for(int j = 0; j < 8; j++) { IntVa[(i * 8 + 7) - j] = IntDa[i] % 2; IntDa[i] = IntDa[i] / 2; } } return IntVa; } private void LeftBitMove(int k[], int offset) { int c0[] = new int[28]; int d0[] = new int[28]; int c1[] = new int[28]; int d1[] = new int[28]; for(int i = 0; i < 28; i++) { c0[i] = k[i]; d0[i] = k[i + 28]; } if(offset == 1) { for(int 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(int 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(int i = 0; i < 28; i++) { k[i] = c1[i]; k[i + 28] = d1[i]; } } private void LoopF(int M[], int times, int flag, int keyarray[][]) { 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(int i = 0; i < 32; i++) { L0[i] = M[i]; R0[i] = M[i + 32]; } for(int i = 0; i < 48; i++) { RE[i] = R0[E[i] - 1]; RE[i] = RE[i] + keyarray[times][i]; if(RE[i] == 2) RE[i] = 0; } for(int i = 0; i < 8; i++) { for(int j = 0; j < 6; j++) S[i][j] = RE[i * 6 + j]; 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]]; for(int j = 0; j < 4; j++) { sValue[(i * 4 + 3) - j] = sBoxData[i] % 2; sBoxData[i] = sBoxData[i] / 2; } } for(int i = 0; i < 32; i++) { RP[i] = sValue[P[i] - 1]; L1[i] = R0[i]; R1[i] = L0[i] + RP[i]; if(R1[i] == 2) R1[i] = 0; 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 GetEncryptResultOfByteArray(int data[], byte value[]) { for(int i = 0; i < 8; i++) { for(int j = 0; j < 8; j++) value[i] += data[(i << 3) + j] << 7 - j; } for(int i = 0; i < 8; i++) { value[i] %= 256; if(value[i] > 128) value[i] -= 255; } } private byte[] ByteDataFormat(byte data[]) { int len = data.length; int padlen = 8 - len % 8; if(padlen == 8) padlen = 0; int newlen = len + padlen; byte newdata[] = new byte[newlen]; System.arraycopy(data, 0, newdata, 0, len); for(int i = len; i < newlen; i++) newdata[i] = 0; return newdata; } public byte[] DesEncrypts(byte des_key[], byte des_data[], int flag) { byte format_key[] = ByteDataFormat(des_key); byte format_data[] = ByteDataFormat(des_data); int datalen = format_data.length; int unitcount = datalen / 8; byte result_data[] = new byte[datalen]; for(int i = 0; i < unitcount; i++) { byte tmpkey[] = new byte[8]; byte tmpdata[] = new byte[8]; System.arraycopy(format_key, 0, tmpkey, 0, 8); System.arraycopy(format_data, i * 8, tmpdata, 0, 8); byte tmpresult[] = UnitDes(tmpkey, tmpdata, flag); System.arraycopy(tmpresult, 0, result_data, i * 8, 8); } if(flag == 0) { int k; for(k = result_data.length - 1; k > 0; k--) if(result_data[k] != 0) break; if(k < result_data.length - 1) { byte tmpresult[] = new byte[k + 1]; System.arraycopy(result_data, 0, tmpresult, 0, k + 1); return tmpresult; } else { return result_data; } } else { return result_data; } } public static String byte2hex(byte b[]) { String hs = ""; String stmp = ""; for(int n = 0; n < b.length; n++) { stmp = Integer.toHexString(b[n] & 0xff); if(stmp.length() == 1) hs = (new StringBuilder(String.valueOf(hs))).append("0").append(stmp).toString(); else hs = (new StringBuilder(String.valueOf(hs))).append(stmp).toString(); } return hs.toUpperCase(); } private static byte toByte(char c) { byte b = (byte)"0123456789ABCDEF".indexOf(c); return b; } public static byte[] hexStringToByte(String hex) { int len = hex.length() / 2; byte result[] = new byte[len]; char achar[] = hex.toCharArray(); for(int i = 0; i < len; i++) { int pos = i * 2; result[i] = (byte)(toByte(achar[pos]) << 4 | toByte(achar[pos + 1])); } return result; } public void getKey(String des_key) { key = des_key; bytekey = key.getBytes(); } public String getDesString(String psData) { result = DesEncrypts(bytekey, hexStringToByte(psData), 0); return new String(result); } public String getEncString(String psData) { data = psData; bytelen = data.getBytes().length; result = new byte[(bytelen + 8) - bytelen % 8]; try { bytedata = data.getBytes("UTF-8"); } catch (Exception e) { e.printStackTrace(); } result = DesEncrypts(bytekey, bytedata, 1); return byte2hex(result); } public static void main(String args[]) throws UnsupportedEncodingException { DesEncrypts des = new DesEncrypts(); des.getKey("123$%^789@guahaocom"); String result = des.getEncString("id=1132132,name=成成,idcard=330303198301253193,[email protected],mobile=13456758654,sex=1"); System.out.println(result); // String[] strs = des.getDesString("A67ECE152F7D3243C65DD2648FED774DC135A8675C1A722F01A91DEFB7405659377ADAEF91E00962E95CBE174D2965C72E688EFE016E20F2A7D02406A21E3760DC7FCA320B3FB43988AB6DB027D59148FC39F36E8924E1F8CACA1F456BAFDA7E").split(","); System.out.println("A67ECE152F7D3243C65DD2648FED774DC135A8675C1A722F01A91DEFB7405659377ADAEF91E00962E95CBE174D2965C72E688EFE016E20F2A7D02406A21E3760DC7FCA320B3FB43988AB6DB027D59148FC39F36E8924E1F8CACA1F456BAFDA7E"); // System.out.println(des.getDesString("A67ECE152F7D3243C65DD2648FED774DC135A8675C1A722F01A91DEFB7405659377ADAEF91E00962E95CBE174D2965C72E688EFE016E20F2A7D02406A21E3760DC7FCA320B3FB43988AB6DB027D59148FC39F36E8924E1F8CACA1F456BAFDA7E")); System.out.println(des.getDesString(result)); } String key; String data; int bytelen; byte result[]; byte bytekey[]; byte bytedata[]; private static final int IP[] = { 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 }; private static final int IP_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 }; 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 }; 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 }; private static final int E[] = { 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 }; private static final int P[] = { 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 }; private static final int S_Box[][][] = { { { 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 } }, { { 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 } }, { { 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 } }, { { 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 } }, { { 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 } }, { { 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 } }, { { 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 } }, { { 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 } } }; private static final int LeftMove[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; }
DES工具类:
package com.taikang.util; public class DESUtil { /** * des加密 * * @param strMing 明文 * @param key 密钥 * @return */ public static String DESEncode(String strMing, String key) { DesEncrypts des = new DesEncrypts(); des.getKey(key); return des.getEncString(strMing); } /** * des解密 * * @param strSecret 密文 * @param key 解密密钥 * @return */ public static String DESDecode(String strSecret, String key) { // System.out.println("key*****:"+key); DesEncrypts des = new DesEncrypts(); des.getKey(key); return des.getDesString(strSecret); } }
非对称加密:与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥
(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。