專業(yè)術(shù)語(yǔ)(摘自百度百科)
密鑰:分為加密密鑰和解密密鑰敛滋。
明文:沒(méi)有進(jìn)行加密,能夠直接代表原文含義的信息。
密文:經(jīng)過(guò)加密處理處理之后徒扶,隱藏原文含義的信息。
加密:將明文轉(zhuǎn)換成密文的實(shí)施過(guò)程根穷。
解密:將密文轉(zhuǎn)換成明文的實(shí)施過(guò)程酷愧。
基本簡(jiǎn)介
密碼是通信雙方按約定的法則進(jìn)行信息特殊變換的一種重要保密手段。依照這些法則缠诅,變明文為密文溶浴,稱為加密變換;變密文為明文管引,稱為脫密變換士败。密碼在早期僅對(duì)文字或數(shù)碼進(jìn)行加、脫密變換褥伴,隨著通信技術(shù)的發(fā)展谅将,對(duì)語(yǔ)音、圖像重慢、數(shù)據(jù)等都可實(shí)施加饥臂、脫密變換。
Android中的加密接口
- 為安全框架提供類和接口似踱,如解析和管理證書(shū)隅熙、密鑰生成、算法參數(shù)核芽。
java.security
java.security.acl
java.security.cert
java.security.interfaces
java.security.spec
2.為加密操作提供類和接口囚戚,如加密操作包括加密,密鑰生成和密鑰協(xié)議以及消息認(rèn)證碼(MAC)生成轧简。
支持加密包括對(duì)稱驰坊,非對(duì)稱,塊和流密碼哮独。
javax.crypto
javax.crypto.interfaces
javax.crypto.spec
可參考谷歌開(kāi)發(fā)者文檔:https://developer.android.com/reference/packages
Base64
Base64只是一種編碼方式拳芙,將二進(jìn)制數(shù)據(jù)轉(zhuǎn)化為字符(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/),不要使用Base64來(lái)進(jìn)行加密數(shù)據(jù)皮璧。
Android中Base64接口為
android.util.Base64
SHA
安全散列算法:能計(jì)算出一個(gè)數(shù)字消息所對(duì)應(yīng)到的舟扎,長(zhǎng)度固定的字符串(又稱消息摘要)的算法,且若輸入的消息不同恶导,它們對(duì)應(yīng)到不同字符串的機(jī)率很高浆竭。
建議使用SHA-256算法對(duì)message字符串做哈希。
不建議使用MD2、MD4邦泄、MD5删窒、SHA-1、RIPEMD算法來(lái)加密用戶密碼等敏感信息顺囊。這一類算法已經(jīng)有很多破解辦法肌索。
請(qǐng)注意在多個(gè)字符串拼接后做SHA加密要注意添加間隔符,以區(qū)分多個(gè)字符串特碳,否則可能會(huì)造成加密后結(jié)果相同:例如sha(AB+CD) = sha(ABC+D)诚亚。
/**
* @author SamLeung
* @Emial 729717222@qq.com
*/
public class SHA {
private SHA() {
}
public static String encrypt1(String data) {
return encrypt(data, "SHA-1");
}
public static String encrypt224(String data) {
return encrypt(data, "SHA-224");
}
public static String encrypt256(String data) {
return encrypt(data, "SHA-256");
}
public static String encrypt384(String data) {
return encrypt(data, "SHA-384");
}
public static String encrypt512(String data) {
return encrypt(data, "SHA-512");
}
/**
* 通過(guò)SHA加密
*
* @param data 原始數(shù)據(jù)
* @param algorithm 算法(SHA-1,SHA-224午乓,SHA-256站宗,SHA-384,和SHA-512)
*/
public static String encrypt(String data, String algorithm) {
String result = null;
try {
byte[] dataBytes = data.getBytes();
MessageDigest md5 = MessageDigest.getInstance(algorithm);
md5.update(dataBytes);
byte[] bytes = md5.digest();
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
if(Integer.toHexString(0xFF & b).length() == 1) {
sb.append("0").append(Integer.toHexString(0xFF & b));
} else {
sb.append(Integer.toHexString(0xFF & b));
}
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return result;
}
}
HMAC
HMAC是密鑰相關(guān)的哈希運(yùn)算消息認(rèn)證碼益愈,HMAC運(yùn)算利用哈希算法梢灭,以一個(gè)密鑰和一個(gè)消息為輸入,生成一個(gè)消息摘要作為輸出蒸其。即在SHA算法上增加了一個(gè)密鑰作為數(shù)據(jù)認(rèn)證敏释,主要用于身份驗(yàn)證中。
/**
* @author SamLeung
* @Emial 729717222@qq.com
*/
public class HMAC {
private HMAC(){}
public static String encrypt1(byte[] data, byte[] key){
return encrypt(data, key, "HmacSHA1");
}
public static String encrypt224(byte[] data, byte[] key){
return encrypt(data, key, "HmacSHA224");
}
public static String encrypt256(byte[] data, byte[] key){
return encrypt(data, key, "HmacSHA256");
}
public static String encrypt384(byte[] data, byte[] key){
return encrypt(data, key, "HmacSHA384");
}
public static String encrypt512(byte[] data, byte[] key){
return encrypt(data, key, "HmacSHA512");
}
public static String encryptMD5(byte[] data, byte[] key){
return encrypt(data, key, "HmacMD5");
}
/**
* 通過(guò)HMAC加密
*
* @param data 原始數(shù)據(jù)
* @param algorithm 算法(SHA-1摸袁,SHA-224钥顽,SHA-256,SHA-384靠汁,和SHA-512)
*/
public static String encrypt(byte[] data, byte[] key, String algorithm) {
try {
SecretKey secretKey = new SecretKeySpec(key, algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secretKey);
mac.update(data);
byte[] bytes = mac.doFinal();
return Base64.encodeToString(bytes, Base64.NO_PADDING);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
}
對(duì)稱加密(DES蜂大、AES)
在對(duì)稱加密算法中,數(shù)據(jù)發(fā)信方將明文(原始數(shù)據(jù))和加密密鑰一起經(jīng)過(guò)特殊加密算法處理后膀曾,使其變成復(fù)雜的加密密文發(fā)送出去县爬。收信方收到密文后,若想解讀原文添谊,則需要使用加密用過(guò)的密鑰及相同算法的逆算法對(duì)密文進(jìn)行解密,才能使其恢復(fù)成可讀明文察迟。在對(duì)稱加密算法中斩狱,使用的密鑰只有一個(gè),發(fā)收信雙方都使用這個(gè)密鑰對(duì)數(shù)據(jù)進(jìn)行加密和解密扎瓶,這就要求解密方事先必須知道加密密鑰所踊。
建議使用AES算法,DES默認(rèn)的是56位的加密密鑰概荷,已經(jīng)不安全秕岛,不建議使用。
DES
DES算法為密碼體制中的對(duì)稱密碼體制,又被稱為美國(guó)數(shù)據(jù)加密標(biāo)準(zhǔn)继薛,是1972年美國(guó)IBM公司研制的對(duì)稱密碼體制加密算法修壕。 明文按64位進(jìn)行分組,密鑰長(zhǎng)64位遏考,密鑰事實(shí)上是56位參與DES運(yùn)算(第8慈鸠、16、24灌具、32青团、40、48咖楣、56督笆、64位是校驗(yàn)位, 使得每個(gè)密鑰都有奇數(shù)個(gè)1)分組后的明文組和56位的密鑰按位替代或交換的方法形成密文組的加密方法诱贿。
/**
* @author SamLeung
* @Emial 729717222@qq.com
*/
public class DES {
private DES() {}
/**
* 生成秘鑰
*
* @return
*/
public static byte[] generateKey() {
try {
KeyGenerator keyGen = KeyGenerator.getInstance("DES"); // 秘鑰生成器
keyGen.init(56); // 初始秘鑰生成器,DES是一個(gè)基于56位密鑰的對(duì)稱的加密算法
SecretKey secretKey = keyGen.generateKey(); // 生成秘鑰
return secretKey.getEncoded(); // 獲取秘鑰字節(jié)數(shù)組
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* 加密
*
* @return
*/
public static byte[] encrypt(byte[] data, byte[] key) {
return doCipher(data, key, Cipher.ENCRYPT_MODE);
}
/**
* 解密
*
* @return
*/
public static byte[] decrypt(byte[] data, byte[] key) {
return doCipher(data, key, Cipher.DECRYPT_MODE);
}
/**
* 進(jìn)行加密/解密
*
* @param data 原始數(shù)據(jù)
* @param key 密鑰
* @param opmode 加密/解密{@link Cipher#ENCRYPT_MODE},{@link Cipher#DECRYPT_MODE}
* */
private static byte[] doCipher(byte[] data, byte[] key, int opmode){
byte[] bytes = null;
try {
//這里首先將密鑰字節(jié)流轉(zhuǎn)為secret key
SecretKey secretKey = new SecretKeySpec(key, "DES");
//算法參數(shù)胖腾,增加加密算法的強(qiáng)度
IvParameterSpec ivParameterSpec = new IvParameterSpec(key);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(opmode, secretKey,ivParameterSpec);
bytes = cipher.doFinal(data);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return bytes;
}
}
DES3
基于DES,對(duì)一塊數(shù)據(jù)用三個(gè)不同的密鑰進(jìn)行三次加密瘪松,強(qiáng)度更高咸作。
/**
* @author SamLeung
* @Emial 729717222@qq.com
*/
public class DES3 {
private DES3() {
}
public static byte[] generateKey(){
byte[] key = null;
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
keyGenerator.init(56 * 3); //DES是一個(gè)基于56位密鑰的對(duì)稱的加密算法,而DES3其實(shí)是進(jìn)行3次DES。
key = keyGenerator.generateKey().getEncoded();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return key;
}
/**
* 加密
*
* @return
*/
public static byte[] encrypt(byte[] data, byte[] key) {
return doCipher(data, key, Cipher.ENCRYPT_MODE);
}
/**
* 解密
*
* @return
*/
public static byte[] decrypt(byte[] data, byte[] key) {
return doCipher(data, key, Cipher.DECRYPT_MODE);
}
/**
* 進(jìn)行加密/解密
*
* @param data 原始數(shù)據(jù)
* @param key 密鑰
* @param opmode 加密/解密{@link Cipher#ENCRYPT_MODE},{@link Cipher#DECRYPT_MODE}
* */
private static byte[] doCipher(byte[] data, byte[] key, int opmode){
byte[] bytes = null;
try {
SecretKey secretKey = new SecretKeySpec(key, "DESede");
IvParameterSpec ivParameterSpec = new IvParameterSpec(key);
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(opmode, secretKey, ivParameterSpec);
bytes = cipher.doFinal(data);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return bytes;
}
}
AES
即密碼學(xué)中的高級(jí)加密標(biāo)準(zhǔn)(Advanced Encryption Standard宵睦,AES)记罚,又稱Rijndael加密法,是美國(guó)聯(lián)邦政府采用的一種區(qū)塊加密標(biāo)準(zhǔn)壳嚎。這個(gè)標(biāo)準(zhǔn)用來(lái)替代原先的DES桐智,已經(jīng)被多方分析且廣為全世界所使用。
AES有五種工作模式:ECB烟馅、CBC说庭、CTR、CFB郑趁、OCF刊驴。
不推薦使用ECB模式,推薦且使用CBC/CFB模式寡润,可使用PKCS5Padding填充捆憎。
工作模式的加密方法可參考https://www.cnblogs.com/starwolf/p/3365834.html。
/**
* @author SamLeung
* @Emial 729717222@qq.com
*/
public class AES {
private static final String CBC_PKCS1_PADDING = "AES/CBC/PKCS5Padding";//注意加密模式不要使用ECB模式梭纹。ECB模式不安全
private static final String IPS = "c^Y!mrz7AYbQRriB"; //使用密碼生成器生成
private AES() {
}
public static byte[] generateKey(){
byte[] key = null;
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
return keyGenerator.generateKey().getEncoded();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return key;
}
public static byte[] encrypt(byte[] data, byte[] key){
return doCipher(data, key, Cipher.ENCRYPT_MODE);
}
public static byte[] decrypt(byte[] data, byte[] key){
return doCipher(data, key, Cipher.DECRYPT_MODE);
}
private static byte[] doCipher(byte[] data, byte[] key, int opmode){
byte[] bytes = null;
try {
SecretKey secretKey = new SecretKeySpec(key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(IPS.getBytes()); //使用CBC模式必須指定IvParameterSpec躲惰,且expected IV length of 16,即長(zhǎng)度限制為16
Cipher cipher = Cipher.getInstance(CBC_PKCS1_PADDING);
cipher.init(opmode, secretKey, ivParameterSpec);
bytes = cipher.doFinal(data);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return bytes;
}
}
AES/CBC/PKCS5Padding說(shuō)明:
我們經(jīng)潮涑椋可以看到
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
這種寫(xiě)法础拨,意思是指定一個(gè)字符串氮块,用于描述要在給定輸入執(zhí)行的操作(或一組操作),以生成一些輸出诡宗。
API接口
transformation參數(shù)總是包括密碼算法的名稱(例如AES)滔蝉,并且可以跟隨反饋模式(谷歌開(kāi)發(fā)者文檔中為feedback mode)和填充方案。形式一般為:
"algorithm/mode/padding" === 算法/模式/填充
或者
"algorithm" === 算法
在只指定算法的情況下僚焦,會(huì)使用默認(rèn)的模式和填充方案锰提,例如:
Cipher c = Cipher.getInstance("DES");
默認(rèn)為
Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
在某些情況下,我們還需指定IvParameterSpec參數(shù)
IvParameterSpec ivParameterSpec = new IvParameterSpec(IPS.getBytes());
Cipher cipher = Cipher.getInstance(CBC_PKCS1_PADDING);
cipher.init(opmode, secretKey, ivParameterSpec);
IvParameterSpec繼承自AlgorithmParameterSpec芳悲,該類的作用是指定了一個(gè)初始化向量立肘,在密碼學(xué)的領(lǐng)域里,初始化向量(英語(yǔ):initialization vector名扛,縮寫(xiě)為IV)谅年,或譯初向量,又稱初始變量(starting variable肮韧,縮寫(xiě)為SV)融蹂,是一個(gè)固定長(zhǎng)度的輸入值。一般的使用上會(huì)要求它是隨機(jī)數(shù)或擬隨機(jī)數(shù)(pseudorandom)弄企。使用隨機(jī)數(shù)產(chǎn)生的初始化向量才能達(dá)到語(yǔ)義安全(散列函數(shù)與消息驗(yàn)證碼也有相同要求)超燃,并讓攻擊者難以對(duì)同一把密鑰的密文進(jìn)行破解。在區(qū)塊加密中拘领,使用了初始化向量的加密模式被稱為區(qū)塊加密模式意乓。
可參考:https://developer.android.com/reference/javax/crypto/Cipher
非對(duì)稱加密
非對(duì)稱加密算法需要兩個(gè)密鑰來(lái)進(jìn)行加密和解密,這兩個(gè)秘鑰是公開(kāi)密鑰(public key约素,簡(jiǎn)稱公鑰)和私有密鑰(private key届良,簡(jiǎn)稱私鑰)。
非對(duì)稱加密與對(duì)稱加密相比圣猎,其安全性更好:對(duì)稱加密的通信雙方使用相同的秘鑰士葫,如果一方的秘鑰遭泄露,那么整個(gè)通信就會(huì)被破解送悔。而非對(duì)稱加密使用一對(duì)秘鑰慢显,一個(gè)用來(lái)加密,一個(gè)用來(lái)解密放祟,而且公鑰是公開(kāi)的鳍怨,秘鑰是自己保存的,不需要像對(duì)稱加密那樣在通信之前要先同步秘鑰跪妥。
非對(duì)稱加密的缺點(diǎn)是加密和解密花費(fèi)時(shí)間長(zhǎng)、速度慢声滥,只適合對(duì)少量數(shù)據(jù)進(jìn)行加密眉撵。
RSA
非對(duì)稱加密算法
1999年512位密鑰的RSA被成功破解侦香,2009年1024位密鑰的RSA也被成功破解,因此建議使用2048位的密鑰長(zhǎng)度纽疟。
RSA非對(duì)稱加密內(nèi)容長(zhǎng)度有限制罐韩,無(wú)論是公鑰加密還是私鑰加密,1024位的key最多只能加密127位數(shù)據(jù)污朽,
否則會(huì)拋出異常:javax.crypto.IllegalBlockSizeException: input must be under 128 bytes散吵。
這是由于RSA算法規(guī)定:待加密的字節(jié)數(shù)不能超過(guò)密鑰的長(zhǎng)度值除以8再減去11,(即:KeySize / 8 - 11)蟆肆,
而加密后得到密文的字節(jié)數(shù)矾睦,是密鑰的長(zhǎng)度值除以 8(即:KeySize / 8),因此在加密和解密的時(shí)候需要分進(jìn)行分塊加密和解密炎功。
建議使用RSA/ECB/OAEPWithSHA256AndMGF1Padding加密算法枚冗。
但是使用OAEPWithSHA256AndMGF1Padding作為填充方式的話,對(duì)輸入即data的長(zhǎng)度有限制,數(shù)據(jù)長(zhǎng)度不能超過(guò)191蛇损,若超過(guò)時(shí)赁温,會(huì)拋出too much data for RSA block異常。
/**
* @author SamLeung
* @Emial 729717222@qq.com
*/
public class RSA {
public static final String RSA = "RSA";// 非對(duì)稱加密密鑰算法
public static final String ECB_PADDING = "RSA/ECB/PKCS1Padding";//加密填充方式
//public static final String ECB_PADDING = "RSA/ECB/OAEPWithSHA256AndMGF1Padding";//加密填充方式
/**
* RSA算法規(guī)定:待加密的字節(jié)數(shù)不能超過(guò)密鑰的長(zhǎng)度值除以8再減去11淤齐。
* 而加密后得到密文的字節(jié)數(shù)股囊,正好是密鑰的長(zhǎng)度值除以 8。
* */
private static int KEYSIZE = 2048;// 密鑰位數(shù)
private static int RESERVE_BYTES = 11;
private static int DECRYPT_BLOCK = KEYSIZE / 8;
private static int ENCRYPT_BLOCK = DECRYPT_BLOCK - RESERVE_BYTES;
/**
* 隨機(jī)生成RSA密鑰對(duì)
*
* @param keysize 密鑰長(zhǎng)度更啄,范圍:512-2048,一般2048
*/
public static KeyPair generateKeyPair(int keysize) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
kpg.initialize(keysize);
return kpg.genKeyPair();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
/**
* 用公鑰對(duì)字符串進(jìn)行加密
*
* @param data 原文
*/
public static byte[] encryptWithPublicKey(byte[] data, byte[] key)
throws Exception {
Cipher cp = Cipher.getInstance(ECB_PADDING);
cp.init(Cipher.ENCRYPT_MODE, getPublicKey(key));
return cp.doFinal(data);
}
/**
* 公鑰解密
*
* @param data 待解密數(shù)據(jù)
* @param key 密鑰
*/
public static byte[] decryptWithPublicKey(byte[] data, byte[] key)
throws Exception {
Cipher cipher = Cipher.getInstance(ECB_PADDING);
cipher.init(Cipher.DECRYPT_MODE, getPublicKey(key));
return cipher.doFinal(data);
}
/**
* 私鑰加密
*
* @param data 待加密數(shù)據(jù)
* @param key 密鑰
*/
public static byte[] encryptWithPrivateKey(byte[] data, byte[] key)
throws Exception {
Cipher cipher = Cipher.getInstance(ECB_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey(key));
return cipher.doFinal(data);
}
/**
* 私鑰解密
*
* @param data 待解密數(shù)據(jù)
* @param key 密鑰
*/
public static byte[] decryptWithPrivateKey(byte[] data, byte[] key)
throws Exception {
Cipher cp = Cipher.getInstance(ECB_PADDING);
cp.init(Cipher.DECRYPT_MODE, getPrivateKey(key));
byte[] arr = cp.doFinal(data);
return arr;
}
public static PublicKey getPublicKey(byte[] key) throws Exception{
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
return keyFactory.generatePublic(keySpec);
}
public static PrivateKey getPrivateKey(byte[] key) throws Exception{
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
return keyFactory.generatePrivate(keySpec);
}
/**
* 分塊加密
*
* @param data
* @param key
* */
public static byte[] encryptWithPublicKeyBlock(byte[] data, byte[] key) throws Exception{
int blockCount = (data.length / ENCRYPT_BLOCK);
if ((data.length % ENCRYPT_BLOCK) != 0) {
blockCount += 1;
}
ByteArrayOutputStream bos = new ByteArrayOutputStream(blockCount * ENCRYPT_BLOCK);
Cipher cipher = Cipher.getInstance(ECB_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(key));
for (int offset = 0; offset < data.length; offset += ENCRYPT_BLOCK) {
int inputLen = (data.length - offset);
if (inputLen > ENCRYPT_BLOCK) {
inputLen = ENCRYPT_BLOCK;
}
byte[] encryptedBlock = cipher.doFinal(data, offset, inputLen);
bos.write(encryptedBlock);
}
bos.close();
return bos.toByteArray();
}
/**
* 分塊加密
*
* @param data
* @param key
* */
public static byte[] encryptWithPrivateKeyBlock(byte[] data, byte[] key) throws Exception{
int blockCount = (data.length / ENCRYPT_BLOCK);
if ((data.length % ENCRYPT_BLOCK) != 0) {
blockCount += 1;
}
ByteArrayOutputStream bos = new ByteArrayOutputStream(blockCount * ENCRYPT_BLOCK);
Cipher cipher = Cipher.getInstance(ECB_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey(key));
for (int offset = 0; offset < data.length; offset += ENCRYPT_BLOCK) {
int inputLen = (data.length - offset);
if (inputLen > ENCRYPT_BLOCK) {
inputLen = ENCRYPT_BLOCK;
}
byte[] encryptedBlock = cipher.doFinal(data, offset, inputLen);
bos.write(encryptedBlock);
}
bos.close();
return bos.toByteArray();
}
/**
* 分塊解密
*
* @param data
* @param key
* */
public static byte[] decryptWithPublicKeyBlock(byte[] data, byte[] key) throws Exception{
int blockCount = (data.length / DECRYPT_BLOCK);
if ((data.length % DECRYPT_BLOCK) != 0) {
blockCount += 1;
}
ByteArrayOutputStream bos = new ByteArrayOutputStream(blockCount * DECRYPT_BLOCK);
Cipher cipher = Cipher.getInstance(ECB_PADDING);
cipher.init(Cipher.DECRYPT_MODE, getPublicKey(key));
for (int offset = 0; offset < data.length; offset += DECRYPT_BLOCK) {
int inputLen = (data.length - offset);
if (inputLen > DECRYPT_BLOCK) {
inputLen = DECRYPT_BLOCK;
}
byte[] decryptedBlock = cipher.doFinal(data, offset, inputLen);
bos.write(decryptedBlock);
}
bos.close();
return bos.toByteArray();
}
/**
* 分塊解密
*
* @param data
* @param key
* */
public static byte[] decryptWithPrivateKeyBlock(byte[] data, byte[] key) throws Exception{
int blockCount = (data.length / DECRYPT_BLOCK);
if ((data.length % DECRYPT_BLOCK) != 0) {
blockCount += 1;
}
ByteArrayOutputStream bos = new ByteArrayOutputStream(blockCount * DECRYPT_BLOCK);
Cipher cipher = Cipher.getInstance(ECB_PADDING);
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(key));
for (int offset = 0; offset < data.length; offset += DECRYPT_BLOCK) {
int inputLen = (data.length - offset);
if (inputLen > DECRYPT_BLOCK) {
inputLen = DECRYPT_BLOCK;
}
byte[] decryptedBlock = cipher.doFinal(data, offset, inputLen);
bos.write(decryptedBlock);
}
bos.close();
return bos.toByteArray();
}
}
XOR
異或加密:
某個(gè)字符或者數(shù)值 x 與一個(gè)數(shù)值 m 進(jìn)行異或運(yùn)算得到 y ,則再用 y 與 m 進(jìn)行異或運(yùn)算就可還原為 x稚疹。
使用場(chǎng)景:
- 兩個(gè)變量的互換(不借助第三個(gè)變量);
- 數(shù)據(jù)的簡(jiǎn)單加密解密锈死;
調(diào)用一次可對(duì)數(shù)據(jù)加密贫堰,將結(jié)果數(shù)據(jù)作為參數(shù)傳入再調(diào)用一次即對(duì)數(shù)據(jù)解密。
public class XOR {
private XOR(){}
public static byte[] execute(byte[] data, int key) {
if (data == null || data.length == 0){
return null;
}
int length = data.length;
for (int i = 0; i < length; i++) {
data[i] ^= key;
}
return data;
}
}