JAVA中的加密演算法之雙向加密(二)

本節主要講述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()庫。