Android加密算法

專業(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中的加密接口

  1. 為安全框架提供類和接口似踱,如解析和管理證書(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


image.png
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接口


image.png

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)景:

  1. 兩個(gè)變量的互換(不借助第三個(gè)變量);
  2. 數(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;
    }
}

源碼地址:https://github.com/samlss/Security

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末待牵,一起剝皮案震驚了整個(gè)濱河市其屏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缨该,老刑警劉巖偎行,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異贰拿,居然都是意外死亡蛤袒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)膨更,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)妙真,“玉大人,你說(shuō)我怎么就攤上這事荚守≌涞拢” “怎么了练般?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)锈候。 經(jīng)常有香客問(wèn)我薄料,道長(zhǎng),這世上最難降的妖魔是什么泵琳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任摄职,我火速辦了婚禮,結(jié)果婚禮上获列,老公的妹妹穿的比我還像新娘谷市。我一直安慰自己,他們只是感情好蛛倦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布歌懒。 她就那樣靜靜地躺著,像睡著了一般溯壶。 火紅的嫁衣襯著肌膚如雪及皂。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天且改,我揣著相機(jī)與錄音验烧,去河邊找鬼。 笑死又跛,一個(gè)胖子當(dāng)著我的面吹牛碍拆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慨蓝,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼感混,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了礼烈?” 一聲冷哼從身側(cè)響起弧满,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎此熬,沒(méi)想到半個(gè)月后庭呜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡犀忱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年募谎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阴汇。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡数冬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出搀庶,到底是詐尸還是另有隱情吉执,我是刑警寧澤疯淫,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布地来,位于F島的核電站戳玫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏未斑。R本人自食惡果不足惜咕宿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蜡秽。 院中可真熱鬧府阀,春花似錦、人聲如沸芽突。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)寞蚌。三九已至田巴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挟秤,已是汗流浹背壹哺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留艘刚,地道東北人管宵。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像攀甚,于是被迫代替她去往敵國(guó)和親箩朴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 主要內(nèi)容 1.加密算法分類 2.常用的加密算法實(shí)現(xiàn) 今天主要講些加密算法的事秋度。相關(guān)代碼:https://githu...
    cgrass閱讀 7,515評(píng)論 0 46
  • 本文主要介紹移動(dòng)端的加解密算法的分類炸庞、其優(yōu)缺點(diǎn)特性及應(yīng)用,幫助讀者由淺入深地了解和選擇加解密算法静陈。文中會(huì)包含算法的...
    蘋(píng)果粉閱讀 11,509評(píng)論 5 29
  • 這篇文章主要講述在Mobile BI(移動(dòng)商務(wù)智能)開(kāi)發(fā)過(guò)程中燕雁,在網(wǎng)絡(luò)通信、數(shù)據(jù)存儲(chǔ)鲸拥、登錄驗(yàn)證這幾個(gè)方面涉及的加密...
    雨_樹(shù)閱讀 2,439評(píng)論 0 6
  • 在介紹加密算法之前, 先介紹一下 base64: 0. base64 Base64要求把每三個(gè)8Bit的字節(jié)轉(zhuǎn)換為...
    reboot_q閱讀 12,960評(píng)論 3 8
  • 這個(gè)科顏氏圣誕套裝真的炒雞炒雞劃算肮崭瘛!雖然當(dāng)時(shí)也是被柜姐忽悠著買(mǎi)了 但是真心沒(méi)有吃虧上當(dāng)靶谈稀捏浊! 再次啰嗦一遍我的膚質(zhì)...
    shireenB閱讀 499評(píng)論 0 0