RSA+AES加解密

2 篇文章 0 订阅
2 篇文章 0 订阅

需求&实现思路

工作中遇到一个需求,需要将接口数据加密发送给后台,项目中采用RSA+AES方式,记录一下思路和实现。

一、加密
1、随机生成AES 32位密钥
2、通过AES对传递数据加密
3、通过RSA的公钥Publickey对AES的密钥进行加密
4、通过RSA的私钥Privatekey对数据进行签名

二、解密
1、得到数据拿到sign值,先做验签
2、使用RSA的私钥private_key解密拿到AES的aesKey
3、使用AES解密得到所需数据

下面是具体实现步骤
1、通过opensll生成加解密所需要的公钥和私钥,生成步骤自行百度,这里 不在介绍
2、AES加解密

    public static class AESUtils {
        private static final String AES = "AES";
        //偏移量
        private static final String IV_STRING = "";
        /**
         * 密钥长度32字节,256位
         */
        private static final int AES_KEY_LENGTH = 32;

        /**
         * 随机生成32位AES密钥
         */
        public static String getRandomString() {
        	//生成规则自己定义
            String base = "";
            Random random = new Random();
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < AES_KEY_LENGTH; i++) {
                int number = random.nextInt(base.length());
                sb.append(base.charAt(number));
            }
            return sb.toString();
        }

        /**
         * 加密
         *
         * @param content 加密内容
         * @return 密文
         * @throws Exception e
         */
        @RequiresApi(api = Build.VERSION_CODES.O)
        public static String encrypt(String key, String content) throws Exception {
            byte[] encryptedBytes = new byte[0];
            try {
                byte[] byteContent = content.getBytes();
                // 注意,为了能与 iOS 统一
                // 这里的 key 不可以使用 KeyGenerator、SecureRandom、SecretKey 生成
                byte[] enCodeFormat = key.getBytes(StandardCharsets.UTF_8);
                SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, AES);
                byte[] initParam = IV_STRING.getBytes();
                IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
                // 指定加密的算法、工作模式和填充方式
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
                encryptedBytes = cipher.doFinal(byteContent);
                // 同样对加密后数据进行 base64 编码
            } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
                LogUtil.e("AES decrypt Exception,content = {},Exception = {}" + content + Arrays.toString(e.getStackTrace()));

            }


//            return Base64.getUrlEncoder().encodeToString(encryptedBytes);
            return Base64Util.encode(encryptedBytes);
        }

        /**
         * 解密
         *
         * @param content 密文
         * @return 明文
         * @throws Exception e
         */
        @RequiresApi(api = Build.VERSION_CODES.O)
        public static String decrypt(String content, String aesKey) {
            // base64 解码
            try {
                byte[] encryptedBytes = Base64Util.decode(content);
                byte[] enCodeFormat = aesKey.getBytes();
                SecretKeySpec secretKey = new SecretKeySpec(enCodeFormat, AES);
                byte[] initParam = IV_STRING.getBytes();
                IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
                byte[] result = cipher.doFinal(encryptedBytes);
                return new String(result, "UTF-8");
            } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {

                LogUtil.e("AES decrypt Exception,content = {},Exception = {}" + content + Arrays.toString(e.getStackTrace()));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

    }

2、RSA加解密,opensll生成公钥和私钥的pem文件放在项目assets下

    public static class RSAUtils {
        /**
         * 算法名字
         */
        private static final String RSA_ALGORITHM = "RSA";

        /**
         * 消息摘要算法
         */
        private static final String MD_ALGORITHM = "SHA256withRSA";

        /**
         * RSA最大加密明文大小
         */
        private static final int MAX_ENCRYPT_BLOCK = 117;

        /**
         * RSA最大解密密文大小
         */
        private static final int MAX_DECRYPT_BLOCK = 128;

        /**
         * 制作公钥
         *
         * @return
         */
        @RequiresApi(api = Build.VERSION_CODES.O)
        public static PublicKey getPublicKey() {

            PublicKey public_Key = null;
            try {
                assert MyApplication.instance != null;
                InputStream in = MyApplication.instance.getResources().getAssets().open("public_key.pem");
                BufferedReader br = new BufferedReader(new InputStreamReader(in));
                String readLine = null;
                StringBuilder sb = new StringBuilder();
                while ((readLine = br.readLine()) != null) {
                    if (readLine.charAt(0) == '-') {
                        continue;
                    } else {
                        sb.append(readLine);
                    }
                }
                KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
                byte[] buffer = Base64Util.decode(sb.toString());
                EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
                public_Key = keyFactory.generatePublic(keySpec);
                return public_Key;
            } catch (Exception e) {
            }
            return null;
        }
       
        /**
         * 制作私钥
         *
         * @return
         */
        @RequiresApi(api = Build.VERSION_CODES.O)
        public static PrivateKey getPrivateKey() {

            PrivateKey privateKey = null;
            try {
                assert MyApplication.instance != null;
                InputStream in = MyApplication.instance.getResources().getAssets().open("private_key.pem");
                BufferedReader br = new BufferedReader(new InputStreamReader(in));
                String readLine = null;
                StringBuilder sb = new StringBuilder();
                while ((readLine = br.readLine()) != null) {
                    if (readLine.charAt(0) == '-') {
                        continue;
                    } else {
                        sb.append(readLine);
                    }
                }
                in.close();
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                byte[] buffer = Base64Util.decode(sb.toString());
                EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(buffer);
                privateKey = keyFactory.generatePrivate(privateKeySpec);
                return privateKey;

            } catch (Exception e) {
            }
            return null;
        }


        /**
         * RSA加密
         * <p>
         * //         * @param data      待加密数据
         *
         * @param publicKey 公钥
         * @return
         */
        @RequiresApi(api = Build.VERSION_CODES.O)
        public static String encrypt(String aesKey, PublicKey publicKey) {
            //RSA加密
            try {
                if (publicKey == null) {
                    return null;
                }
                Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                int inputLen = aesKey.getBytes().length;
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                int offset = 0;
                byte[] cache;
                int i = 0;
                // 对数据分段加密
                while (inputLen - offset > 0) {
                    if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                        cache = cipher.doFinal(aesKey.getBytes(), offset, MAX_ENCRYPT_BLOCK);
                    } else {
                        cache = cipher.doFinal(aesKey.getBytes(), offset, inputLen - offset);
                    }
                    out.write(cache, 0, cache.length);
                    i++;
                    offset = i * MAX_ENCRYPT_BLOCK;
                }
                byte[] encryptedData = out.toByteArray();
                out.close();
                // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
                // 加密后的字符串
                return Base64Util.encode(encryptedData);
            } catch (Exception e) {
//                log.warn("encrypt error, ex:{}", e.getMessage());
            }
            return null;
        }

        /**
         * RSA解密
         *
         * @param data       待解密数据
         * @param privateKey 私钥
         * @return
         */
        @RequiresApi(api = Build.VERSION_CODES.O)
        public static String decrypt(String data, PrivateKey privateKey) {
            try {
                if (privateKey == null) {
                    return null;
                }
                Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
                cipher.init(Cipher.DECRYPT_MODE, privateKey);
                byte[] dataBytes = Base64Util.decode(data);
                int inputLen = dataBytes.length;
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                int offset = 0;
                byte[] cache;
                int i = 0;
                // 对数据分段解密
                while (inputLen - offset > 0) {
                    if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                        cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
                    } else {
                        cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
                    }
                    out.write(cache, 0, cache.length);
                    i++;
                    offset = i * MAX_DECRYPT_BLOCK;
                }
                out.close();
                // 解密后的内容
                return out.toString("UTF-8");
            } catch (Exception e) {
//                log.warn("decrypt error, ex:{}", e.getMessage());
            }
            return null;
        }

        /**
         * 签名
         *
         * @param data       待签名数据
         * @param privateKey 私钥
         * @return 签名
         */
        @RequiresApi(api = Build.VERSION_CODES.O)
        public static String sign(String data, PrivateKey privateKey) {
            try {
                byte[] keyBytes = privateKey.getEncoded();
                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
                KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
                PrivateKey key = keyFactory.generatePrivate(keySpec);
                Signature signature = Signature.getInstance(MD_ALGORITHM);
                signature.initSign(key);
                signature.update(data.getBytes());
                return Base64Util.encode(signature.sign());
            } catch (Exception e) {
//                log.warn("RSA sign error, ex:{}", e.getMessage());
            }
            return null;
        }

        /**
         * 验签
         *
         * @param srcData   原始字符串
         * @param publicKey 公钥
         * @param sign      签名
         * @return 是否验签通过
         */
        @RequiresApi(api = Build.VERSION_CODES.O)
        public static boolean verify(String srcData, PublicKey publicKey, String sign) {
            try {
                byte[] keyBytes = publicKey.getEncoded();
                X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
                KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
                PublicKey key = keyFactory.generatePublic(keySpec);
                Signature signature = Signature.getInstance(MD_ALGORITHM);
                signature.initVerify(key);
                signature.update(srcData.getBytes());
                return signature.verify(Base64Util.decode(sign));
            } catch (Exception e) {
            }
            return false;
        }

    }

3、Base64Util编解码工具类 ,需要依赖javabase64-1.3.1.jar

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import it.sauronsoftware.base64.Base64;

public class Base64Util {
    /** */
    /**
     * 文件读取缓冲区大小
     */
    private static final int CACHE_SIZE = 1024;

    /** */
    /**
     * <p>
     * BASE64字符串解码为二进制数据
     * </p>
     *
     * @param base64
     * @return
     * @throws Exception
     */
    public static byte[] decode(String base64) throws Exception {
        return Base64.decode(base64.getBytes());
    }

    /** */
    /**
     * <p>
     * 二进制数据编码为BASE64字符串
     * </p>
     *
     * @param bytes
     * @return
     * @throws Exception
     */
    public static String encode(byte[] bytes) throws Exception {
        return new String(Base64.encode(bytes));
    }

    /** */
    /**
     * <p>
     * 将文件编码为BASE64字符串
     * </p>
     * <p>
     * 大文件慎用,可能会导致内存溢出
     * </p>
     *
     * @param filePath
     *            文件绝对路径
     * @return
     * @throws Exception
     */
    public static String encodeFile(String filePath) throws Exception {
        byte[] bytes = fileToByte(filePath);
        return encode(bytes);
    }

    /** */
    /**
     * <p>
     * BASE64字符串转回文件
     * </p>
     *
     * @param filePath
     *            文件绝对路径
     * @param base64
     *            编码字符串
     * @throws Exception
     */
    public static void decodeToFile(String filePath, String base64)
            throws Exception {
        byte[] bytes = decode(base64);
        byteArrayToFile(bytes, filePath);
    }

    /** */
    /**
     * <p>
     * 文件转换为二进制数组
     * </p>
     *
     * @param filePath
     *            文件路径
     * @return
     * @throws Exception
     */
    public static byte[] fileToByte(String filePath) throws Exception {
        byte[] data = new byte[0];
        File file = new File(filePath);
        if (file.exists()) {
            FileInputStream in = new FileInputStream(file);
            ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
            byte[] cache = new byte[CACHE_SIZE];
            int nRead = 0;
            while ((nRead = in.read(cache)) != -1) {
                out.write(cache, 0, nRead);
                out.flush();
            }
            out.close();
            in.close();
            data = out.toByteArray();
        }
        return data;
    }

    /** */
    /**
     * <p>
     * 二进制数据写文件
     * </p>
     *
     * @param bytes
     *            二进制数据
     * @param filePath
     *            文件生成目录
     */
    public static void byteArrayToFile(byte[] bytes, String filePath)
            throws Exception {
        InputStream in = new ByteArrayInputStream(bytes);
        File destFile = new File(filePath);
        if (!destFile.getParentFile().exists()) {
            destFile.getParentFile().mkdirs();
        }
        destFile.createNewFile();
        OutputStream out = new FileOutputStream(destFile);
        byte[] cache = new byte[CACHE_SIZE];
        int nRead = 0;
        while ((nRead = in.read(cache)) != -1) {
            out.write(cache, 0, nRead);
            out.flush();
        }
        out.close();
        in.close();
    }

}

4、下面是项目中世界运用

			一、加密
			
 			//获取AES签名
            val aesKey = CipherUtils.AESUtils.getRandomString()
            //加密数据
            val data = CipherUtils.AESUtils.encrypt(aesKey, "需要加密的数据")
            //RSA加密
            val key = CipherUtils.RSAUtils.encrypt(aesKey, publicKey)
            //RSA签名
            val sign = CipherUtils.RSAUtils.sign(data, privateKey)
				二、解密
				//RSA解密
                val aesKey = CipherUtils.RSAUtils.decrypt("后台返回的AES的key值", privateKey)
                //AES解密
                val data = CipherUtils.AESUtils.decrypt("后台返回的加密数据", aesKey)
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当然可以!下面是一个使用RSAAES混合密的示例代码: ```python from Crypto.Cipher import AES, PKCS1_OAEP from Crypto.PublicKey import RSA from Crypto.Random import get_random_bytes # 生成RSA密钥对 key = RSA.generate(2048) private_key = key.export_key() public_key = key.publickey().export_key() # 密数据 data = b'This is a secret message.' # 使用AES生成随机密钥 session_key = get_random_bytes(16) # 使用RSA公钥AES密钥 rsa_cipher = PKCS1_OAEP.new(RSA.import_key(public_key)) encrypted_session_key = rsa_cipher.encrypt(session_key) # 使用AES密数据 aes_cipher = AES.new(session_key, AES.MODE_EAX) ciphertext, tag = aes_cipher.encrypt_and_digest(data) # 传输密后的数据和密钥... # 接收方解密数据 # 使用RSA私钥解密AES密钥 rsa_cipher = PKCS1_OAEP.new(RSA.import_key(private_key)) session_key = rsa_cipher.decrypt(encrypted_session_key) # 使用AES解密数据 aes_cipher = AES.new(session_key, AES.MODE_EAX) decrypted_data = aes_cipher.decrypt_and_verify(ciphertext, tag) print(decrypted_data.decode()) ``` 在这个示例中,首先生成了一个RSA密钥对。然后,生成了一个随机的AES密钥,并使用RSA公钥密了该密钥。接下来,使用AES密钥对要密的数据进行密,并生成了一个认证标签。最后,发送密后的数据和密的AES密钥给接收方。 接收方使用RSA私钥解密接收到的AES密钥,并使用解密后的AES密钥解密数据,并进行认证。 请注意,这只是一个简单的示例代码,用于演示RSAAES混合密的基本概念。在实际应用中,需要更多的安全措施和错误处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踏着蜗牛去旅行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值