Android開發中對于數據的傳輸和保存一定會使用加密技術,加密算法是最普遍的安保手段,多數情況數據加密后在需要使用源數據時需要再進行解密,但凡是都有例外。下面從可逆加密、不可逆、不純粹加密三種方式記錄一下常見的加解密算法。
加密技術包括兩個元素:算法和密鑰:算法使用密鑰將明文數據變成無法辨識的密文。
以下代碼是點擊事件里調用SecurityUtil工具類,加解密算法都再SecurityUtil中實現。
1、可逆加密:分為對稱加密和非對加密
1.1對稱加密
加密和解密使用的同一套密鑰,包括:DES、3DES、AES等
以AES為例:
被加密的明文public static final String CONTENT = "suibianxie888888888";密鑰public static final String SECRET_KEY = "6a8w0c91kc7";
public static final String SECRET_KEY_PREFIX = "aw098";aesTv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {String encryptAES = SecurityUtil.encryptAES( CONTENT, SECRET_KEY+SECRET_KEY_PREFIX);Log.e(TAG, "onClick: encryptAES= "+encryptAES );String value = SecurityUtil.decryptAES(encryptAES, SECRET_KEY+SECRET_KEY_PREFIX);Log.e(TAG, "onClick: decryptAES = "+value);}catch (Exception e){Log.e(TAG, "onClick: decryptAES -Exception= "+e.getMessage() );}}
});
????/*** AES加密* @throws Exception ?此處實際有好多個Exception,偷懶直接拋Exception了*/public static String encryptAES(String data, String secretKey) {try {Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "AES");IvParameterSpec ivSpec = new IvParameterSpec(secretKey.getBytes());cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);byte[] bEncData = cipher.doFinal(data.getBytes());
// ???????????return com.android.api.utils.Base64.encode(bEncData);return Base64.encodeToString(bEncData, Base64.NO_WRAP);} catch (Exception e) {e.printStackTrace();return "";}}/*** AES 解密* @param cipherText* @param secretKey* @return* @throws Exception*/
public static String decryptAES(String cipherText, String secretKey){try {byte[] encrypted1 = Base64.decode(cipherText, Base64.NO_WRAP);Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "AES");IvParameterSpec ivSpec = new IvParameterSpec(secretKey.getBytes());cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);byte[] original = cipher.doFinal(encrypted1);String originalString = new String(original);return originalString;} catch (Exception e) {e.printStackTrace();return null;}
}
AES加密和解密日志打印:
1.2??非對稱加密
加密和解密分別使用不同的密鑰,包括:SM2、SM4、RSA
2、不可逆加密
無解,理論上誰都別想解開,包括:MD5、SHA系列,MD5和SHA系列,SHA-1之外的SHA系列稱作SHA2算法,SHA系列比MD5安全性更高而SHA2的都高于SHA-1。SHA-x 后面的x代表加密后的字符串長度,SHA-1加密后固定160位。常用于用戶密碼和文件完整性校驗。
2.1 MD5加密,
擁有以下特質:
壓縮性:無論多大加密后都生成128位(16字節)的數據,通常用它的16進制字面值輸出是一個32位長度的字符串; ?
容易計算性質:通過原數據很容易計算出MD5值; ??
抗修改性:隨便修改一個字節重新計算的MD5值千差萬別; ??
抗碰撞性:知道數據和MD5值,很小概率找到相同MD5值的原數據。
public static final String CONTENT = "suibianxie888888888";md5Tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.e(TAG, "onClick: md5Tv-string= "+ SecurityUtil.encryptMD5(CONTENT) );Log.e(TAG, "onClick: md5Tv-bytes1= "+SecurityUtil.encryptMD5Bytes(CONTENT.getBytes()) );}
});
// 16進制下數字到字符的映射數組
public static String[] hexDigits = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9","a", "b", "c", "d", "e", "f" };// 對字符串進行MD5編碼
public static String encryptMD5(String originstr) {if (originstr != null) {return encryptMD5Bytes(originstr.getBytes());}else {return null;}
}public static String encryptMD5Bytes(byte[] originstr) {if (originstr != null) {try {// 創建具有指定算法名稱的信息摘要MessageDigest md = MessageDigest.getInstance("MD5");// 使用指定的字節數組對摘要進行最后的更新,然后完成摘要計算byte[] results = md.digest(originstr);// 將得到的字節數組編程字符串返回String resultString = byteArrayToHexString(results);return resultString.toUpperCase();} catch (Exception ex) {ex.printStackTrace();}}return null;
}// 轉換字節數組為十六進制字符串
public static String byteArrayToHexString(byte[] b) {StringBuffer resultsb = new StringBuffer();int i = 0;for (i = 0; i < b.length; i++) {resultsb.append(byteToHexString(b[i]));}return resultsb.toString();
}
//以下代碼是對字符串進行MD5加密的相關代碼// 將字節轉化成十六進制的字符串
private static String byteToHexString(byte b) {int n = b;if (n < 0) {n = 256 + n;}int d1 = n / 16;int d2 = n / 16;return hexDigits[d1] + hexDigits[d2];
}
MD5日志:
SHA1和SHA256:
public static final String CONTENT = "suibianxie888888888";sha1Tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//SHA1算法String fileSHA1 = SecurityUtil.getFileSHA1(CONTENT);Log.e(TAG, "onClick: ?sha1Tv="+fileSHA1 );//SHA256算法String sha_256 = SecurityUtil.SHA_256(CONTENT);Log.e(TAG, "onClick: ?sha_256="+sha_256 );}
});
// 獲取文件的SHA1值
public static String getFileSHA1(String text) {if (text.isEmpty()){return "";}try{text = text.trim();byte[] bytes = text.getBytes("UTF-8");return getFileSHA1(bytes);}catch (Exception e){return "";}
}// 獲取文件的SHA1值
public static String getFileSHA1(byte[] bytes) {StringBuffer strResult = new StringBuffer();MessageDigest md;try {md = MessageDigest.getInstance("SHA-1");md.update(bytes);byte[] encryptedBytes = md.digest();String stmp;for (int n = 0; n < encryptedBytes.length; n++) {stmp = (Integer.toHexString(encryptedBytes[n] & 0XFF));if (stmp.length() == 1) {strResult.append("0");strResult.append(stmp);} else {strResult.append(stmp);}}return strResult.toString();} catch (Exception e) {return "";}
}/*** SHA加密* @param strText 明文* @return*/
public static String SHA_256(final String strText){// 返回值String strResult = null;// 是否是有效字符串if (strText != null && strText.length() > 0){try{// SHA 加密開始MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");// 傳入要加密的字符串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;
}
SHA1和SHA256算法日志打印:
3、不純粹加密
Base64,經它運算后表面看是變形了,但不屬于真的加密,開發中也經常遇到。一種不算嚴格意義上的加解密,把字符串轉換成以"=="雙等號結尾的串。
未完結,持續更新中。