加密算法与java实现和HTTPS原理简介

一、安全问题

在我们的数据传输过程中有以下几个安全问题:
Q1、中间人篡改过程中的数据,使得接收方接收到错误的数据
Q2、发送方发送数据,被中间人获取,窃取发送方的机密信息。
Q3、中间人模拟发送方发送数据,接收人接收到的是中间人的数据。

二、应用场景

在我们的应用中需要考虑这些问题的场景:
C1、开放平台open接口。
C2、对互联网开放访问的服务端。

三、加密算法

为解决上面几个场景的几个安全问题,有以下几种加密算法。

S1、签名、摘要算法

哈希算法,主要是验证数据完整性。
特点:
1、长度不受限制
2、hash值容易计算
3、过程不可逆
有一种压缩散列, 能够把不同长度的值散列成相同长度的值,当明文不同而hash值相同时,叫做“hash碰撞”
主要有MD5,SHA,MAC3种算法。

MD5

摘要是128位的,即32位16进制的字符串
不可逆,高度离散型。MD5>MD4>MD2
但是文字碰撞率比SHA256高
java实现:

import org.apache.commons.codec.binary.Hex
public static void jdkMD5(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD1");// 得到MD5加密的对象
            byte[] md5Bytes = md.digest(str.getBytes("UTF-8"));
            // Hex.encodeHexString()将byte[]数组转换成十六进制
            System.out.println("JDK MD5:" + Hex.encodeHexString(md5Bytes));
            BigInteger bi = new BigInteger(1, md5Bytes);
            System.out.println(bi.toString(16));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

输出:
JDK MD5:87b9d8e8b87cf7f59ed59852a17dd128

SHA

SHA1 160位的,但是已被破解
SHA-256 256位的,比较靠谱

private static void jdkSHA256(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");// 得到MD5加密的对象
            byte[] md5Bytes = md.digest(str.getBytes("UTF-8"));
            System.out.println("JDK SHA-256:" + Hex.encodeHexString(md5Bytes));
            // Hex.encodeHexString()将byte[]数组转换成十六进制
            BigInteger bi = new BigInteger(1, md5Bytes);
            System.out.println(bi.toString(16));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
输出:
JDK SHA-256:75927f072a8da41477c4236ad81de37b4bf0c8bfc033a97602aa2733cee83d58

MAC

加入秘钥计算,秘钥经过一系列的计算和元字符串组成一个新的字符串,再MD5或者SHA-256计算得到

 public static void jdkHmacMD5(String str) {
        try {

            // 还原密钥,HmacMD5是算法的名字
            SecretKey restoreSecretKey = new SecretKeySpec("deng".getBytes(), "HmacMD5");
            // 实例化MAC
            Mac mac = Mac.getInstance("HmacMD5");
            // 初始化MAC
            mac.init(restoreSecretKey);
            // 执行消息摘要
            byte[] hmacMD5Bytes = mac.doFinal(str.getBytes());
            System.out.println("jdk hmacMD5:"
                    + Hex.encodeHexString(hmacMD5Bytes));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void jdkHmacSHA256(String str) {
        try {

            // 还原密钥,HmacMD5是算法的名字
            SecretKey restoreSecretKey = new SecretKeySpec("deng".getBytes(), "HmacSHA256");
            // 实例化MAC
            Mac mac = Mac.getInstance("HmacSHA256");
            // 初始化MAC
            mac.init(restoreSecretKey);
            // 执行消息摘要
            byte[] hmacMD5Bytes = mac.doFinal(str.getBytes());
            System.out.println("jdk HmacSHA256:"
                    + Hex.encodeHexString(hmacMD5Bytes));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
输出:
jdk hmacMD5:fc969a3904490852d6209ffd27cab3e5
jdk HmacSHA256:1d1884f44eeecf818457345159dfcc571160baa68784b5d411cdf96f6e60ee26

S2、对称加密

使用相同的密钥进行加密,解密。
常用:AES(安全) DES

DES

(Data Encryption Standard),数据加密标准,已被破解。
秘钥长度:56位

3DES

经过3轮DES

AES

(Advanced Encryption Standard),高级加密标准,未被破解,比3DES效率高。
秘钥长度:128

public static void jdkAES(String str) {
        try {
            // 获取KEY生成器
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");

            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            random.setSeed("111111".getBytes());//设置加密用的种子,密钥
            keyGenerator.init(128, random);
//          keyGenerator.init(128);
            // 产生KEY
            SecretKey secretKey = keyGenerator.generateKey();
            // 获取KEY
            byte[] keyBytes = secretKey.getEncoded();

            // KEY转换
            Key key = new SecretKeySpec(keyBytes, "AES");

            // 加密
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(str.getBytes());
            System.out.println("jdk aes encrypt:" + Base64.encodeBase64String(result));

            // 解密
            cipher.init(Cipher.DECRYPT_MODE, key);
            result = cipher.doFinal(result);
            System.out.println("jdk aes decrypt:" + new String(result));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
输出:
jdk aes encrypt:td9pqIv9Z9Q1Y4n+LO3GKg==
jdk aes decrypt:denganming

S3、非对称加密

一对加密对,分为公钥和私钥,有RSA ESA等。
公钥加密用作数据加密,私钥解密;
私钥加密用作数据签名,公钥验签。
对明文有限制,不能大于公钥的长度。通常只做ca数字签名和对称密钥加密。

RSA

RSA:基于因子分解,既能用于数字加密也能用于数字签名
秘钥长度:512-65536 默认1024 jdk

  public static void jdkRSA(String str) {
        try {
            // 1.初始化发送方密钥
//            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
//            keyPairGenerator.initialize(512);
//            KeyPair keyPair = keyPairGenerator.generateKeyPair();
//            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
//            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
//            System.out.println("Public Key:"+ Base64.encodeBase64String(rsaPublicKey.getEncoded()));
//            System.out.println("Private Key:"+ Base64.encodeBase64String(rsaPrivateKey.getEncoded()));
            String publicKeyStr = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAK9m6RcW8OH/HQeL/YVhyKX1v79V6Lgm\n" +
                    "/+39AcLx0jdt8zPDk57A/8ld9PKpz8RAPXJ3aq2vuSRpWghSJ07v5CcCAwEAAQ==";
            String privateKeyStr = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAr2bpFxbw4f8dB4v9\n" +
                    "hWHIpfW/v1XouCb/7f0BwvHSN23zM8OTnsD/yV308qnPxEA9cndqra+5JGlaCFIn\n" +
                    "Tu/kJwIDAQABAkEAibMm5oOSFDntllEmdKIxnWhyYkmVa4zievmXem3R9MTF49oz\n" +
                    "aR0mCAuM0LVe1xL0SeKDPN4vGyKmASc295T0MQIhANRhtLlLVQF67Bb/7DCWHe38\n" +
                    "Th9IyHrllqSRMwQ344IdAiEA02zw+PCXdJfHYAqsRM8rMz7CANTR2QXm+WUGHl59\n" +
                    "bBMCIAIQdQ48AjaCeFr839HVE7NleWjqbzBqnN06oBFRbb+tAiEAkhxoj/FdCdNW\n" +
                    "krXthYQSW9DUK9TnzO56SAIb72LnlIcCIFqEL75aMM+R7LEG0TjXY3oD/jOePVoA\n" +
                    "+NHO45CI/jaf";

            // 2.私钥加密、公钥解密 ---- 加密
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] result = cipher.doFinal(str.getBytes());
            System.out.println("私钥加密、公钥解密 ---- 加密:"+ Base64.encodeBase64String(result) + "--" + result.length+"---"+Base64.decodeBase64(privateKeyStr).length);

            // 3.私钥加密、公钥解密 ---- 解密
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
            keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            result = cipher.doFinal(result);
            System.out.println("私钥加密、公钥解密 ---- 解密:" + new String(result));

            // 4.公钥加密、私钥解密 ---- 加密
            X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
            KeyFactory keyFactory2 = KeyFactory.getInstance("RSA");
            PublicKey publicKey2 = keyFactory2.generatePublic(x509EncodedKeySpec2);
            Cipher cipher2 = Cipher.getInstance("RSA");
            cipher2.init(Cipher.ENCRYPT_MODE, publicKey2);
            byte[] result2 = cipher2.doFinal(str.getBytes());
            System.out.println("公钥加密、私钥解密 ---- 加密:"+ Base64.encodeBase64String(result2)+ "--" + result2.length+"---"+Base64.decodeBase64(publicKeyStr).length);

            // 5.公钥加密、私钥解密 ---- 解密
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
            KeyFactory keyFactory5 = KeyFactory.getInstance("RSA");
            PrivateKey privateKey5 = keyFactory5.generatePrivate(pkcs8EncodedKeySpec5);
            Cipher cipher5 = Cipher.getInstance("RSA");
            cipher5.init(Cipher.DECRYPT_MODE, privateKey5);
            byte[] result5 = cipher5.doFinal(result2);
            System.out.println("公钥加密、私钥解密 ---- 解密:" + new String(result5) );

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
输出:
私钥加密、公钥解密 ---- 加密:P3NhKa8y+jTXuOHFkZE9Vkc9dYvZonr1bLT4fj4/tB70EU9JP1fnJWf7xrDczC7+HxVr4GlH6M3/h4Qkb59Vdg==--64---345
私钥加密、公钥解密 ---- 解密:denganming
公钥加密、私钥解密 ---- 加密:I5OB0cwfzKHWwUnIsvw2XoLaomwwlQpIkcFmH8lWgWjMDWqYK6DO17xEUHXVKR1iB/jxROX4Ejbyw/f59nEUew==--64---94
公钥加密、私钥解密 ---- 解密:denganming

S4、数字签名

先签名,再用私钥加密签名得到数字签名
先用MD5,再RSA私钥加密。

public static void jdkRSAMD5(String str) {
        try {
            // 1.初始化密钥
            KeyPairGenerator keyPairGenerator = KeyPairGenerator
                    .getInstance("RSA");
            //设置KEY的长度
            keyPairGenerator.initialize(512);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            //得到公钥
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
            //得到私钥
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();

            // 2.进行签名
            //用私钥进行签名
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
                    rsaPrivateKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            //构造一个privateKey
            PrivateKey privateKey = keyFactory
                    .generatePrivate(pkcs8EncodedKeySpec);
            //声明签名的对象
            Signature signature = Signature.getInstance("MD5withRSA");
            signature.initSign(privateKey);
            signature.update(str.getBytes());
            //进行签名
            byte[] result = signature.sign();
            System.out.println("jdk rsa sign:" + Hex.encodeHexString(result));

            // 3.验证签名
            //用公钥进行验证签名
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
                    rsaPublicKey.getEncoded());
            keyFactory = KeyFactory.getInstance("RSA");
            //构造一个publicKey
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            //声明签名对象
            signature = Signature.getInstance("MD5withRSA");
            signature.initVerify(publicKey);
            signature.update(str.getBytes());
            //验证签名
            boolean bool = signature.verify(result);
            System.out.println("jdk rsa verify:" + bool);
        } catch (Exception e) {
            System.out.println(e.toString());
        }

    }
输出:
jdk rsa sign:6f2e0a9a028271906c40559c26cebb290c30744066474507df0fb91652ba739139fcccdeff9b8450898e1587afd7647ac8fcc932d44ea736320176609a7f081b
jdk rsa verify:true

S5、数字证书

数字证书就是:服务端的公钥+服务端信息+CA数字签名(第三方机构通过自己的私钥加密的数字证书的签名)/证书编号
浏览器/操作系统存留大的第三方机构的公钥,用于解开数字证书得到服务端公钥
可以使用keyTools生成证书:https://www.cnblogs.com/xdp-gacl/p/3750965.html

四、解决方案

我们就考虑互联网的解决方案
Q1、加签可以解决
Q2、公钥加密,只要服务端有私钥,其他人没有,获取不到数据。
Q3、私钥加密,只有客户端有私钥,其他人没有,不能发送请求。

五、HTTPS的原理

同时使用对称加密和非对称加密。
对称加密是传输过程中的加密(效率高),非对称加密是刚开始建立连接时使用(耗时,安全)。
建立SSL安全连接的全过程:
1、服务端生成一对非对称加密公私钥,pubK1,priK1。
2、服务端把公钥和服务端信息发送到CA(第三方数字证书颁发机构),由CA生成数字证书
3、数字证书内容:服务端公钥pubK1,服务器信息,CA的数字签名(证书编号),签名算法。
数字签名:由CA用自己的私钥priK2做数字签名。
4、服务端获取到证书,把证书库放到服务端下。
5、客户端请求,建立SSL连接。
6、请求获取到证书,根据证书的颁发机构,用浏览器内置的颁发机构的公钥pubK2,进行解密数字签名,再用同样的签名算法对明文签名,对比2个结果,如果相同的话,则认为合法,获取到服务端的公钥pubK1。
7、客户端利用随机数,(客户端和服务端多次交互产生的随机数,由客户端和服务端产生的随机数),在客户端生成一个密钥K,用公钥pubK1加密,传给服务端。
8、服务端接收到秘钥K,和客户端使用秘钥K进行后面的数据交互。

六、tomcat的设置

参考:https://www.cnblogs.com/wanghaoyuhappy/p/5267702.html

七、参考文档和其他问题

1、https://www.cnblogs.com/Caersi/p/6720789.html
2、https://www.cnblogs.com/lipengxiang2009/p/7471752.html
3、https://showme.codes/2017-02-20/understand-https/
4、https://wetest.qq.com/lab/view/110.html
5、加密系列:https://blog.csdn.net/u013991521/article/details/48182081
6、A、B两人分别在两座岛上。B生病了,A有B所需要的药。C有一艘小船和一个可以上锁的箱子。C愿意在A和B之间运东西,但东西只能放在箱子里。只要箱子没被上锁,C都会偷走箱子里的东西,不管箱子里有什么。如果A和B各自有一把锁和只能开自己那把锁的钥匙,A应该如何把东西安全递交给B?
A加锁,B加锁,A解锁,B解锁
7、
分组加密:分成组加密,多用于网络传输
流加密:一个字符一个字符加密
8、服务端私钥如何存储 tomcat设置目录
9、浏览器保存的是CA的公钥和证书信息
10、CA的密钥被污染怎么办:证书链
11、登录密码器的实现

1、60s刷新一次
2、使用相同的hash算法 生成固定的6位数字
3、参数:用户信息,时间,私钥
4、注册时,根据用户名 生成私钥。把私钥,软件(加密算法),密码器发给用户
5、客户端算法:时间(分)+私钥 hash一个6位的数字 30s/60s有效,打开软件时开始计算时间
6、服务端验证:时间(分)+私钥 hash一个6位的数字 验证当前1分钟和上一分钟的code
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值