Kotlin基礎學習3
阿新 • • 發佈:2020-08-06
一、加密
1、對稱加密與非對稱加密的區別
- 對稱加密。同一把鑰匙進行加密和解密
- 非對稱加密,公鑰加密,私鑰解密。
對稱加密:
常見演算法:AES、DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK
AES:高階加密標準(Advanced Encryption Standard)
DES:資料加密標準(Data Encryption Standard)
案例一:
/** *獲取祕鑰 * @return * @throws NoSuchAlgorithmException */ private staticSecretKey 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過的訊息摘要與傳過來的摘要相同就證明沒被篡改過