小工具      在线工具  汉语词典  css  js  c++  java

HTTPS加密原理

拓展,https 额外说明

收录于:40天前

一、单向加密

单向加密算法也称为不可逆算法,是指明文加密后原则上无法恢复;

姓名 运行速度 安全
MD5 快的 中间
SHA-1 慢的 高的
SHA-256 慢点 更高
// hutool工具包有md5,sha1,sha256等加密算法
<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
</dependency>
public static void main(String[] args) throws NoSuchAlgorithmException {
    
    System.out.println(Arrays.toString(DigestUtil.md5("常见加密算法"))); //16位byte数组
    System.out.println(DigestUtil.md5Hex16("常见加密算法")); // 16位
    System.out.println(DigestUtil.md5Hex("常见加密算法")); // 32位
}

[12, 116, 39, -14, 17, -57, 63, -111, 78, -13, -14, 3, 62, -73, -64, -22]
11c73f914ef3f203
0c7427f211c73f914ef3f2033eb7c0ea

二、对称加密

对称加密使用密钥来加密消息,然后使用相同的密钥来解密消息。也就是说,加密和解密使用相同的密钥。

算法 密钥长度 速度 安全 如果
DES 56/64 快点 低(完全依赖密钥,容易受到穷举搜索攻击) 中间
AES 128/192/256 快的 高(ECB模式生成固定密钥,安全性较低,CBC模式每次生成不同的密文,安全性较高) 低的
主意 128 慢点 高(军工级,耐差异分析和相关分析) 中间

出于性能和安全考虑,这里以AES加密算法为例。

AES的ECB模式:每次生成的密文都相同

public class AESECBUtil {
    
    /** * 加密 * * @param content 加密内容 * @param aesKey 加密aeskey,一定要16个字节 */
    public static String encryption(String content, String aesKey) throws Exception {
    
        SecretKeySpec secretKey = new SecretKeySpec(aesKey.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        byte[] bytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
        return Base64Utils.encodeToString(bytes);
    }

    /** * 解密 * * @param content 解密内容 * @param aesKey 加密使用的key,一定要16个字节 */
    public static String decrypt(String content, String aesKey) throws Exception {
    
        byte[] bytes = StringUtils.isEmpty(content) ? null : Base64Utils.decodeFromString(content);
        SecretKeySpec secretKey = new SecretKeySpec(aesKey.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decryptBytes = cipher.doFinal(bytes);
        return new String(decryptBytes, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) throws Exception {
    
        String msg = "这是测试内容";
        // key一定要16个字节
        String key = "123456789abcdefg";
        String encryption = encryption(msg, key);
        System.out.println(encryption);
        String decrypt = decrypt(encryption, key);
        System.out.println(decrypt);
    }
}
vjphG35JfUn8n8l0Iqos2qrURPN7J3zZaiPXU+3Rhmk=
这是测试内容

AES的CBC模式:每次生成的密文都不同,更加安全。

public class AESCBCUtil {
    
    //这里需要设置你的32位字节密钥
    public static final String ENCRYPT_OR_DECRYPT_KEY = "1234567890abcdef1234567890abcdef";
    // 256位密钥 = 32 bytes Key:
    //CBC模式是安全性较高的AES加密模式,它需要一个随机数作为IV参数,这样对于同一份明文,每次生成的密文都不同
    public static final byte[] BYTES_KEY = ENCRYPT_OR_DECRYPT_KEY.getBytes(StandardCharsets.UTF_8);
    public static final String INSTANCE = "AES/CBC/PKCS5Padding";
    public static final String AES = "AES";

    // 加密
    public static String encrypt(String password) throws Exception {
    
        Cipher cipher = Cipher.getInstance(INSTANCE);
        SecretKeySpec keySpec = new SecretKeySpec(BYTES_KEY, AES);
        // CBC模式需要生成一个16 bytes的initialization vector
        SecureRandom sr = SecureRandom.getInstanceStrong();
        byte[] iv = sr.generateSeed(16);
        IvParameterSpec ivps = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps);
        byte[] data = cipher.doFinal(password.getBytes(StandardCharsets.UTF_8));
        // IV不需要保密,把IV和密文一起返回
        return DatatypeConverter.printBase64Binary(join(iv, data));
    }

    // 解密
    public static String decrypt(String password) throws Exception {
    
        byte[] iv = new byte[16];
        byte[] input = DatatypeConverter.parseBase64Binary(password);
        byte[] data = new byte[input.length - 16];
        // 把password分割成IV和密文
        System.arraycopy(input, 0, iv, 0, 16);
        System.arraycopy(input, 16, data, 0, data.length);
        // 解密
        Cipher cipher = Cipher.getInstance(INSTANCE);
        SecretKeySpec keySpec = new SecretKeySpec(BYTES_KEY, AES);
        IvParameterSpec ivps = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps);
        return new String(cipher.doFinal(data), StandardCharsets.UTF_8);
    }

    public static byte[] join(byte[] bs1, byte[] bs2) {
    
        byte[] r = new byte[bs1.length + bs2.length];
        System.arraycopy(bs1, 0, r, 0, bs1.length);
        System.arraycopy(bs2, 0, r, bs1.length, bs2.length);
        return r;
    }

    public static void main(String[] args) throws Exception {
    
        String password = "这是CBC产生的密文";
        String encryptStr1 = encrypt(password);
        System.out.println("第一次加密:" + encryptStr1);
        String decryptStr1 = decrypt(encryptStr1);
        System.out.println("第一次解密:" + decryptStr1);

        String encryptStr2 = encrypt(password);
        System.out.println("第二次加密:" + encryptStr2);
        String decryptStr2 = decrypt(encryptStr1);
        System.out.println("第二次解密:" + decryptStr2);
    }
}
第一次加密:ujUa1sQAYN4tWDa9vrSnaiV8oFUjwb7dyRL93C3w3G7wzf1bs+L+/l1ipyjWkfzH
第一次解密:这是CBC产生的密文
第二次加密:QYP4nzAd/2DDuKiSMck1W3TuddXf71BBUSSzzS2f9h3cXolNZEwq0IUFWclJiDcQ
第二次解密:这是CBC产生的密文

从结果可以看出,第一次加密和第二次加密的密文不同,但可以解析出相同的明文,安全系数非常高。

三、非对称加密

非对称加密算法需要两个密钥:公钥(publickey:简称公钥)和私钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

有两种常见的非对称加密。这里我们以经典的RSA为例:

姓名 到期 安全 计算速度 如果
RSA 高的 高的 中间 中间
ECC 高的 高的 慢的 高的
public class RSAEncrypt {
    
    /** * 加密算法 DESEDE */
    private static String ALGORITHM = "RSA";
    /** * key值大小 */
    private static int KEYSIZE = 1024;
    /** * 公钥存放文件自定义 */
    private static final String PUBLIC_KEY_FILE = "PublicKey";
    /** * 私钥存放文件自定义 */
    private static final String PRIVATE_KEY_FILE = "PrivateKey";
    /** * object 对象流 */
    private static ObjectInputStream ois = null;

    /** * 生成密钥对 */
    private static void generateKeyPair() throws Exception {
    
        //RSA算法可信任的随机数源
        SecureRandom sr = new SecureRandom();
        //RSA算法创建KeyPairGenerator对象
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
        //随机数据源初始化KeyPairGenerator对象
        kpg.initialize(KEYSIZE, sr);
        //生成密匙对
        KeyPair kp = kpg.generateKeyPair();
        //得到公钥
        Key publicKey = kp.getPublic();
        //得到私钥
        Key privateKey = kp.getPrivate();
        //用对象流将生成的密钥写入文件
        ObjectOutputStream ois = new ObjectOutputStream(new FileOutputStream(PUBLIC_KEY_FILE));
        ois.writeObject(publicKey);
        ois.close();
        ois = new ObjectOutputStream(new FileOutputStream(PRIVATE_KEY_FILE));
        ois.writeObject(privateKey);
        ois.close();
    }

    /** * 加密方法 * * @param source 源数据 * @return */
    public static String encrypt(String source) throws Exception {
    
        ois = new ObjectInputStream(new FileInputStream(PUBLIC_KEY_FILE));
        Key key = (Key) ois.readObject();
        ois.close();
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] b = source.getBytes();
        b = cipher.doFinal(b);
        return Base64.getEncoder().encodeToString(b);
    }

    /** * 解密算法 * * @param cryptograph * @return * @throws Exception */
    public static String decrypt(String cryptograph) throws Exception {
    
        ois = new ObjectInputStream(new FileInputStream(PRIVATE_KEY_FILE));
        Key key = (Key) ois.readObject();
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] b = Base64.getDecoder().decode(cryptograph);
        b = cipher.doFinal(b);
        return new String(b);
    }

    public static void main(String[] args) throws Exception {
    
// generateKeyPair();
        String source = "Hello World 要加密的字符串!!!@@@??? ===dd!";// 要加密的字符串
        String cryptograph = encrypt(source);// 生成的密文
        String cryptograph1 = encrypt(source);// 生成的密文
        String cryptograph2 = encrypt(source);// 生成的密文
        System.out.println(cryptograph);
        System.out.println(cryptograph1);
        System.out.println(cryptograph2);
        String target = decrypt(cryptograph);// 解密密文
        String target1 = decrypt(cryptograph1);// 解密密文
        String target2 = decrypt(cryptograph2);// 解密密文
        System.out.println(target);
        System.out.println(target1);
        System.out.println(target2);
    }
}
  • 公钥加密、私钥解密、生成的密文都是不同的。
Ki5FfK2nZN1i8KAe6uImS220P98YopKk3aLcm2ievFPjgjt8q4EdqZAfrEwyXW0S3uo0EwBOle5e7lLqjmakk3BBaDGyyC/pZgtU8nCGLE6h56cRmi2aR/O3TrazQyOJ3vap0ex+Jc2uZmGX+Y4QYMzyd0h9hAcfcAs0xc9xnYw=
dPLgLMLgjjoljLOHYa7o9vhTtABNoYr03RqJUSDx2JCTN7n4pZbPD5BbfnrX0WsjM1+o6NgK/fVb8/FTUe7Wg/iq+HE/gW7bqprUl0k9UZXLLft6EWWNyZfoMcNXk3q3Dgb7IXK0qXf0WbWYcUBTf0g2KPsJJLmomYtkl+f9e4s=
DDE0mGZ49rBQ4Q2i4Iz01ybjTntRatTdvty5tYZXbo52GiINc/emcaqCilkL19mzUmTECVna8b/9L3duBJ9WbQoHQpes2KvSjn4Q1tYh+VZhIiUMuN/D4YqBIssFYGgK6rN2W7+f9Z+vVRxPnP2pDFh3ORbEl+ttBcHOy996XoE=
Hello World 要加密的字符串!!!@@@???   ===dd!
Hello World 要加密的字符串!!!@@@???   ===dd!
Hello World 要加密的字符串!!!@@@???   ===dd!
  • 私钥加密,公钥解密,生成的密文是相同的
bfYvfBB3pTWanx/uBKpEkETeulsdNW75vGBU6xbeH5c+eUCtxtTAZV4UlZuZGL3CgPd04r3oBjTCssi1efUM2eUovfgSevKFlOaXSfp+mg6A3UhY1DKWvHSSFd7NkasftbA9D34COqB8RyUVGvJMYBIk6t55v5u1K52Rq1nsjMY=
bfYvfBB3pTWanx/uBKpEkETeulsdNW75vGBU6xbeH5c+eUCtxtTAZV4UlZuZGL3CgPd04r3oBjTCssi1efUM2eUovfgSevKFlOaXSfp+mg6A3UhY1DKWvHSSFd7NkasftbA9D34COqB8RyUVGvJMYBIk6t55v5u1K52Rq1nsjMY=
bfYvfBB3pTWanx/uBKpEkETeulsdNW75vGBU6xbeH5c+eUCtxtTAZV4UlZuZGL3CgPd04r3oBjTCssi1efUM2eUovfgSevKFlOaXSfp+mg6A3UhY1DKWvHSSFd7NkasftbA9D34COqB8RyUVGvJMYBIk6t55v5u1K52Rq1nsjMY=
Hello World 要加密的字符串!!!@@@???   ===dd!
Hello World 要加密的字符串!!!@@@???   ===dd!
Hello World 要加密的字符串!!!@@@???   ===dd!

四、HTTPS原理

HTTP 的问题:

  • 无法保证消息的机密性
  • 无法保证消息的完整性和准确性
  • 无法保证来源的可靠性

HTTPS就是为了解决上述问题。这里的S值是SSL加密。简单来说,HTTPS是利用一些加解密、数字证书、数字签名技术来实现数据安全;

  • 数字证书和数字签名

为了解决非对称加密中公钥来源的不安全问题。我们可以利用数字证书和数字签名来解决

  1. 数字证书的申请
    • 自己本地先生成一对RSA密匙,然后拿着自己的公钥以及其他信息(比如说企业名称)去CA申请数字证书
    • CA获得该信息后,会选择一种单向Hash算法(类似于MD5)对信息进行加密,防止篡改。加密的内容称为摘要。
    • CA还会用自己的私钥对摘要进行加密,摘要加密后的数据我们称之为数字签名
    • CA会整合我们的应用信息(包括服务器的公钥)和数字签名,从而生成数字证书并交给浏览器
  2. 浏览器怎么验证数字签名
    • 服务器获得数字证书后,服务器会将数字证书发送给客户端,客户端需要使用CA的公钥来解密数字证书并验证数字证书的合法性。
    • 我们的电脑和浏览器已经内置了一些权威机构的根证书。这些根证书包含 CA 的公钥。
    • 客户端使用CA的公钥来解密数字证书。如果解密成功,则说明该证书来自合法的证书颁发机构。解密成功后,客户端得到摘要。
    • 客户端会根据与CA相同的哈希算法生成一份申请信息摘要,并与解密后的进行比较。如果相同,则说明内容完整,没有被篡改。
    • 最后,客户端从证书中安全地获取服务器的公钥,并可以通过安全的非对称加密与服务器进行通信。
  • HTTPS原理
  1. 浏览器验证数字证书后,在本地生成随机AES密钥xxx
  2. 使用服务器传输来的公钥对 xxx 进行加密。服务器获取到后,用私钥解密,得到xxx。
  3. 一旦双方知道密钥并建立 HTTPS 链接,他们就可以使用它来加密通信。
. . .

相关推荐

额外说明

flex拖拽实例

<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"          layout="horizontal" b

额外说明

Java基础 第二节 第十二课

抽象类 概述 由来 定义 abstract 使用格式 抽象方法 抽象类 抽象的使用 注意事项 概述 由来 父类中的方法, 被它的子类们重写. 子类各自实现都不尽相同. 那么父类的方法声明和方法主体, 只有声明还有意义, 而方法主体则没有存在的意义了. 我

额外说明

机器学习 第四节 第四课

[toc] Pandas 之 DataFrame 和一个 ndarray 一样, 我们通过 shape, ndim, dtype 了解这个 ndarray 的基本信息, 那么对于 DataFarme 我们有什么方法了解呢? DataFrame 的基础属性

额外说明

C++程序设计:补齐函数求鸡的数量

问题描述: n个铜钱买了m只鸡,其中公鸡(A)一只5钱、母鸡(B)一只3钱,小鸡(C)一钱3只,问m只鸡中公鸡、母鸡、小鸡各多少。   样例输入: 100 100 样例输出: A0,B25,C75 A4,B18,C78 A8,B11,C81 A12,B4

额外说明

使用Visual Leak Detector排查内存泄漏问题

目录 1、VLD工具概述 2、下载、安装VLD 2.1、下载VLD 2.2、安装VLD 3、VLD安装目录及文件说明

额外说明

Android R或Android 11 上柔和缓慢的背光亮度调节实现

Android R或Android 11 上柔和缓慢的背光亮度调节实现 最近研究了一下Android R的背光调节动画: 相关代码: DisplayPowerController.java private final float mBrightnessR

额外说明

【Java 基础篇】Java 标准输出流详解:输出你的程序之美

Java 编程中,标准输出流是一个重要的概念。它允许我们将程序的输出信息显示在终端或控制台上,这对于调试、用户界面和与用户的交互非常重要。在这篇文章中,我们将深入探讨 Java 的标准输出流,了解如何使用它以及一些常见的用法和技巧。 什么是标准输出流?

额外说明

【计算机系统】位运算与逻辑运算

计算机系统的位运算与逻辑运算 一、位 1、定义 二进制数字系统中数据存储的最小单位,即每个二进制数0或1就称为位。位也叫比特(bit),8个bit组成一个字节(byte),每个字节表示程序中的某些文本字符。字长(word size)表征了CPU一次能并行

额外说明

解决Windows丢失mfc120chs.dll文件问题

其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或者损坏了,这时你只需下载这个mfc120chs.dll文件进行安装(前提是找到适合的版本)

额外说明

wordpress弹窗通知_如何仅在回复其WordPress注释时通知用户

WordPress 弹出通知 您只想在回复用户的 WordPress 评论时通知用户吗?默认情况下,用户无法知道是否有人回复了他们在您的 WordPress 网站上的评论。在本文中,我们将向您展示如何仅在回复用户的 WordPress 评论时轻松通知用户

ads via 小工具