1. 程式人生 > 實用技巧 >Kotlin基礎學習3

Kotlin基礎學習3

一、加密

1、對稱加密與非對稱加密的區別

  • 對稱加密。同一把鑰匙進行加密和解密
  • 非對稱加密,公鑰加密,私鑰解密。

對稱加密:
常見演算法:AES、DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK
AES:高階加密標準(Advanced Encryption Standard)
DES:資料加密標準(Data Encryption Standard)

案例一:

    /**
     *獲取祕鑰
     * @return
     * @throws NoSuchAlgorithmException
     */ 
    private static
SecretKey getSecretKey() throws NoSuchAlgorithmException { //得到keyGenerator物件 KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); SecretKey secretKey = keyGenerator.generateKey(); return secretKey; }

加密

    /**
     * 加密AES
     * @param content
     * @return
     * @throws NoSuchPaddingException 
     * @throws NoSuchAlgorithmException 
     * @throws InvalidKeyException 
     * @throws BadPaddingException 
     * @throws IllegalBlockSizeException 
     
*/ public static String encrypt(Cipher cipher,String content,SecretKey secretKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{ //content轉換成位元組陣列 byte[] bytes = content.getBytes(); //初始化cipher,確定為加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKey); //開始加密 byte[] encryptBytes = cipher.doFinal(bytes); //可以用Base64,也可以不用 return Base64.getEncoder().encodeToString(encryptBytes); }

解密

/**
     * 解密
     * @param encryptData
     * @return
     * @throws InvalidKeyException 
     * @throws BadPaddingException 
     * @throws IllegalBlockSizeException 
     */
    public static String decrypt(Cipher cipher,String encryptData,SecretKey secretKey) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
        //將加密後的內容轉換成bytes,使用Base64解碼
        byte[] bytes = Base64.getDecoder().decode(encryptData);
        //初始化cipher,確定為解密密模式,
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        //開始解密
        byte[] decryptBytes = cipher.doFinal(bytes);
        return new String(decryptBytes);
    }
}

執行

public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        String content = "今晚六點半404不見不散!";
        SecretKey secretKey = getSecretKey();
        Cipher cipher = Cipher.getInstance("AES");
        //加密
        String encryptData = encrypt(cipher, content, secretKey);
        System.out.println("加密後的資料:" + encryptData);
        //解密
        String decryptData = decrypt(cipher, encryptData, secretKey);
        System.out.println("解密後的資料:" + decryptData);
    }

案例二將生成的key儲存到本地,然後解密時和下一次加密時就只需要到本地讀取即可:

/**
 * 儲存物件到檔案中
 * @param object
 * @param fileName
 * @throws IOException 
 */
public static void saveObject2File(Object object,String fileName) throws IOException{
    FileOutputStream out = new FileOutputStream(new File(fileName));
    ObjectOutputStream oos = new ObjectOutputStream(out);
    try {
        oos.writeObject(object); 
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        out.close();
        oos.close();
    }
}

讀取

/**
 * 從檔案中讀取物件
 * @param fileName
 * @return
 * @throws IOException 
 * @throws ClassNotFoundException 
 */
public static Object readObjectFromFile(String fileName) throws IOException, ClassNotFoundException{
    FileInputStream in = new FileInputStream(new File(fileName));
    ObjectInputStream ois = new ObjectInputStream(in);
    Object object = null;
    try {
        object = ois.readObject();
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        in.close();
        ois.close();
    }
    
    return object;
}

自定義祕鑰:

/**
 *自定義祕鑰
 * @return
 * @throws NoSuchAlgorithmException
 */
private static SecretKey getSecretKey(String keyWord) throws NoSuchAlgorithmException {
    //得到keyGenerator物件
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
    //初始化種子得到key
    keyGenerator.init(new SecureRandom(keyWord.getBytes()));
    SecretKey secretKey = keyGenerator.generateKey();
    return secretKey;
}

對稱加密相對於非對稱加密不安全(key被得到,就可以被破解)

非對稱加密
常見演算法:RSA、Elgamal、揹包演算法、Rabin、D-H、ECC(橢圓曲線加密演算法)等

應用場景:銀行和電商網站,他就採用非對稱加密,將公鑰給所有人,你們就用這個公鑰加密,私鑰我自己留著,誰也不知道,所以除了我,誰也解密不了。
案例(資料量較小):

/**
         * 獲取金鑰對
         * @return
         * @throws NoSuchAlgorithmException
         */
        public static KeyPair getKeypair() throws NoSuchAlgorithmException{
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            return keyPair;
        }
    /**
         * 加密AES
         * @param content
         * @return
         * @throws NoSuchPaddingException 
         * @throws NoSuchAlgorithmException 
         * @throws InvalidKeyException 
         * @throws BadPaddingException 
         * @throws IllegalBlockSizeException 
         */
        public static String encrypt(Cipher cipher,String content,PublicKey publicKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
            //content轉換成位元組陣列
            byte[] bytes = content.getBytes();
            //初始化cipher,確定為加密模式
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            //開始加密
            byte[] encryptBytes = cipher.doFinal(bytes);
            return Base64.getEncoder().encodeToString(encryptBytes);
        }
/**
         * 解密
         * @param encryptData
         * @return
         * @throws InvalidKeyException 
         * @throws BadPaddingException 
         * @throws IllegalBlockSizeException 
         */
        public static String decrypt(Cipher cipher,String encryptData,PrivateKey privateKey) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
            //將加密後的內容轉換成bytes,使用Base64解碼
            byte[] bytes = Base64.getDecoder().decode(encryptData);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            //開始解密
            byte[] decryptBytes = cipher.doFinal(bytes);
            return new String(decryptBytes);
        
    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
            String content = "今晚六點半404不見不散";
            //獲取金鑰對
            KeyPair keypair = getKeypair();
            PublicKey publicKey = keypair.getPublic();
            //獲取cipher
            Cipher cipher = Cipher.getInstance("RSA");
            //加密
            String encryptData = encrypt(cipher, content, publicKey);
            System.out.println(encryptData);
            PrivateKey privateKey = keypair.getPrivate();
            String decryptData = decrypt(cipher, encryptData, privateKey);
            System.out.println(decryptData);
        }

如果資料量大的話(大於117bytes),則要對要加密、解密的資料進行分塊處理,程式碼如下:

    /**
 * 分塊進行加密或解密
 * @param cipher
 * @param bytes
 * @param max
 * @return
 * @throws IllegalBlockSizeException
 * @throws BadPaddingException
 * @throws IOException
 */
private static ByteArrayOutputStream doFinalWithBlock(Cipher cipher, byte[] bytes,int max)
        throws IllegalBlockSizeException, BadPaddingException, IOException {
    int inputOffset = 0;//從0位元組開始加密
    int leng = bytes.length;//得到位元組總長度
    ByteArrayOutputStream baos = new ByteArrayOutputStream();//將加密的資料寫入baos
    while(inputOffset < leng){//如果加密的長度小於總長度加密
        if (leng - inputOffset >= max) {//剩下沒被加密的位元組如果大於117,就加密117
            byte[] encryptBytes = cipher.doFinal(bytes, 0, max);
            baos.write(encryptBytes);
            inputOffset = inputOffset + max;//加密一段位元組,移動位置
        }else {//剩下沒被加密的位元組如果小於117,就加密剩下的
            byte[] encryptBytes = cipher.doFinal(bytes, 0, leng - inputOffset);
            baos.write(encryptBytes);
            inputOffset = leng;
        }
    }
    return baos;
}

篡改風險:
擷取加密過的資訊,自己寫一段資訊用公鑰加密傳送過去篡改資訊
篡改風險的解決辦法:
訊息摘要是一個不可逆的過程。常用來防篡改。
常見演算法:MD5、SHA、CRC等
傳送加密過的訊息和md5過的訊息摘要,得到資訊後解密資訊md5一下,如果
MD5過的訊息摘要與傳過來的摘要相同就證明沒被篡改過