1.加密算法通常分为对称性加密算法和非对称性加密算法:对于对称性加密算法,信息接收双方都需事先知道密匙和加解密算法且其密匙是相同的,之后便是对数据进行 加解密了。非对称算法与之不同,发送双方A,B事先均生成一堆密匙,然后A将自己的公有密匙发送给B,B将自己的公有密匙发送给A,如果A要给B发送消息,则先需要用B的公有密匙进行消息加密,然后发送给B端,此时B端再用自己的私有密匙进行消息解密,B向A发送消息时为同样的道理。
Android数据加密之Rsa加密:非对称加密
Android数据加密之MD5加密:非对称加密
Android数据加密之Aes加密:对称加密
Android数据加密之Des加密:对称加密
项目中无论是密码的存储或者说判断文件是否是同一文件,都会用到MD5算法,今天来总结一下MD5加密算法。
MD5英文全称“Message-Digest Algorithm 5”,翻译过来是“消息摘要算法5”,由MD2、MD3、MD4演变过来的,是一种单向加密算法,是不可逆的一种的加密方式。 MD5 是非对称的加密算法
2、MD5加密有哪些特点?
压缩性:任意长度的数据,算出的MD5值长度都是固定的。
容易计算:从原数据计算出MD5值很容易。
抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
一致性验证
数字签名
安全访问认证
虽然说MD5加密本身是不可逆的,但并不是不可破译的,网上有关MD5解密的网站数不胜数,破解机制采用穷举法,就是我们平时说的跑字典。所以如何才能加大MD5破解的难度呢?
1.)对字符串多次MD5加密
2.)MD5加盐
加盐的方式也是多种多样
string+key(盐值key)然后进行MD5加密
用string明文的hashcode作为盐,然后进行MD5加密
随机生成一串字符串作为盐,然后进行MD5加密
MD5加密工具类: package com.wangshuchang.utils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;
/** * Salt MD5 加强模块 * 提供 16 位与 32 位 MD5 加密与其 Salt 加密功能 * * Salt 加密方法调用: * MD5Utilsmd5 = new MD5Utils(); * String [] _tmp = md5.salt32("明文"); System.out.println(_tmp[0] + "\t" + _tmp[1]); * * @author WangSC */ public class MD5Utils {
/** * 随机密钥长度 */ private static final int _KEYTLENGTH = 6;
public UtilMD5() { }
/** * 生成随机密钥 * * @param length * 密钥长度 */ private String getRandomKeyt(int length) throws Exception { if (length < 1) throw new Exception("密钥长度不能小于 1"); StringBuilder sb = new StringBuilder("0123456789abcdefghijklmnopqrstuvwxyz"); int len = sb.length(); System.out.println("len " + len); String _keyt = ""; for (int i = 0; i < length; i++) { int ran = (int) (Math.random() * len); System.out.println("ran " + ran); int index = ran % len; System.out.println("index " + index); System.out.println("char " + sb.charAt(index)); _keyt += sb.charAt(index);
} return _keyt; }
/** * 32位标准 MD5 加密 * * @param plainText * 明文 * @return 密文 * 返回 Null 值则出现异常 */ public String cell32(String plainText) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(plainText.getBytes()); byte b[] = md.digest(); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < b.length; offset++) { i = b[offset]; if (i < 0) i += 256; if (i < 16) buf.append("0"); buf.append(Integer.toHexString(i)); } return buf.toString();// 32位的加密
} catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; }
/** * 32 位 salt 加密 * * @param plainText * 明文 * @return 索引 0 是密文,索引 1 是二次密钥 */ // public String[] salt32(String plainText) throws Exception { // return salt("cell32", plainText); // } // /** * 32 位 salt 加密 * * @param plainText * 明文 * @return 索引 0 是密文,索引 1 是二次密钥 */ public String salt32(String plainText) throws Exception { return salt1("cell32", plainText); }
/** * 16 位标准 MD5 加密 * * @param plainText * 明文 * @return 密文 * 返回 Null 值则出现异常 */ public String cell16(String plainText) { String result = cell32(plainText); if (result == null) return null; return result.toString().substring(8, 24);// 16位的加密 }
/** * 16 位 salt 加密 * * @param plainText * 明文 * @return 索引 0 是密文,索引 1 是二次密钥 */ public String[] salt16(String plainText) throws Exception { return salt("cell16", plainText); }
/** * 根据调用的方法名称执行不同的方法 * * @param saltFunctionName * 加密的方法名称 */ private String[] salt(String saltFunctionName, String plainText) throws Exception { String _keyt = getRandomKeyt(_KEYTLENGTH); return new String[] {(String) this.getClass().getMethod(saltFunctionName, Class.forName("java.lang.String")).invoke(this, (cell32(plainText) + _keyt)), _keyt }; }
private String salt1(String saltFunctionName, String plainText) throws Exception { String _keyt = getRandomKeyt(_KEYTLENGTH); return (String) this.getClass().getMethod(saltFunctionName, Class.forName("java.lang.String")).invoke(this, cell32(plainText)) + _keyt; } } MD5解密工具类: package com.wangshuchang.utils; /** * @author WangSC * 解密工具类 */ public class UtilDecode {
private static final int _KEYTLENGTH = 6;
public static String pack(String base64) { String nBase64 = null; if (base64 != null) { nBase64 = base64.substring(1, base64.length() - 1); } return nBase64; }
/** * 去掉加密数据后面的Salt数据 * @param salt * @return */ public static String removeSalt(String salt) { String data = null; if (salt != null) { int len = salt.length() - _KEYTLENGTH; if (len > 0) { data = salt.substring(0, len); } } return data; } } |
Android数据加密之Aes加密
什么是aes加密?
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
对于AesUtils类常量简介:
private final static String HEX = "0123456789ABCDEF";
//AES是加密方式 CBC是工作模式 PKCS5Padding是填充模式
private static final String CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";
AES加密工具类: package com.wangshuchang.utils; import java.math.BigInteger; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.spec.SecretKeySpec; import org.apache.http.util.TextUtils;
/** * @author: WangSC * @date: 2018/11/22 * @description: AES的加密和解密 * aesEncrypt(content, KEY); 加密 * aesDecrypt(encrypt, KEY); 解密 */ public class AesUtil { //密钥 (需要前端和后端保持一致) private static final String KEY = "com_WangSC_@36!"; //算法 private static final String ALGORITHMSTR = "Aes/ECB/PKCS5Padding";
/** * aes解密 * * @param encrypt 内容 * @return * @throws Exception */ public static String aesDecrypt(String encrypt) { try { return aesDecrypt(encrypt, KEY); } catch (Exception e) { e.printStackTrace(); return ""; } }
/** * aes加密 * * @param content * @return * @throws Exception */ public static String aesEncrypt(String content) { try { return aesEncrypt(content, KEY); } catch (Exception e) { e.printStackTrace(); return ""; } }
/** * 将byte[]转为各种进制的字符串 * * @param bytes byte[] * @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制 * @return 转换后的字符串 */ public static String binary(byte[] bytes, int radix) { return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数 }
/** * AES加密 * * @param content 待加密的内容 * @param encryptKey 加密密钥 * @return 加密后的byte[] * @throws Exception */ public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("Aes"); kgen.init(128); Cipher cipher = Cipher.getInstance(ALGORITHMSTR); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "Aes"));
return cipher.doFinal(content.getBytes("utf-8")); }
/** * AES加密为code * * @param content 待加密的内容 * @param encryptKey 加密密钥 * @return 加密后的code * @throws Exception */ public static String aesEncrypt(String content, String encryptKey) throws Exception { return parseByte2HexStr(aesEncryptToBytes(content, encryptKey)); }
/** * AES解密 * * @param encryptBytes 待解密的byte[] * @param decryptKey 解密密钥 * @return 解密后的String * @throws Exception */ public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("Aes"); kgen.init(128);
Cipher cipher = Cipher.getInstance(ALGORITHMSTR); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "Aes")); byte[] decryptBytes = cipher.doFinal(encryptBytes); return new String(decryptBytes); }
/** * 将code AES解密 * * @param encryptStr 待解密的code * @param decryptKey 解密密钥 * @return 解密后的string * @throws Exception */ public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception { return TextUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(parseHexStr2Byte(encryptStr), decryptKey); }
/** * 将二进制转换成16进制 * * @param buf * @return */ public static String parseByte2HexStr(byte buf[]) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < buf.length; i++) { String hex = Integer.toHexString(buf[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); }
/** * 将16进制转换为二进制 * * @param hexStr * @return */ public static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) return null; byte[] result = new byte[hexStr.length() / 2]; for (int i = 0; i < hexStr.length() / 2; i++) { int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); result[i] = (byte) (high * 16 + low); } return result; } } |
前面学习总结了平时开发中遇见的各种数据加密方式,最终都会对加密后的二进制数据进行Base64编码,起到一种二次加密的效果,其实呢Base64从严格意义上来说的话不是一种加密算法,而是一种编码算法,为何要使用Base64编码呢?它解决了什么问题?这也是本文探讨的东西?
Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,Base64并不是安全领域的加密算法,其实Base64只能算是一个编码算法,对数据内容进行编码来适合传输。标准Base64编码解码无需额外信息即完全可逆,即使你自己自定义字符集设计一种类Base64的编码方式用于数据加密,在多数场景下也较容易破解。Base64编码本质上是一种将二进制数据转成文本数据的方案。对于非二进制数据,是先将其转换成二进制形式,然后每连续6比特(2的6次方=64)计算其十进制值,根据该值在A--Z,a--z,0--9,+,/ 这64个字符中找到对应的字符,最终得到一个文本字符串。基本规则如下几点:
标准Base64只有64个字符(英文大小写、数字和+、/)以及用作后缀等号;
Base64是把3个字节变成4个可打印字符,所以Base64编码后的字符串一定能被4整除(不算用作后缀的等号);
等号一定用作后缀,且数目一定是0个、1个或2个。这是因为如果原文长度不能被3整除,Base64要在后面添加\0凑齐3n位。为了正确还原,添加了几个\0就加上几个等号。显然添加等号的数目只能是0、1或2;
严格来说Base64不能算是一种加密,只能说是编码转换。
下图为Base64编码表
在计算机中任何数据都是按ascii码存储的,而ascii码的128~255之间的值是不可见字符。而在网络上交换数据时,比如说从A地传到B地,往往要经过多个路由设备,由于不同的设备对字符的处理方式有一些不同,这样那些不可见字符就有可能被处理错误,这是不利于传输的。所以就先把数据先做一个Base64编码,统统变成可见字符,这样出错的可能性就大降低了。
3、Base64具体实现
1.)字符串进行Base64编码
String encodedString = Base64.encodeToString("whoislcj".getBytes(), Base64.DEFAULT);
Log.e("Base64", "Base64---->" + encodedString);
2.)字符串进行Base64解码
String decodedString =new String(Base64.decode(encodedString,Base64.DEFAULT));
Log.e("Base64", "Base64---->" + decodedString);
3.)对文件进行Base64编码
File file = new File("/storage/emulated/0/pimsecure_debug.txt");
FileInputStream inputFile = null;
try {
inputFile = new FileInputStream(file);
byte[] buffer = new byte[(int) file.length()];
inputFile.read(buffer);
inputFile.close();
encodedString = Base64.encodeToString(buffer, Base64.DEFAULT);
Log.e("Base64", "Base64---->" + encodedString);
} catch (Exception e) {
e.printStackTrace();
}
4.)对文件进行Base64解码
File desFile = new File("/storage/emulated/0/pimsecure_debug_1.txt");
FileOutputStream fos = null;
try {
byte[] decodeBytes = Base64.decode(encodedString.getBytes(), Base64.DEFAULT);
fos = new FileOutputStream(desFile);
fos.write(decodeBytes);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
5.)针对Base64.DEFAULT参数说明
无论是编码还是解码都会有一个参数Flags,Android提供了以下几种
DEFAULT 这个参数是默认,使用默认的方法来加密
NO_PADDING 这个参数是略去加密字符串最后的”=”
NO_WRAP 这个参数意思是略去所有的换行符(设置后CRLF就没用了)
CRLF 这个参数看起来比较眼熟,它就是Win风格的换行符,意思就是使用CR LF这一对作为一行的结尾而不是Unix风格的LF
URL_SAFE 这个参数意思是加密时不使用对URL和文件名有特殊意义的字符来作为加密字符,具体就是以-和_取代+和/