最近项目在维护过程中,估计这一周都会没有什么事情做了。于是开始打量自己做完的这个项目,项目在展示方面乏善可陈,然后仔细的想了想,这个项目的亮点无非就在数据加密和解密这一块了。因为是银行的项目,所以对数据的安全要求比较高,其次在这个项目里面学到的就是银行项目开发的严谨,比如说数据类型和前后台数据统一和维护,以及接口的规范。
好了现在就进入到这篇博客的正文,那就是数据的加密解密问题。
通常我们在进行数据的传递的时候都会对请求的数据以及得到的数据进行加解密,这样别人在截取我们应用的数据的时候就不会对我们造成太多的破坏。一般的应用只要进行一些简单的数据加解密就行了,我们一般进行的操作就是用BASE64 或者MD5对数据进行加解密。但是,在王小云教授宣布已经破解了MD5以及利用hash数组进行加解密的算法后,MD5不再是那么安全了,特别是关于银行的和一些对数据比较敏感的开发就只能用更安全或者更复杂的算法进行加解密了。比如DES/AES/等算法。
首先我们来看一下在开发中接触到的密码学。
我们在开发的时候会接触到双向解密和单向加密,其中双向加密又分为对称机密和非对称加密。对称加密就是指的我们用同一秘钥进行加密解密,所以对称加密又称为单密钥加密,它主要运用在一些加密的数据量比较大的场合。对称加密主要的加密算法有DES/3DES/AES.等。其次就是非对称加密,这种加密算法需要有公开秘钥和私有秘钥,也就是说数据通讯的两端必须拥有公开秘钥和私有秘钥的其中一个才能进行数据的加密和解密。非对称加密主要包括了RSA/DSA等算法。第二、就是单向加密,数据只能进行加密不能解密(很多的文章说数据不能解密,我当时就纳闷了,不能解密了那人家怎么对你的数据进行校验啊?在看了算法以后才明白,就是在甲方进行加密然后对乙方公布加密的算法,然后乙方对获得的数据按照乙方给的算法进行数据的校对,通过这样的机制进行数据的传递)。
在本项目中我们主要应用的是AES算法+MD5+SHA算法对数据进行加解密。
下面是主要用到的几个类:
AES加密算法部分代码
import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec;/** * 加密解密 */ public class AESUtil { public static String algorithm ="AES"; public static String enctrypt(String content,String password){ SecretKey key = getKey(algorithm,password); byte [] enCodeFormat = key.getEncoded(); SecretKeySpec ss = new SecretKeySpec(password.getBytes(), algorithm); try { IvParameterSpec iv = new IvParameterSpec(password.getBytes("UTF-8")); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, ss,iv); // cipher.init(Cipher.ENCRYPT_MODE, ss); byte b [] = cipher.doFinal(content.getBytes()); return byteToHex(b); } catch (Exception e) { LogCatLog.e("AES 加密失败",e); } return null; } public static String decrypt(byte [] content,String password){ // SecretKey key = getKey(algorithm,password); // byte [] enCodeFormat = key.getEncoded(); SecretKeySpec ss = new SecretKeySpec(password.getBytes(), algorithm); try { IvParameterSpec iv = new IvParameterSpec(password.getBytes("UTF-8")); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, ss,iv); // cipher.init(Cipher.DECRYPT_MODE, ss); byte b [] = cipher.doFinal(content); return new String(b); } catch (Exception e) { LogCatLog.e("AES 解密失败",e); } return null; } /** * 使用keygenerator 依赖平台,导致Android和java加密出来的密文不一致 * * @param algorithm * @param password * @return */ public static SecretKey getKey(String algorithm,String password){ try { KeyGenerator gen = KeyGenerator.getInstance(algorithm); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); secureRandom.setSeed(password.getBytes()); gen.init(128, secureRandom); // gen.init(128); return gen.generateKey(); } catch (NoSuchAlgorithmException e) { LogCatLog.e("getKey 获取加密密钥失败 ",e); e.printStackTrace(); } return null; } private static String byteToHex(byte [] b){ StringBuilder sb = new StringBuilder(); for (int i = 0; i < b.length; i++) { String s = Integer.toHexString(b[i] & 0xFF); if(s.length()==1){ s = '0'+s; } sb.append(s.toUpperCase()); } return sb.toString(); } public static byte[] hexStrToByte(String hexStr) { if (hexStr == null || hexStr.equals("")) { return null; } hexStr = hexStr.toUpperCase(); int length = hexStr.length() / 2; char[] hexChars = hexStr.toCharArray(); byte[] d = new byte[length]; for (int i = 0; i < length; i++) { int pos = i * 2; d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); } return d; } private static byte charToByte(char c) { int index = "0123456789ABCDEF".indexOf(c); if(index==-1){ index = "0123456789abcdef".indexOf(c); } return (byte)index; } }
MD5算法部分代码
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.security.MessageDigest; /** * @Description 不解释 */ public final class MD5Util { private static final char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'B', 'C', 'D', 'B', 'O', 'T', 'H', 'O', 'F', 'Y', 'O', 'U' }; /** 对文件加密 */ public static String encode(File file) { FileInputStream in = null; MessageDigest md5 = null; try { in = new FileInputStream(file); FileChannel ch = in.getChannel(); MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); md5 = MessageDigest.getInstance("MD5"); md5.update(byteBuffer); } catch (Exception e) { e.printStackTrace(); } finally { try { if(in != null) in.close(); } catch (IOException e) { e.printStackTrace(); } } return toHex(md5.digest()); } /** 对字符串加密 */ public static String encode(String arg) { if (arg == null) { arg = ""; } MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); md5.update(arg.getBytes("utf-8")); } catch (Exception e) { e.printStackTrace(); } return toHex(md5.digest()); } private static String toHex(byte[] bytes) { StringBuffer str = new StringBuffer(32); for (byte b : bytes) { str.append(hexDigits[(b & 0xf0) >> 4]); str.append(hexDigits[(b & 0x0f)]); } return str.toString(); } public static String md5_3(String arg) { if (arg == null) { arg = ""; } MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); byte[] a = md5.digest(arg.getBytes("utf-8")); a = md5.digest(a); md5.update(a); } catch (Exception e) { e.printStackTrace(); } return toHex(md5.digest()); } /** * MD5加密 以byte数组表示的字符串 * 结果与encode(String arg)返回的一样 * * @param bytes 目标byte数组 * @return MD5加密后的字符串 */ public static String getMD5String(String str) { return getMD5String(str.getBytes()); } public static String getMD5String(byte[] bytes) { MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); md5.update(bytes); } catch (Exception e) { e.printStackTrace(); } return toHex(md5.digest()); } public static String toHex2(byte[] bytes){ StringBuffer sb = new StringBuffer(); for (int i = 0; i < bytes.length; i++) { String shex = Integer.toHexString(bytes[i] & 0xff); if(shex.length()==1){ shex='0'+shex; } sb.append(shex); } return sb.toString().toUpperCase(); } public static String getMD5StringQGen(String str) { MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); md5.update(str.getBytes()); } catch (Exception e) { e.printStackTrace(); } return toHex2(md5.digest()); } }