美文网首页加密-解密
java实现RSA与AES混合加密

java实现RSA与AES混合加密

作者: 就知道写代码 | 来源:发表于2019-05-09 12:38 被阅读0次

    之前写过一篇在python中实现RSA和AES混合加密的文章,这次用java来实现

    什么是RSA加密?

    这是一种非对称加密算法,密钥分为公钥和私钥。通常私钥长度有512bit,1024bit,2048bit,4096bit,长度越长,越安全,但是生成密钥越慢,加解密也越耗时。一般公钥用来加密数据,私钥用来解密数据,并且为防止有人冒充发送密文,私钥又可以负责签名,公钥负责验证。公钥可以分发给其他系统,但是私钥一般保存在唯一的系统中。

    什么是AES加密?

    这是一种对称加密算法,加密和解密公用同一密钥。密钥最长只有256个bit,执行速度快,易于硬件实现。通常发送方使用密钥加密数据后会使用口令对密钥进行加密,然后把密文和加密后的密钥一同发送给接收方,接收方接收到数据后首先使用口令对密钥进行解密,在使用密钥对密文进行解密。

    以上两种加密方式都有各自的特点,在互联网领域有着广泛的应用,我们需要根据不同的场景使用不同的加密解密方案。
    一般需要加密传输的时候存在以下两种场景:

    客户端发送加密数据,服务端解密后返回明文:

    例如用户在客户端提交个人信息时,客户端把个人信息加密后发送给服务端,服务端再返回code或者提交成功的提示

    客户端发送加密数据,服务端解密后同样返回密文

    例如用户登录时,客户端发送加密后的账号密码,服务端解密后生成对应的token,并且对token进行加密,客户端收到返回的token再对其进行解密

    如何生成RSA公钥和私钥可以参考我的另一篇文章
    RSA公钥和私钥的生成以及PKCS#1与PKCE#8格式的转换
    下面直接贴代码

    java实现RSA加密

    Config类

    **
     * @author Taoyimin
     * @create 2019 05 07 20:39
     */
    public class Config {
        public static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
        public static final String RSA_ALGORITHM = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
        //必须是PKCS8格式
        public static final String CLIENT_PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAO/8ucCgOTJ7DCPC" +
                "rCCL1VKDnUX61QnxwbAvpGp1/lletEIcjUouM7F0VvMHzViNLvpw7N7NBHPa+5gO" +
                "js68t9hKMUh+a6RTE34SWIqSDRPCzDKVWugsFb04o3vRl3rZ1z6B+QDdW7xwOhEr" +
                "PPoEqmjjIOjQPcU6xs0SPzSimOa1AgMBAAECgYAO5m0OBaSnerZNPhf7yVLMVbmd" +
                "D67MeEMjUkHuDjdlixi8BhPLqESzXtrLKg/Y0KM7D2nVh3sgSldWoIjDUzpCx8Z2" +
                "yHLU1K2wakMdBgEF3xeJPxxZRpP+earl0SyLTA4hMxl48uAjn/mkPgzoMgQkqyQz" +
                "5HOWjjsCLJFyEvqmoQJBAP5cBk0KXpHnCMgOupbi/pXDyaF1o+dCE97GaEdrV/0P" +
                "uwDfYDYfY3wzd1QM7C4b4MmE+SNVpC0W9PyaMONJlN0CQQDxiPiGdwX9actMNJea" +
                "JZ+k3BjCN+mM6Px7j/mtYcXWNZkyCXSXUBI62drZ0htenrh2qwichMlMgNJClvG6" +
                "Gu+5AkEA30R7q2gstrkrNh/nnMZHXcJr3DPc2QNhWayin/4TT+hc51krpJZMxxqN" +
                "5dMqBRcnavwzi9aCs6lxBcF6pCdUaQJANhd7uPls4PzRZ6abkQz9/LjB3rUQ29rN" +
                "uIpc2yR7XuawAVG2x7BJ9N4XMhLoyD75hrH1AsCGKFjtPbZ6OjiQGQJAF2DbIodC" +
                "uYb6eMZ8ux1Ab0wBEWWc5+iGgEVBNh22uZ/klE1/C0+KKzZhqgzaA/vPapq6dhuJ" +
                "sNXlJia10PwYrQ==";
    
        public static final String CLIENT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDv/LnAoDkyewwjwqwgi9VSg51F" +
                "+tUJ8cGwL6Rqdf5ZXrRCHI1KLjOxdFbzB81YjS76cOzezQRz2vuYDo7OvLfYSjFI" +
                "fmukUxN+EliKkg0TwswylVroLBW9OKN70Zd62dc+gfkA3Vu8cDoRKzz6BKpo4yDo" +
                "0D3FOsbNEj80opjmtQIDAQAB";
    
        public static final String SERVER_PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAPGkxlAJPKR3BRxT\n" +
                "PIeB3pDv117j8XbpuEik5UIOlY3GUtAV1sad5NNDUAnP/DB80yAQ8ycm9Xdkutuo" +
                "f25Xlb7w0bRQNpfJlijx9eF8PsB6t63r8KAfWJlqbNHgN8AMK9P5XzVyN4YiEnUl" +
                "Jh/EYiwLiYzflNnmnnfRrI4nUo8fAgMBAAECgYEAvwTxm81heeV4Tcbi33/jUBG4" +
                "4BMzCzyA6DQp4wkiYju3tTS+Xq3seLEKcWdPxYi3YO7lODsM6j/fksrlSXXFMe1i" +
                "ZAF3FNuDVZPz2zdFYS8vh6kdlDHMJAUnU/POMMWJ880MQDtkwTuzH8Tao8OKcAP4" +
                "kc0QuG00wOrmuE+5gZECQQD9bqZkJsN+tj3+pxs57azy6B6gOqgm54/ujB+u63XU" +
                "rO9Sf57asgF4OfUFltaVhjlUMSrWcgp6f4HSy7hBSKJpAkEA9BeML5iDIHOgTIws" +
                "+ID55ELbzO7A/YtcYnUU09mkKCdonMXbXke+EhLApf5vX9ZmreoEfJCdsTnMEcQi" +
                "fkjkRwJBALpf2TXl2/cfhs/zjG45f+rTEVK8UFTsDklb+yDkQC87TnTZLbWfGr2T" +
                "wcFugDhOEXL9BYfXLiWQB6VB9Crug6ECQGEmTiFTbj0oSBCvaeauTsdO5PS3whAn" +
                "u2lkeBmpcfCZXsWm6hyoKTpARHTMw789Mjjd/1Mkq96xxkr76U6h7FkCQHRc2elg" +
                "Dh84wqHIptwa+moosVvd7aSzktuOB4CQRO10qKkSHVFuI+sl47A4KGzH/nX9ydUm" +
                "tpsTnQAlXwBczd4=";
    
        public static final String SERVER_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDxpMZQCTykdwUcUzyHgd6Q79de" +
                "4/F26bhIpOVCDpWNxlLQFdbGneTTQ1AJz/wwfNMgEPMnJvV3ZLrbqH9uV5W+8NG0" +
                "UDaXyZYo8fXhfD7Aeret6/CgH1iZamzR4DfADCvT+V81cjeGIhJ1JSYfxGIsC4mM" +
                "35TZ5p530ayOJ1KPHwIDAQAB";
    }
    
    

    RSACipher类

    import javax.crypto.Cipher;
    import javax.crypto.spec.OAEPParameterSpec;
    import javax.crypto.spec.PSource;
    import java.security.*;
    import java.security.spec.MGF1ParameterSpec;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    /**
     * @author Taoyimin
     * @create 2019 05 07 20:25
     */
    public class RSACipher {
        /**
         * 加密方法
         *
         * @param publicKey 公钥
         * @param raw       待加密明文
         * @return 加密后的密文
         * @throws Exception
         */
        public static byte[] encrypt(String publicKey, byte[] raw) throws Exception {
            Key key = getPublicKey(publicKey);
            Cipher cipher = Cipher.getInstance(Config.RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
            byte[] b1 = cipher.doFinal(raw);
            return Base64.encodeBase64(b1);
        }
    
        /**
         * 解密方法
         *
         * @param privateKey 私钥
         * @param enc        待解密密文
         * @return 解密后的明文
         * @throws Exception
         */
        public static byte[] decrypt(String privateKey, byte[] enc) throws Exception {
            Key key = getPrivateKey(privateKey);
            Cipher cipher = Cipher.getInstance(Config.RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
            return cipher.doFinal(Base64.decodeBase64(enc));
        }
    
        /**
         * 获取公钥
         *
         * @param key 密钥字符串(经过base64编码)
         * @return 公钥
         * @throws Exception
         */
        public static PublicKey getPublicKey(String key) throws Exception {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(key.getBytes()));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            return publicKey;
        }
    
        /**
         * 获取私钥
         *
         * @param key 密钥字符串(经过base64编码)
         * @return 私钥
         * @throws Exception
         */
        public static PrivateKey getPrivateKey(String key) throws Exception {
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key.getBytes()));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            return privateKey;
        }
    
        /**
         * 签名
         *
         * @param privateKey 私钥
         * @param content    要进行签名的内容
         * @return 签名
         */
        public static String sign(String privateKey, byte[] content) {
            try {
                PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey.getBytes()));
                KeyFactory keyf = KeyFactory.getInstance("RSA");
                PrivateKey priKey = keyf.generatePrivate(priPKCS8);
                Signature signature = Signature.getInstance("SHA256WithRSA");
                signature.initSign(priKey);
                signature.update(content);
                byte[] signed = signature.sign();
                return new String(Base64.encodeBase64(signed));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 验签
         *
         * @param publicKey 公钥
         * @param content   要验签的内容
         * @param sign      签名
         * @return 验签结果
         */
        public static boolean checkSign(String publicKey, byte[] content, String sign) {
            try {
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                byte[] encodedKey = Base64.decode2(publicKey);
                PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
                java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");
                signature.initVerify(pubKey);
                signature.update(content);
                return signature.verify(Base64.decode2(sign));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }
    
        public static void main(String[] args) throws Exception {
            //客户端代码
            String text = "hello";
            //使用服务端公钥加密
            byte[] encryptText = RSACipher.encrypt(Config.SERVER_PUBLIC_KEY, text.getBytes());
            System.out.println("加密后:\n" + new String(encryptText));
            //使用客户端私钥签名
            String signature = RSACipher.sign(Config.CLIENT_PRIVATE_KEY, encryptText);
            System.out.println("签名:\n" + signature);
    
            //服务端代码
            //使用客户端公钥验签
            boolean result = RSACipher.checkSign(Config.CLIENT_PUBLIC_KEY, encryptText, signature);
            System.out.println("验签:\n" + result);
            //使用服务端私钥解密
            byte[] decryptText = RSACipher.decrypt(Config.SERVER_PRIVATE_KEY, encryptText);
            System.out.println("解密后:\n" + new String(decryptText));
        }
    }
    

    运行结果:

    加密后:
    y5u+c89sm1UZ2VrFwpcRKceQkdL1+N8QmqOiRR/lRvQpYx7a2DQqi962IAgG4wUO4EppetGPCZt+gzNakKnLPE3qCCf3gYd0iT81+Q/9QMSF6MBGEV/eB30VFlgYllpy/VRuwCZBWzZNEjTo/2vi/ntXEuSz02Qp34TpHAbUdww=
    签名:
    kJviixPG3l7hmpPoKg7WXveks2A7hFe1NbcQT0UrdA8cmElzKxqBw6PjnBy3KxSpwx9ilh1W4+aGtiar08WnlRAYBSkGEx7VsoeTNaVDIT09pJcV3qokeO7WQEw29s6HrH1ebPLbfIKkn0jX1XTr7cHIMXxVuOBGOnDf0FhmK7M=
    验签:
    true
    解密后:
    hello
    

    java实现AES加密

    AESCipher类

    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Base64;
    
    /**
     * @author Taoyimin
     * @create 2019 05 07 12:31
     */
    public class AESCipher {
    
        /**
         * 加密方法,使用key充当向量iv,增加加密算法的强度
         *
         * @param key 密钥
         * @param raw 需要加密的内容
         * @return
         */
        public static String encrypt(byte[] key, String raw) throws Exception {
            SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance(Config.AES_ALGORITHM);
            IvParameterSpec iv = new IvParameterSpec(key);
            cipher.init(Cipher.ENCRYPT_MODE, seckey, iv);
            byte[] result = cipher.doFinal(raw.getBytes());
            Base64.Encoder encoder = Base64.getEncoder();
            return encoder.encodeToString(result);
        }
    
        /**
         * 解密方法,使用key充当向量iv,增加加密算法的强度
         *
         * @param key 密钥
         * @param enc 待解密内容
         * @return
         */
        public static String decrypt(byte[] key, String enc) throws Exception {
            SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance(Config.AES_ALGORITHM);
            IvParameterSpec iv = new IvParameterSpec(key);
            cipher.init(Cipher.DECRYPT_MODE, seckey, iv);
            Base64.Decoder decoder = Base64.getDecoder();
            byte[] result = cipher.doFinal(decoder.decode(enc));
            return new String(result);
        }
    
        public static void main(String[] args) throws Exception {
            //客户端代码
            String text = "hello";
            //随机生成16位aes密钥
            byte[] aesKey = SecureRandomUtil.getRandom(16).getBytes();
            String encryptText = AESCipher.encrypt(aesKey, text);
            System.out.println("加密后:\n" + encryptText);
            String decryptText = AESCipher.decrypt(aesKey, encryptText);
            System.out.println("解密后:\n" + decryptText);
        }
    }
    

    运行结果:

    加密后:
    J85vumF+sEJjMDtxgQ41rA==
    解密后:
    hello
    

    RSA+AES混合加密:

    public class Main {
        public static void main(String[] args) throws Exception {
            //客户端代码
            String text = "hello server!";
    
            //随机生成16位aes密钥
            byte[] aesKey = SecureRandomUtil.getRandom(16).getBytes();
            System.out.println("生成的aes密钥:\n" + new String(aesKey));
    
            //使用aes密钥对数据进行加密
            String encryptText = AESCipher.encrypt(aesKey, text);
            System.out.println("经过aes加密后的数据:\n" + encryptText);
    
            //使用客户端私钥对aes密钥签名
            String signature = RSACipher.sign(Config.CLIENT_PRIVATE_KEY, aesKey);
            System.out.println("签名:\n" + signature);
    
            //使用服务端公钥加密aes密钥
            byte[] encryptKey = RSACipher.encrypt(Config.SERVER_PUBLIC_KEY, aesKey);
            System.out.println("加密后的aes密钥:\n" + new String(encryptKey));
    
            //客户端发送密文、签名和加密后的aes密钥
            System.out.println("\n************************分割线************************\n");
            //接收到客户端发送过来的signature encrypt_key encrypt_text
    
            //服务端代码
            //使用服务端私钥对加密后的aes密钥解密
            byte[] aesKey1 = RSACipher.decrypt(Config.SERVER_PRIVATE_KEY, encryptKey);
            System.out.println("解密后的aes密钥:\n" + new String(aesKey1));
    
            //使用客户端公钥验签
            Boolean result = RSACipher.checkSign(Config.CLIENT_PUBLIC_KEY, aesKey1, signature);
            System.out.println("验签结果:\n" + result);
    
            //使用aes私钥解密密文
            String decryptText = AESCipher.decrypt(aesKey1, encryptText);
            System.out.println("经过aes解密后的数据:\n" + decryptText);
        }
    }
    

    运行结果:

    生成的aes密钥:
    95Gnm1leO485A7iZ
    经过aes加密后的数据:
    Mesvxp102Fv1khfBebqXxQ==
    签名:
    EzLFRvY3cFFiRocio+vx0g4l3eZO6wWaoZ+lnI949ETn6xlQ+nDLZ7njSHbjvWCnWai9hFAM99AWHDRvw92jNv9R8T3JHnJ/wFAKvHYryFh0BMuHSeB3yefdqwzRQpbwp+Z/6HL6OA9s9bLw8CKhq3rQCsVKAKiDxTUDqwZ6P3E=
    加密后的aes密钥:
    PtGl6PaJE5ZQIRx62WUn+Ak6iLMBVGbVq+a5ANDHnu6V3EGpT40BF7PBEDsBrebd92kAI1T2Pihts+77N4Zz6LQ8gpQnL1sAao0mz84/ZGvEUgjdK8x75+NLY61VFAEx3eKtjWjLPyqdgahMxJtByRhEw/PGJ5VgEJgNODhts+8=
    
    ************************分割线************************
    
    解密后的aes密钥:
    95Gnm1leO485A7iZ
    验签结果:
    true
    经过aes解密后的数据:
    hello server!
    



    最后附上python版本文章和相关源码源码:
    python实现RSA与AES混合加密
    python,java跨语言RSA+AES混合加密解密以及踩过的那些坑
    https://github.com/taoyimin/rsa-aes-python
    https://github.com/taoyimin/rsa-aes-java

    相关文章

      网友评论

        本文标题:java实现RSA与AES混合加密

        本文链接:https://www.haomeiwen.com/subject/nwoioqtx.html