您的位置:首页 > 移动开发 > Android开发

Android中的加密解密安全

2016-10-14 15:46 288 查看
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对称加密算法的使用

[java] view
plain copy







package com.pc.destest;

import java.security.Key;
4000

import java.security.SecureRandom;

import javax.crypto.Cipher;

import javax.crypto.SecretKey;

import javax.crypto.SecretKeyFactory;

import javax.crypto.spec.DESKeySpec;

public class DesTest{

//DES加密

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

}

//DES解密

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

}

}

算法运行结果

[java] view
plain copy







加密前:abddddc123tesaabbc

加密后:57990b25549a0ff8ab57b2ba08175546210a01e2dee06bee

解密后:abddddc123tesaabbc

AES对称加密算法使用及代码

[java] view
plain copy







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{

//AES加密

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

}

//AES解密

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

}

}

运算结果

[plain] view
plain copy







加密前:abddddc123tesaabbc

加密后:6ce0add18dbcdc4a8394db087ea7da6a46afc04fc4a2728c8a9ea7b0bb5a38d2

解密后:abddddc123tesaabbc

AES的ECB加密算法使用代码

[java] view
plain copy







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{

//AES的ECB模式加密

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

}

//AES的ECB模式解密

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
& 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模式

[plain] view
plain copy







加密前:abddddc123tesaabbc

加密后:6ce0add18dbcdc4a8394db087ea7da6a46afc04fc4a2728c8a9ea7b0bb5a38d2

解密后:abddddc123tesaabbc

AES的CBC模式加密算法代码,建议使用这一种模式的对称加密算法,这种模式的使用是安全。

[java] view
plain copy







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;

//AES加密CBC模式

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

}

//AES解密CBC模式

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
& 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;

}

}

运算结果

[java] view
plain copy







加密前: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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: