JAVA中的加密演算法之雙向加密(二)
- 2020 年 4 月 2 日
- 筆記
本節主要講述Java雙向加密演算法中的非對稱加密演算法實現。 (二)、非對稱加密 1976年,美國學者Dime和Henman為解決資訊公開傳送和密鑰管理問題,提出一種新的密鑰交換協議,允許在不安全的媒體上的通訊雙方交換資訊,安全地達成一致的密鑰,這就是「公開密鑰系統」。相對於「對稱加密演算法」這種方法也叫做「非對稱加密演算法」。 與對稱加密演算法不同,非對稱加密演算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰 (privatekey)。公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種演算法叫作非對稱加密演算法。 1. RSA 公鑰加密演算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美國麻省理工學院)開發的。RSA取名來自開發他們三者的名字。RSA是目前最有影響力的公鑰加密演算法,它能夠抵抗到目前為止已知的所有密碼攻擊,已被ISO推薦為公鑰數據加密標準。RSA演算法基於一個十分簡單的數論事實:將兩個大素數相乘十分容易,但那時想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰。
Java程式碼
import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; public class EncrypRSA { /** * 加密 * @param publicKey * @param srcBytes * @return * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws IllegalBlockSizeException * @throws BadPaddingException */ protected byte[] encrypt(RSAPublicKey publicKey,byte[] srcBytes)throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{ if(publicKey!=null){ //Cipher負責完成加密或解密工作,基於RSA Cipher cipher = Cipher.getInstance("RSA"); //根據公鑰,對Cipher對象進行初始化 cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] resultBytes = cipher.doFinal(srcBytes); return resultBytes; } return null; } /** * 解密 * @param privateKey * @param srcBytes * @return * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws IllegalBlockSizeException * @throws BadPaddingException */ protected byte[] decrypt(RSAPrivateKey privateKey,byte[] srcBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{ if(privateKey!=null){ //Cipher負責完成加密或解密工作,基於RSA Cipher cipher = Cipher.getInstance("RSA"); //根據公鑰,對Cipher對象進行初始化 cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] resultBytes = cipher.doFinal(srcBytes); return resultBytes; } return null; } /** * @param args * @throws NoSuchAlgorithmException * @throws BadPaddingException * @throws IllegalBlockSizeException * @throws NoSuchPaddingException * @throws InvalidKeyException */ public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException { EncrypRSA rsa = new EncrypRSA(); String msg = "郭XX-精品相聲"; //KeyPairGenerator類用於生成公鑰和私鑰對,基於RSA演算法生成對象 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); //初始化密鑰對生成器,密鑰大小為1024位 keyPairGen.initialize(1024); //生成一個密鑰對,保存在keyPair中 KeyPair keyPair = keyPairGen.generateKeyPair(); //得到私鑰 RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate(); //得到公鑰 RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic(); //用公鑰加密 byte[] srcBytes = msg.getBytes(); byte[] resultBytes = rsa.encrypt(publicKey, srcBytes); //用私鑰解密 byte[] decBytes = rsa.decrypt(privateKey, resultBytes); System.out.println("明文是:" + msg); System.out.println("加密後是:" + new String(resultBytes)); System.out.println("解密後是:" + new String(decBytes)); } } import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; public class EncrypRSA { /** * 加密 * @param publicKey * @param srcBytes * @return * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws IllegalBlockSizeException * @throws BadPaddingException */ protected byte[] encrypt(RSAPublicKey publicKey,byte[] srcBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{ if(publicKey!=null){ //Cipher負責完成加密或解密工作,基於RSA Cipher cipher = Cipher.getInstance("RSA"); //根據公鑰,對Cipher對象進行初始化 cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] resultBytes = cipher.doFinal(srcBytes); return resultBytes; }return null;} /** * 解密 * @param privateKey * @param srcBytes * @return * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws IllegalBlockSizeException * @throws BadPaddingException */ protected byte[] decrypt( RSAPrivateKey privateKey,byte[] srcBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{ if(privateKey!=null){ //Cipher負責完成加密或解密工作,基於RSA Cipher cipher = Cipher.getInstance("RSA"); //根據公鑰,對Cipher對象進行初始化 cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] resultBytes = cipher.doFinal(srcBytes); return resultBytes;}return null;} /** * @param args * @throws NoSuchAlgorithmException * @throws BadPaddingException * @throws IllegalBlockSizeException * @throws NoSuchPaddingException * @throws InvalidKeyException */ public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException { EncrypRSA rsa = new EncrypRSA(); String msg = "郭XX-精品相聲"; //KeyPairGenerator類用於生成公鑰和私鑰對,基於RSA演算法生成對象 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); //初始化密鑰對生成器,密鑰大小為1024位 keyPairGen.initialize(1024); //生成一個密鑰對,保存在keyPair中 KeyPair keyPair = keyPairGen.generateKeyPair(); //得到私鑰RSA PrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate(); //得到公鑰RSA PublicKey publicKey = (RSAPublicKey)keyPair.getPublic(); //用公鑰加密 byte[] srcBytes = msg.getBytes(); byte[] resultBytes = rsa.encrypt(publicKey, srcBytes); //用私鑰解密 byte[] decBytes = rsa.decrypt(privateKey, resultBytes); System.out.println("明文是:" + msg); System.out.println("加密後是:" + new String(resultBytes)); System.out.println("解密後是:" + new String(decBytes)); }}
2. DSA Digital Signature Algorithm (DSA)是Schnorr和ElGamal簽名演算法的變種,被美國NIST作為DSS(DigitalSignature Standard)。(感覺有點複雜,沒有附程式碼) 詳見http://63938525.iteye.com/blog/1051565 (三)、題外話 MySQL加密解密函數 MySQL有兩個函數來支援這種類型的加密,分別叫做ENCODE()和DECODE()。 下面是一個簡單的實例:
Mysql程式碼 mysql> INSERT INTO users (username,password) VALUES ('joe',ENCODE('guessme','abr')); Query OK, 1 row affected (0.14 sec) mysql> INSERT INTO users (username,password) VALUES ('joe',ENCODE('guessme','abr'));Query OK, 1 row affected (0.14 sec)
其中,Joe的密碼是guessme,它通過密鑰abracadabra被加密。要注意的是,加密完的結果是一個二進位字元串,如下所示: 提示:雖然ENCODE()和DECODE()這兩個函數能夠滿足大多數的要求,但是有的時候您希望使用強度更高的加密手段。在這種情況下,您可以使用AES_ENCRYPT()和AES_DECRYPT()函數,它們的工作方式是相同的,但是加密強度更高。 單向加密與雙向加密不同,一旦數據被加密就沒有辦法顛倒這一過程。因此密碼的驗證包括對用戶輸入內容的重新加密,並將它與保存的密文進行比對,看是否匹配。一種簡單的單向加密方式是MD5校驗碼。MySQL的MD5()函數會為您的數據創建一個「指紋」並將它保存起來,供驗證測試使用。下面就是如何使用它的一個簡單例子:
Mysql程式碼 mysql> INSERT INTO users (username,password) VALUES ('joe',MD5('guessme')); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO users (username,password) VALUES ('joe',MD5('guessme'));Query OK, 1 row affected (0.00 sec)
或者,您考慮一下使用ENCRYPT()函數,它使用系統底層的crypt()系統調用來完成加密。這個函數有兩個參數:一個是要被加密的 字元串,另一個是雙(或者多)字元的「salt」。它然後會用salt加密字元串;這個salt然後可以被用來再次加密用戶輸入的內容,並 將它與先前加密的字元串進行比對。下面一個例子說明了如何使用它:
Mysql程式碼 mysql> INSERT INTO users (username,password) VALUES('joe', ENCRYPT('guessme','ab')); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO users (username,password) VALUES('joe', ENCRYPT('guessme','ab'));Query OK, 1 row affected (0.00 sec)
提示:ENCRYPT()只能用在UNIX、LINIX系統上,因為它需要用到底層的crypt()庫。