对称加密+非对称加密,实现数据安全传输-程序员宅基地

技术标签: 非对称加密  对称加密  Android  

一般金融类的产品,涉及前端和后端交互的时候,都会都严格的数据安全保证。防止黑客攻击,信息篡改。

加密方式有很多,总的来说,分为2种:对称和非对称。我们先来看一下,这两种加密方式分别是什么?他们有什么区别?

对称加密:

对称加密,即采用对称的密码编码技术,他的特点是,加密和解密使用相同的秘钥。

 

常见的对称加密算法有DES、3DES、Blowfish、IDEA、RC4、RC5、RC6和AES。对称加密算法使用起来简单快捷,密钥较短,且破译困难。

但是对称秘钥在使用过程中存在以下问题:

1、对称加密算法一般不能提供信息完整性的鉴别。它无法验证发送者和接受者的身份;

2、对称密钥的管理和分发工作是一件具有潜在危险的和烦琐的过程。如何防止秘钥泄露是一个难点。

非对称加密:

非对称加密技术,需要两个秘钥,公钥和私钥。公钥和私钥成对出现。

 

如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。甲方只能用其专用密钥解密由其公用密钥加密后的任何信息。

非对称加密的典型应用是数字签名。

常见的非对称加密算法有:RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)。

对称+非对称:

现在,我们已经对对称和非对称加密有了一定的了解。接下来,我将会给大家介绍一下,我在项目中使用的一种加密方式:对称+非对称。

先看一张流程图:

先看发送方:

这里,我们主要有2步操作。

1、报文原文使用对称加密技术。对称加密的秘钥(避免混淆,这里称对称密码)。根据随机数生成。每次发起请求时,会重新产生一个随机数,进一步降低被破解的风险。      

2、对称密码通过非对称加密方式进行加密。公钥由后台产生,匹配的私钥由后台保管。这样产生一个加密后的对称密码。前端在发送给后端之后,后端需要用匹配的私钥才能解开。

再看接收方:

接收方在接收到数据包之后,同样有两步操作:

1、会使用匹配的私钥解密加密的对称密码,获取到真实的对称密码。

2、使用对称密码,解密加密报文,获取原报文内容。

 

这样做的好处是:

1、因为我们的对称密码是使用非对称加密的,因此,想要破解,需要找到相应的公钥才行。

2、每次请求会重新生成一个对称密码,这就加大了破解的难度。

 

代码实现:

工具类:

非对称加密:

public class RSA1 {
    /**
     * 随机生成公钥和私钥
     */

    public static final String publicKeyString  = "publicKeyString";
    public static final String privateKeyString = "privateKeyString";


    public static HashMap<String, String> getRandomKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        keyPairGen.initialize(1024);//生成大小 1024
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();//获取公钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();//获取私钥
        HashMap<String, String> keyMap = new HashMap<String, String>();
        keyMap.put(publicKeyString, new String(Base64.encode(publicKey.getEncoded(), Base64.DEFAULT)));//获取公钥Base64编码
        keyMap.put(privateKeyString, new String(Base64.encode(privateKey.getEncoded(), Base64.DEFAULT)));//获取密钥Base64编码
        return keyMap;
    }

    /**
     * 通过字符串生成私钥
     */
    public static PrivateKey getPrivateKey(String privateKeyData) {
        PrivateKey privateKey = null;
        try {
            byte[] decodeKey = Base64.decode(privateKeyData, Base64.DEFAULT); //将字符串Base64解码
            PKCS8EncodedKeySpec x509 = new PKCS8EncodedKeySpec(decodeKey);//创建x509证书封装类
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");//指定RSA
            privateKey = keyFactory.generatePrivate(x509);//生成私钥
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return privateKey;
    }


    /**
     * 通过字符串生成公钥
     */
    public static PublicKey getPublicKey(String publicKeyData) {
        PublicKey publicKey = null;
        try {
            byte[] decodeKey = Base64.decode(publicKeyData, Base64.DEFAULT);
            X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodeKey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            publicKey = keyFactory.generatePublic(x509);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return publicKey;
    }

    /**
     * 加密
     */
    public static byte[] encrypt(String data, Key key) {
        try {
            //取公钥
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm(),"BC");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(data.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     */
    public static byte[] decrypt(byte[] data, Key key) {
        try {
            Cipher cipher = Cipher.getInstance("RSA","BC");
            cipher.init(Cipher.DECRYPT_MODE, key);
            return cipher.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

对称加密:

public class AES_2 {

    public static byte[] genPrivateKey(String password) throws NoSuchAlgorithmException {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        byte[] bytes = tohash256Deal(password);
        SecureRandom securerandom = new SecureRandom(bytes);
        kgen.init(128, securerandom);
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        return key.getEncoded();
    }

    public static byte[] encrypt(String content, SecretKeySpec key) {
        try {
            //创建一个实现指定转换的 Cipher对象,该转换由指定的提供程序提供。
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] byteContent = content.getBytes("utf-8");
            byte[] cryptograph = cipher.doFinal(byteContent);
            return Base64.encode(cryptograph, Base64.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decrypt(byte[] cryptograph, SecretKeySpec key) {
        try {
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] content = cipher.doFinal(Base64.decode(cryptograph, Base64.DEFAULT));
            return new String(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static byte[] encrypt(String content, String password) {
        try {
            //"AES":请求的密钥算法的标准名称
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            //256:密钥生成参数;securerandom:密钥生成器的随机源
            SecureRandom securerandom = new SecureRandom(tohash256Deal(password));
            kgen.init(128, securerandom);
            //生成秘密(对称)密钥
            SecretKey secretKey = kgen.generateKey();
            //返回基本编码格式的密钥
            byte[] enCodeFormat = secretKey.getEncoded();
            //根据给定的字节数组构造一个密钥。enCodeFormat:密钥内容;"AES":与给定的密钥内容相关联的密钥算法的名称
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            //将提供程序添加到下一个可用位置
            Security.addProvider(new BouncyCastleProvider());
            //创建一个实现指定转换的 Cipher对象,该转换由指定的提供程序提供。
            //"AES/ECB/PKCS7Padding":转换的名称;"BC":提供程序的名称
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] byteContent = content.getBytes("utf-8");
            byte[] cryptograph = cipher.doFinal(byteContent);
            return Base64.encode(cryptograph, Base64.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decrypt(byte[] cryptograph, String password) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            SecureRandom securerandom = new SecureRandom(tohash256Deal(password));
            kgen.init(128, securerandom);
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] content = cipher.doFinal(Base64.decode(cryptograph, Base64.DEFAULT));
            return new String(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    public static byte[] tohash256Deal(String datastr) {
        try {
            MessageDigest digester = MessageDigest.getInstance("SHA-256");
            digester.update(datastr.getBytes());
            byte[] hex = digester.digest();
            return hex;
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

}  

发送方和接收方的实现:

        String content = "000";
        JSONObject jsonObject = new JSONObject();
        try {
            LogT.i("++++++++++++++++++++++发送方+++++++++++++++++++++++++=");
            //产生私钥
            int random = (int) ((Math.random() * 9 + 1) * 100000);
            //私钥字节
            byte[] bytes = AES_2.genPrivateKey(String.valueOf(random));
            //传输报文加密
            SecretKeySpec key1 = new SecretKeySpec(bytes, "AES");
            byte[] content_encrypt = AES_2.encrypt(content, key1);
            //公钥对私钥加密
            PublicKey publicKey = RSA1.getPublicKey(public_key);
            sKey_encrypt = RSA1.encrypt(Base64.encodeToString(bytes, Base64.DEFAULT), publicKey);
            //数据组装
            jsonObject.put("key", Base64.encodeToString(sKey_encrypt, Base64.DEFAULT));
            jsonObject.put("content", AES_2.parseByte2HexStr(content_encrypt));

            LogT.i("+++++++++++++++++++++++接收方++++++++++++++++++++++++=");

            //解析获取私钥
            PrivateKey privateKey = RSA1.getPrivateKey(private_key);
            //解析接收到的key数据
            byte[] decode = Base64.decode(Base64.encodeToString(sKey_encrypt, Base64.DEFAULT), Base64.DEFAULT);
            //私钥解密
            byte[] decrypt = RSA1.decrypt(decode, privateKey);
            //解码私钥字节
            byte[] decode_orig = Base64.decode(new String(decrypt), Base64.DEFAULT);
            //加密的报文
            byte[] HexStrByte = AES_2.parseHexStr2Byte(AES_2.parseByte2HexStr(content_encrypt));
            SecretKeySpec key2 = new SecretKeySpec(decode_orig, "AES");
            //解密后的报文
            String decrypt1 = AES_2.decrypt(HexStrByte, key2);
            LogT.i(decrypt1);//000
        } catch (Exception e) {
            e.printStackTrace();
        }

 

                                                                                扫码关注,共同进步

 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Aminy123/article/details/81871092

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签