Java對稱與非對稱加密解密,AES與RSA
加密技術可以分為對稱與非對稱兩種.
對稱加密,解密,即加密與解密用的是同一把祕鑰,常用的對稱加密技術有DES,AES等
而非對稱技術,加密與解密用的是不同的祕鑰,常用的非對稱加密技術有RSA等
為什麼要有非對稱加密,解密技術呢
假設這樣一種場景A要傳送一段訊息給B,但是又不想以明文傳送,所以就需要對訊息進行加密.如果採用對稱加密技術,那麼加密與解密用的是同一把祕鑰.除非B事先就知道A的祕鑰,並且儲存好.這樣才可以解密A發來的訊息.
由於對稱技術只有一把祕鑰,所以祕鑰的管理是一個很麻煩的問題.而非對稱技術的誕生就解決了這個問題.非對稱加密與解密使用的是不同的祕鑰,並且祕鑰對是一一對應的,即用A的私鑰加密的密文只有用A的公鑰才能解密.
這樣的話,每個人都有兩把祕鑰,私鑰和公鑰,私鑰是隻有自己才知道的,不能告訴別人,而公鑰是公開的,大家都可以知道.這樣,當A想要傳送訊息給B的時候,只需要用B的公鑰對訊息進行加密就可以了,由於B的私鑰只有B才擁有,所以A用B的公鑰加密的訊息只有B才能解開.而B想更換自己的祕要時也很方便,只須把公鑰告訴大家就可以了.
那麼,既然非對稱加密如此之好,對稱加密就沒有存在的必要了啊,其實不然,由於非對稱加密演算法的開銷很大,所以如果直接以非對稱技術來加密傳送的訊息效率會很差.那麼怎麼辦呢?解決的辦法也很簡單,就是把對稱加密技術與非對稱加密技術結合起來使用.
還是這個例子:A要傳送一個訊息給B.
一,A先生成一個對稱祕鑰,這個祕鑰可以是隨機生成的,
二,A用B的公鑰加密第一步生成的這個對稱祕鑰
三,A把加密過的對稱祕鑰發給B
四,A用第一步生成的這個對稱祕鑰加密實際要發的訊息
五,A把用對稱祕鑰加密的訊息發給B
對於B
他先收到A發來的對稱祕鑰,這個祕鑰是用B的公鑰加密過的,所以B需要用自己的私鑰來解密這個祕鑰
然後B又收到A發來的密文,這時候用剛才解密出來的祕鑰來解密密文
這樣子的整個過程既保證了安全,又保證了效率.
接下來是Java實現:
我這個Java實現使用的是AES的對稱加密和RSA的非對稱加密(DES的對稱加密實現方法和AES的是一樣的,但是由於DES演算法本身有缺陷,容易被破解,所以現在多用其升級版AES對稱加密)
AES對稱加密,解密
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.security.InvalidKeyException;
- import java.security.Key;
- import java.security.NoSuchAlgorithmException;
- import java.security.SecureRandom;
- import javax.crypto.BadPaddingException;
- import javax.crypto.Cipher;
- import javax.crypto.IllegalBlockSizeException;
- import javax.crypto.KeyGenerator;
- import javax.crypto.NoSuchPaddingException;
- import javax.crypto.ShortBufferException;
- publicclass AES {
- private Key key;
- /**
- * 生成AES對稱祕鑰
- * @throws NoSuchAlgorithmException
- */
- publicvoid generateKey() throws NoSuchAlgorithmException {
- KeyGenerator keygen = KeyGenerator.getInstance("AES");
- SecureRandom random = new SecureRandom();
- keygen.init(random);
- this.key = keygen.generateKey();
- }
- /**
- * 加密
- * @param in
- * @param out
- * @throws InvalidKeyException
- * @throws ShortBufferException
- * @throws IllegalBlockSizeException
- * @throws BadPaddingException
- * @throws NoSuchAlgorithmException
- * @throws NoSuchPaddingException
- * @throws IOException
- */
- publicvoid encrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {
- this.crypt(in, out, Cipher.ENCRYPT_MODE);
- }
- /**
- * 解密
- * @param in
- * @param out
- * @throws InvalidKeyException
- * @throws ShortBufferException
- * @throws IllegalBlockSizeException
- * @throws BadPaddingException
- * @throws NoSuchAlgorithmException
- * @throws NoSuchPaddingException
- * @throws IOException
- */
- publicvoid decrypt(InputStream in, OutputStream out) throws InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException {
- this.crypt(in, out, Cipher.DECRYPT_MODE);
- }
- /**
- * 實際的加密解密過程
- * @param in
- * @param out
- * @param mode
- * @throws IOException
- * @throws ShortBufferException
- * @throws IllegalBlockSizeException
- * @throws BadPaddingException
- * @throws NoSuchAlgorithmException
- * @throws NoSuchPaddingException
- * @throws InvalidKeyException
- */
- publicvoid crypt(InputStream in, OutputStream out, int mode) throws IOException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(mode, this.key);
- int blockSize = cipher.getBlockSize();
- int outputSize = cipher.getOutputSize(blockSize);
- byte[] inBytes = newbyte[blockSize];
- byte[] outBytes = newbyte[outputSize];
- int inLength = 0;
- boolean more = true;
- while (more) {
- inLength = in.read(inBytes);
- if (inLength == blockSize) {
- int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
- out.write(outBytes, 0, outLength);
- } else {
- more = false;
- }
- }
- if (inLength > 0)
- outBytes = cipher.doFinal(inBytes, 0, inLength);
- else
- outBytes = cipher.doFinal();
- out.write(outBytes);
- out.flush();
- }
- publicvoid setKey(Key key) {
- this.key = key;
- }
- public Key getKey() {
- return key;
- }
- }
RSA非對稱加密,解密對稱祕鑰
Java程式碼- publicclass RSA {
- publicstaticfinalint KEYSIZE = 512;
- private KeyPair keyPair;
- private Key publicKey;
- private Key privateKey;
- /**
- * 生成祕鑰對
- * @return
- * @throws NoSuchAlgorithmException
- */
- public KeyPair generateKeyPair() throws NoSuchAlgorithmException {
- KeyPairGenerator pairgen = KeyPairGenerator.getInstance("RSA");
- SecureRandom random = new SecureRandom();
- pairgen.initialize(RSA.KEYSIZE, random);
- this.keyPair = pairgen.generateKeyPair();
- returnthis.keyPair;
- }
- /**
- * 加密祕鑰
- * @param key
- * @return
- * @throws NoSuchAlgorithmException
- * @throws NoSuchPaddingException
- * @throws InvalidKeyException
- * @throws IllegalBlockSizeException
- */
- publicbyte[] wrapKey(Key key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException {
- Cipher cipher = Cipher.getInstance("RSA");
- cipher.init(Cipher.WRAP_MODE, this.privateKey);
- byte[] wrappedKey = cipher.wrap(key);
- return wrappedKey;
- }
- /**
- * 解密祕鑰
- * @param wrapedKeyBytes
- * @return
- * @throws NoSuchAlgorithmException
- * @throws NoSuchPaddingException
- * @throws InvalidKeyException
- */
- public Key unwrapKey(byte[] wrapedKeyBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
- Cipher cipher = Cipher.getInstance("RSA");
- cipher.init(Cipher.UNWRAP_MODE, this.publicKey);
- Key key = cipher.unwrap(wrapedKeyBytes, "AES", Cipher.SECRET_KEY);
- return key;
- }
- public Key getPublicKey() {
- return publicKey;
- }
- publicvoid setPublicKey(Key publicKey) {
- this.publicKey = publicKey;
- }
- public Key getPrivateKey() {
- return privateKey;
- }
- publicvoid setPrivateKey(Key privateKey) {
- this.privateKey = privateKey;
- }
- }