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; public class AES { private Key key; /** * 生成AES对称秘钥 * @throws NoSuchAlgorithmException */ public void 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 */ public void 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 */ public void 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 */ public void 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 = new byte[blockSize]; byte[] outBytes = new byte[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(); } public void setKey(Key key) { this.key = key; } public Key getKey() { return key; } }
RSA非对称加密,解密对称秘钥
public class RSA { public static final int 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(); return this.keyPair; } /** * 加密秘钥 * @param key * @return * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws IllegalBlockSizeException */ public byte[] 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; } public void setPublicKey(Key publicKey) { this.publicKey = publicKey; } public Key getPrivateKey() { return privateKey; } public void setPrivateKey(Key privateKey) { this.privateKey = privateKey; } }