0x01不安全的加密hash函数
常见的hash函数,像md5,sha1,sha256,它们都是不可逆加密函数。
由于计算机运算能力的提高,md5和sha1函数现在都有比较成熟的破解方法,像彩虹表,字典库等,故建议使用安全的sha256函数对message字符串做哈希。sha256函数在java中的使用方法,参考代码如下。
package com.pc.test;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Encrypt {
public static String SHA256(final String strText) {
return SHA(strText, "SHA-256");
}
private static String SHA(final String strText, final String strType) {
String strResult = null;
if (strText != null && strText.length() > 0) {
try {
MessageDigest messageDigest = MessageDigest
.getInstance(strType);
messageDigest.update(strText.getBytes());
byte byteBuffer[] = messageDigest.digest();
StringBuffer strHexString = new StringBuffer();
for (int i = 0; i < byteBuffer.length; i++) {
String hex = Integer.toHexString(0xff & byteBuffer[i]);
if (hex.length() == 1) {
strHexString.append('0');
}
strHexString.append(hex);
}
strResult = strHexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
return strResult;
}
public static void main(String[] args) throws Exception{
String str = "admin";
System.out.println(SHA256(str));
//result: 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
}
}
0x02安全随机数的生成
在Android加密算法中需要随机数时要使用SecureRandom来获取随机数。注意不要使用Random类来获取随机数,且使用SecureRandom获取随机数时不要设置种子。代码示例如下。
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
0x03对称加密算法DES/AES安全
在使用对称加密算法的过程中,使用DES/AES和AES的AES/EBC/PKCS5Padding模式都是不安全的,(AES默认模式是ECB模式),所以我们要使用安全的对称加密函数AES/CBC/PKCS5Padding模式。使用这些加密函数的过程中,当密钥硬编码程序中时,密钥很容易通过反编译被还原,不建议密钥硬编码在代码中,可以通过白盒加密的方式进行加密,可以调用阿里云开发的安全组件进行相应的安全防护是一个比较好的防御方式。
下面重点说一下加密函数的用法代码
DES对称加密算法的使用
- package com.pc.destest;
-
- import java.security.Key;
- import java.security.SecureRandom;
- import javax.crypto.Cipher;
- import javax.crypto.SecretKey;
- import javax.crypto.SecretKeyFactory;
- import javax.crypto.spec.DESKeySpec;
-
-
- public class DesTest{
-
-
- public static byte[] encrypt(byte[] datasource, String password) throws Exception {
-
-
- SecureRandom random = new SecureRandom();
- Key key = toKey(password.getBytes());
- Cipher cipher = Cipher.getInstance("DES");
- cipher.init(Cipher.ENCRYPT_MODE, key,random);
- return cipher.doFinal(datasource);
- }
-
-
- public static byte[] decrypt(byte[] src, String password) throws Exception {
-
- SecureRandom random = new SecureRandom();
- Key key = toKey(password.getBytes());
- Cipher cipher = Cipher.getInstance("DES");
- cipher.init(Cipher.DECRYPT_MODE, key,random);
- return cipher.doFinal(src);
- }
-
- private static Key toKey(byte[] key) throws Exception {
-
- DESKeySpec dks = new DESKeySpec(key);
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
- SecretKey secretKey = keyFactory.generateSecret(dks);
-
- return secretKey;
- }
-
- private static String byte2String(byte[] b) {
- StringBuilder hs = new StringBuilder();
- String stmp;
- for (int n = 0; b != null && n < b.length; n++) {
- stmp = Integer.toHexString(b[n] & 0XFF);
- if (stmp.length() == 1)
- hs.append('0');
- hs.append(stmp);
- }
- return hs.toString();
- }
-
- private static byte[] str2Byte(String strIn) throws NumberFormatException {
- byte[] arrB = strIn.getBytes();
- int iLen = arrB.length;
- byte[] arrOut = new byte[iLen / 2];
- for (int i = 0; i < iLen; i = i + 2) {
- String strTmp = new String(arrB, i, 2);
- arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
- }
- return arrOut;
- }
-
-
- public static void main(String[] args) throws Exception {
- String str = "abddddc123tesaabbc";
-
- String password = "1234567890ABCDEF";
-
- System.out.println("加密前:" + str);
- byte[] result = DesTest.encrypt(str.getBytes(),password);
- String res = byte2String(result);
- System.out.println("加密后:"+res);
-
- byte[] decryResult = DesTest.decrypt(str2Byte(res), password);
- System.out.println("解密后:"+new String(decryResult));
-
- }
-
- }
算法运行结果
- 加密前:abddddc123tesaabbc
- 加密后:57990b25549a0ff8ab57b2ba08175546210a01e2dee06bee
- 解密后:abddddc123tesaabbc
AES对称加密算法使用及代码
- package com.pc.aestest;
-
- import java.security.Key;
- import java.security.SecureRandom;
-
- import javax.crypto.Cipher;
- import javax.crypto.SecretKey;
- import javax.crypto.spec.SecretKeySpec;
-
-
- public class AesTest{
-
-
- public static byte[] encrypt(byte[] datasource, String password) throws Exception {
-
-
- SecureRandom random = new SecureRandom();
- Key key = toKey(password.getBytes());
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(Cipher.ENCRYPT_MODE, key,random);
- return cipher.doFinal(datasource);
- }
-
-
- public static byte[] decrypt(byte[] src, String password) throws Exception {
-
- SecureRandom random = new SecureRandom();
- Key key = toKey(password.getBytes());
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(Cipher.DECRYPT_MODE, key,random);
- return cipher.doFinal(src);
- }
-
- private static Key toKey(byte[] key) throws Exception {
-
- SecretKey secretKey = new SecretKeySpec(key, "AES");
- return secretKey;
- }
-
- private static String byte2String(byte[] b) {
- StringBuilder hs = new StringBuilder();
- String stmp;
- for (int n = 0; b != null && n < b.length; n++) {
- stmp = Integer.toHexString(b[n] & 0XFF);
- if (stmp.length() == 1)
- hs.append('0');
- hs.append(stmp);
- }
- return hs.toString();
- }
-
- private static byte[] str2Byte(String strIn) throws NumberFormatException {
- byte[] arrB = strIn.getBytes();
- int iLen = arrB.length;
- byte[] arrOut = new byte[iLen / 2];
- for (int i = 0; i < iLen; i = i + 2) {
- String strTmp = new String(arrB, i, 2);
- arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
- }
- return arrOut;
- }
-
-
- public static void main(String[] args) throws Exception {
- String str = "abddddc123tesaabbc";
-
- String password = "1234567890ABCDEF";
-
- System.out.println("加密前:" + str);
- byte[] result = AesTest.encrypt(str.getBytes(),password);
- String res = byte2String(result);
- System.out.println("加密后:"+res);
-
- byte[] decryResult = AesTest.decrypt(str2Byte(res), password);
- System.out.println("解密后:"+new String(decryResult));
-
- }
-
- }
运算结果
- 加密前:abddddc123tesaabbc
- 加密后:6ce0add18dbcdc4a8394db087ea7da6a46afc04fc4a2728c8a9ea7b0bb5a38d2
- 解密后:abddddc123tesaabbc
AES的ECB加密算法使用代码
- package com.pc.aestest;
-
-
- import java.security.Key;
- import java.security.SecureRandom;
- import javax.crypto.Cipher;
- import javax.crypto.SecretKey;
- import javax.crypto.spec.SecretKeySpec;
-
-
- public class AesTestECB{
-
-
- public static byte[] encrypt(byte[] datasource, String password) throws Exception {
-
- SecureRandom random = new SecureRandom();
- Key key = toKey(password.getBytes());
- Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
- cipher.init(Cipher.ENCRYPT_MODE, key,random);
- return cipher.doFinal(datasource);
- }
-
-
- public static byte[] decrypt(byte[] src, String password) throws Exception {
-
- SecureRandom random = new SecureRandom();
- Key key = toKey(password.getBytes());
- Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
- cipher.init(Cipher.DECRYPT_MODE, key,random);
- return cipher.doFinal(src);
- }
-
- private static Key toKey(byte[] key) throws Exception {
-
- SecretKey secretKey = new SecretKeySpec(key, "AES");
-
- return secretKey;
- }
-
- private static String byte2String(byte[] b) {
- StringBuilder hs = new StringBuilder();
- String stmp;
- for (int n = 0; b != null && n < b.length; n++) {
- stmp = Integer.toHexString(b[n] & 0XFF);
- if (stmp.length() == 1)
- hs.append('0');
- hs.append(stmp);
- }
- return hs.toString();
- }
-
- private static byte[] str2Byte(String strIn) throws NumberFormatException {
- byte[] arrB = strIn.getBytes();
- int iLen = arrB.length;
- byte[] arrOut = new byte[iLen / 2];
- for (int i = 0; i < iLen; i = i + 2) {
- String strTmp = new String(arrB, i, 2);
- arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
- }
- return arrOut;
- }
-
-
- public static void main(String[] args) throws Exception {
- String str = "abddddc123tesaabbc";
-
- String password = "1234567890ABCDEF";
-
- System.out.println("加密前:" + str);
- byte[] result = AesTestECB.encrypt(str.getBytes(),password);
- String res = byte2String(result);
- System.out.println("加密后:"+res);
-
- byte[] decryResult = AesTestECB.decrypt(str2Byte(res), password);
-
- System.out.println("解密后:"+new String(decryResult));
- }
- }
运算结果,根据运算结果可知AES算法默认使用的是ECB模式
- 加密前:abddddc123tesaabbc
- 加密后:6ce0add18dbcdc4a8394db087ea7da6a46afc04fc4a2728c8a9ea7b0bb5a38d2
- 解密后:abddddc123tesaabbc
AES的CBC模式加密算法代码,建议使用这一种模式的对称加密算法,这种模式的使用是安全。
- package com.pc.aestest;
-
- import java.security.Key;
- import java.security.Security;
- import javax.crypto.Cipher;
- import javax.crypto.SecretKey;
- import javax.crypto.spec.IvParameterSpec;
- import javax.crypto.spec.SecretKeySpec;
-
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-
- public class AesTestCBC{
-
- public static boolean initialized = false;
-
- public static byte[] encrypt(byte[] datasource, String password) throws Exception {
-
- initialize();
- Key key = toKey(password.getBytes());
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding","BC");
- IvParameterSpec iv = new IvParameterSpec("1234567890123456".getBytes());
-
- cipher.init(Cipher.ENCRYPT_MODE, key,iv);
- return cipher.doFinal(datasource);
- }
-
-
- public static byte[] decrypt(byte[] src, String password) throws Exception {
-
- initialize();
- Key key = toKey(password.getBytes());
-
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- IvParameterSpec iv = new IvParameterSpec("1234567890123456".getBytes());
- cipher.init(Cipher.DECRYPT_MODE, key,iv);
- return cipher.doFinal(src);
- }
-
- private static Key toKey(byte[] key) throws Exception {
-
- SecretKey secretKey = new SecretKeySpec(key, "AES");
- return secretKey;
- }
-
- private static String byte2String(byte[] b) {
- StringBuilder hs = new StringBuilder();
- String stmp;
- for (int n = 0; b != null && n < b.length; n++) {
- stmp = Integer.toHexString(b[n] & 0XFF);
- if (stmp.length() == 1)
- hs.append('0');
- hs.append(stmp);
- }
- return hs.toString();
- }
-
- private static byte[] str2Byte(String strIn) throws NumberFormatException {
- byte[] arrB = strIn.getBytes();
- int iLen = arrB.length;
- byte[] arrOut = new byte[iLen / 2];
- for (int i = 0; i < iLen; i = i + 2) {
- String strTmp = new String(arrB, i, 2);
- arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
- }
- return arrOut;
- }
-
-
- public static void main(String[] args) throws Exception {
- String str = "abddddc123tesaa";
-
- String password = "1234567890ABCDEF";
-
- System.out.println("加密前:" + str);
- byte[] result = AesTest.encrypt(str.getBytes(),password);
- String res = byte2String(result);
- System.out.println("加密后:"+res);
-
- byte[] decryResult = AesTest.decrypt(str2Byte(res), password);
- System.out.println("解密后:"+new String(decryResult));
-
- }
-
- public static void initialize(){
- if (initialized) return;
- Security.addProvider(new BouncyCastleProvider());
- initialized = true;
- }
-
- }
运算结果
- 加密前:abddddc123tesaa
- 加密后:647c5546059c44d2d35b9b38e52fc6e9
- 解密后:abddddc123tesaa
0x04 RSA非对称加密算法
RSA非对称加密算法既可以用于非对称加密,又可以用户签名算法。由于在相应的时间方面远远大于对称加密算法,故用户加密少量的数据或用与签名,下面的链接中展示了既可以进行非对称加密,又可以用于签名的java代码,在这里就不再重复贴出。详情见下面的链接RSA非对称加密和签名算法。
参考链接:
RSA非对称加密算法及签名
http://blog.csdn.net/wangqiuyun/article/details/42143957/
http://snowolf.iteye.com/blog/381767
java加密解密的艺术
http://snowolf.iteye.com/blog/379860