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;  
    }  

}  

转自:http://redstarofsleep.iteye.com/blog/1171282

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
双向 RSA + AES 加密是一种常见的加密方式,其中使用 RSA 算法加密 AES 密钥,然后使用 AES 算法加密数据。在 C# 中,可以使用 `RSACryptoServiceProvider` 类和 `AesCryptoServiceProvider` 类来实现此加密方式。以下是一个简单的示例: ```csharp using System; using System.IO; using System.Security.Cryptography; using System.Text; class Program { static void Main(string[] args) { string plainText = "Hello, world!"; byte[] encryptedData = Encrypt(plainText); string decryptedText = Decrypt(encryptedData); Console.WriteLine("Original text: {0}", plainText); Console.WriteLine("Encrypted data: {0}", Convert.ToBase64String(encryptedData)); Console.WriteLine("Decrypted text: {0}", decryptedText); } static byte[] Encrypt(string plainText) { byte[] aesKey = GenerateAesKey(); using (var rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; byte[] encryptedAesKey = rsa.Encrypt(aesKey, true); // 使用 RSA 加密 AES 密钥 using (var aes = new AesCryptoServiceProvider()) { aes.Key = aesKey; aes.GenerateIV(); using (var memoryStream = new MemoryStream()) { memoryStream.Write(aes.IV, 0, aes.IV.Length); using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write)) { byte[] plainData = Encoding.UTF8.GetBytes(plainText); cryptoStream.Write(plainData, 0, plainData.Length); cryptoStream.FlushFinalBlock(); } byte[] encryptedData = memoryStream.ToArray(); byte[] result = new byte[encryptedAesKey.Length + encryptedData.Length]; Buffer.BlockCopy(encryptedAesKey, 0, result, 0, encryptedAesKey.Length); Buffer.BlockCopy(encryptedData, 0, result, encryptedAesKey.Length, encryptedData.Length); return result; } } } } static string Decrypt(byte[] encryptedData) { byte[] encryptedAesKey = new byte[128]; // RSA 加密 AES 密钥得到的密文长度为 128 字节 byte[] encryptedDataOnly = new byte[encryptedData.Length - encryptedAesKey.Length]; Buffer.BlockCopy(encryptedData, 0, encryptedAesKey, 0, encryptedAesKey.Length); Buffer.BlockCopy(encryptedData, encryptedAesKey.Length, encryptedDataOnly, 0, encryptedDataOnly.Length); using (var rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; byte[] aesKey = rsa.Decrypt(encryptedAesKey, true); // 使用 RSA 解密 AES 密钥 using (var aes = new AesCryptoServiceProvider()) { aes.Key = aesKey; aes.IV = encryptedDataOnly.Take(aes.IV.Length).ToArray(); using (var memoryStream = new MemoryStream()) { using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write)) { cryptoStream.Write(encryptedDataOnly, aes.IV.Length, encryptedDataOnly.Length - aes.IV.Length); cryptoStream.FlushFinalBlock(); } byte[] decryptedData = memoryStream.ToArray(); return Encoding.UTF8.GetString(decryptedData); } } } } static byte[] GenerateAesKey() { using (var aes = new AesCryptoServiceProvider()) { aes.GenerateKey(); return aes.Key; } } } ``` 上面的代码中,首先调用 `GenerateAesKey` 方法生成 AES 密钥,然后使用 RSA 算法加密 AES 密钥。加密时,先将 AES 密钥使用 RSA 加密,然后使用 AES 算法加密数据。具体来说,将 AES 密钥和 IV 都写入 `MemoryStream` 对象中,然后使用 `CryptoStream` 对象将数据写入 `MemoryStream` 对象中。最后将密文和 RSA 加密AES 密钥一起返回。 解密时,先从密文中取出 RSA 加密AES 密钥,然后使用 RSA 算法解密 AES 密钥。解密时,先从密文中取出 AES 的 IV 值,然后使用 `CryptoStream` 对象将数据解密。最后将解密后的文本返回。 注意,上面的示例仅用于演示 RSA + AES 加密的基本原理,实际使用中还需要考虑安全性等因素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值