密码学看这篇就够了_密码学单表代替、多表代替例子-程序员宅基地

技术标签: 安全  数字签名  非对称加密  数字证书  密码学  对称加密  

概念及发展

概念

密码学是网络安全、信息安全、区块链等产品的基础,常见的非对称加密、对称加密、散列函数等,都属于密码学范畴。
密码学有数千年的历史,从最开始的替换法到如今的非对称加密算法,经历了古典密码学,近代密码学和现代密码学三个阶段。密码学不仅仅是数学家们的智慧,更是如今网络空间安全的重要基础。

古典密码学(1949年之前)

数据的安全基于算法的保密
替换法
用固定的信息将原文替换成无法直接阅读的密文信息。例如将 b 替换成 w ,e 替换成p ,这样bee 单词就变换成了wpp,不知道替换规则的人就无法阅读出原文的含义。
1)单表替换
单表替换即只有一张原文密文对照表单,发送者和接收者用这张表单来加密解密。在上述例子中,表单即为:a b c d e - s w t r p
2)多表替换
多表替换即有多张原文密文对照表单,不同字母可以用不同表单的内容替换。
例如约定好表单为:表单 1:abcde-swtrp 、表单2:abcde-chfhk 、表单 3:abcde-jftou。规定第一个字母用第三张表单,第二个字母用第一张表单,第三个字母用第二张表单,这时 bee单词就变成了(312)fpk ,破解难度更高,其中 312 又叫做密钥,密钥可以事先约定好,也可以在传输过程中标记出来。

移位法

移位法就是将原文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后得出密文,典型的移位法应用有 “ 恺撒密码 ”。
例如约定好向后移动2位(abcde - cdefg),这样 bee 单词就变换成了dgg
移位法也可以采用多表移位的方式,典型的多表案例是“维尼吉亚密码”(又译维热纳尔密码),属于多表密码的一种形式
古典密码的破解
古典密码虽然很简单,但是在密码史上是使用的最久的加密方式,直到“概率论”的数学方法被发现,古典密码就被破解了

近代密码学(1949年~1975年)

密码学真正成为一门科学
恩尼格玛机
恩尼格玛机使用的加密方式本质上还是移位和替代,只不过因为密码表种类极多,破解难度高,同时加密解密机器化,使用便捷,因而在二战时期得以使用。
恩尼格玛机是二战时期纳粹德国使用的加密机器,后被英国破译,参与破译的人员有被称为计算机科学之父、人工智能之父的图灵。

现代密码学(1976年以后)

密码学的新方向-公钥密码学,解决了秘钥分发和管理的问题
散列函数
散列函数,也见杂凑函数、摘要函数或哈希函数,可将任意长度的消息经过运算,变成固定长度数值,常见的有MD5、SHA-1、SHA256,多应用在文件校验,数字签名中。
MD5 可以将任意长度的原文生成一个128位(16字节)的哈希值
SHA-1可以将任意长度的原文生成一个160位(20字节)的哈希值
对称加密
对称密码应用了相同的加密密钥和解密密钥。对称密码分为:序列密码(流密码),分组密码(块密码)两种。流密码是对信息流中的每一个元素(一个字母或一个比特)作为基本的处理单元进行加密,块密码是先对信息流分块,再对每一块分别加密。
例如:原文为1234567890,流加密即先对1进行加密,再对2进行加密,再对3进行加密……最后拼接成密文;块加密先分成不同的块,如1234成块,5678成块,90XX(XX为补位数字)成块,再分别对不同块进行加密,最后拼接成密文。前文提到的古典密码学加密方法,都属于流加密。
对称密码的密钥安全极其重要,加密者和解密者需要提前协商密钥,并各自确保密钥的安全性,一但密钥泄露,即使算法是安全的也无法保障原文信息的私密性。

非对称加密

在实际的使用中,远程的提前协商密钥不容易实现,即使协商好,在远程传输过程中也容易被他人获取,因此非对称密钥此时就凸显出了优势。
非对称密码有两支密钥,公钥(publickey)和私钥(privatekey),加密和解密运算使用的密钥不同。用公钥对原文进行加密后,需要由私钥进行解密;用私钥对原文进行加密后(此时一般称为签名),需要由公钥进行解密(此时一般称为验签)。公钥可以公开的,大家使用公钥对信息进行加密,再发送给私钥的持有者,私钥持有者使用私钥对信息进行解密,获得信息原文。因为私钥只有单一人持有,因此不用担心被他人解密获取信息原文。

ASCII编码

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646
在这里插入图片描述

Base64可视化算法

Base64是网络上最常见的用于传输8Bit字节码的可读性编码算法之一

  1. 可读性编码算法不是为了保护数据的安全性,而是为了可读性
  2. 可读性编码不改变信息内容,只改变信息内容的表现形式
  3. 所谓Base64 即是说在编码过程中使用了64种字符:大写A到Z、小写a到z、数字0到9、“+”和“/”
  4. Base58是Bitcoin(比特币)中使用的一种编码方式,主要用于产生Bitcoin的钱包地址
    相比Base64,Base58不使用数字"0",字母大写"O",字母大写"I",和字母小写"i",以及"+“和”/"符号

算法原理

base64 是 3个字节为一组,一个字节 8位,一共 就是24位 ,然后,把3个字节转成4组,每组6位,3 * 8 = 4 * 6 = 24 ,每组6位,缺少的2位,会在高位进行补0 ,这样做的好处在于 ,base取的是后面6位,去掉高2位 ,那么base64的取值就可以控制在0-63位了,所以就叫base64。0~63在asc码表中正好对应上述64中字符。

注意,因为base64是三个字节一组 ,如果当我们的位数不够(三个字节)的时候,会使用等号来补齐。因此处理结果可能会出现=号

在这里插入图片描述 这里分析 “1” encode 过程:

  1. 字符 1asci码49 二进制表示为: 00110001
  2. 三个字节拆分为四个字节 这里只有一个字节,所以只能拆分成两个(不足的时候补0): 001100 010000
  3. 拆分后连个字节分别为:12 (M) 和 16(Q)
  4. 因为只有一个字节不足三个字节,因此必须进行补位,后边必须补两个“=” ,因此decode结果是: MQ==

对称加密

采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。
特点
高效:加密速度快, 可以加密大文件密文可逆,
不足:秘钥无法管理复杂,一旦密钥文件泄漏, 就会导致数据暴露。
常见算法
DES : Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。
AES : Advanced Encryption Standard, 高级加密标准 .在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
其他还有 3DES、IDEA

示例

public static void main(String[] args) throws Exception {
	 String key = "12345465";//des key 必须8位
	 String input = "zhansan";
	 String transformation = "DES";
	 String algorithm = "DES";
	 String ers= encryptDES(input,key,transformation,algorithm);
	 System.out.println(ers);
	 String rrr = decryptDES(ers, key, transformation, algorithm);
	 System.out.println(rrr);
	//使用AES加解密
	 key = "1234546511111111";//aes 算法 key 必须是16位
	 transformation = "AES";
	 algorithm = "AES";
	 ers= encryptDES(input,key,transformation,algorithm);
	 System.out.println(ers);
	 rrr = decryptDES(ers, key, transformation, algorithm);
	 System.out.println(rrr);
}
/**
 * 使用DES加密数据
*
 * @param input          : 原文
 * @param key            : 密钥(DES,密钥的长度必须是8个字节)
 * @param transformation : 获取Cipher对象的算法
 * @param algorithm      : 获取密钥的算法
 * @return : 密文
 * @throws Exception
 */
private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
    // 获取加密对象
    Cipher cipher = Cipher.getInstance(transformation);
    // 创建加密规则
    // 第一个参数key的字节
    // 第二个参数表示加密算法
    SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
    // ENCRYPT_MODE:加密模式
    // DECRYPT_MODE: 解密模式
    // 初始化加密模式和算法
    cipher.init(Cipher.ENCRYPT_MODE,sks);
    // 加密
    byte[] bytes = cipher.doFinal(input.getBytes());
    // 输出加密后的数据
    String encode = Base64.encode(bytes);
    return encode;
}

/**
 * 使用DES解密
 *
 * @param input          : 密文
 * @param key            : 密钥
 * @param transformation : 获取Cipher对象的算法
 * @param algorithm      : 获取密钥的算法
 * @throws Exception
 * @return: 原文
 */
private static String decryptDES(String input, String key, String transformation, String algorithm) throws Exception {
    // 1,获取Cipher对象
    Cipher cipher = Cipher.getInstance(transformation);
    // 指定密钥规则
    SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
    cipher.init(Cipher.DECRYPT_MODE, sks);
    // 3. 解密,上面使用的base64编码,下面直接用密文
    byte[] bytes = cipher.doFinal(Base64.decode(input));
    //  因为是明文,所以直接返回
    return new String(bytes);
}

加密模式和填充模式

加密模式
ECB : Electronic codebook, 电子密码本. 需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密,同时加密,原文是一样的,加密出来的密文也是一样的
在这里插入图片描述

优点 : 可以并行处理数据
缺点 : 同样的原文生成同样的密文, 不能很好的保护数据

CBC : Cipher-block chaining, 密码块链接. 每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块
在这里插入图片描述
优点 : 同样的原文生成的密文不一样
缺点 : 串行处理数据.

填充模式
当需要按块处理的数据, 数据长度不符合块处理需求时, 按照一定的方法填充满块长的规则
NoPadding
不填充.在DES加密算法下, 要求原文长度必须是8byte的整数倍在AES加密算法下, 要求原文长度必须是16byte的整数倍。否则报错
PKCS5Padding
数据块的大小为8位, 不够就补足
默认情况下, 加密模式和填充模式为 : ECB/PKCS5Padding如果使用CBC模式, 在初始化Cipher对象时, 需要增加参数, 初始化向量IV : IvParameterSpec iv = new IvParameterSpec(key.getBytes());

加密模式和填充模式

AES/CBC/NoPadding (128)
AES/CBC/PKCS5Padding (128)
AES/ECB/NoPadding (128)
AES/ECB/PKCS5Padding (128)
DES/CBC/NoPadding (56)
DES/CBC/PKCS5Padding (56)
DES/ECB/NoPadding (56)
DES/ECB/PKCS5Padding (56)
DESede/CBC/NoPadding (168)
DESede/CBC/PKCS5Padding (168)
DESede/ECB/NoPadding (168)
DESede/ECB/PKCS5Padding (168)
RSA/ECB/PKCS1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)

示例:

import com.sun.org.apache.xml.internal.security.utils.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DesDemo {
    
    // DES加密算法,key的大小必须是8个字节

    public static void main(String[] args) throws Exception {
    
        String input ="ceshi";
        // DES加密算法,key的大小必须是8个字节
        String key = "12345678";
        // 指定获取Cipher的算法,如果没有指定加密模式和填充模式,ECB/PKCS5Padding就是默认值
        //     String transformation = "DES"; // 9PQXVUIhaaQ=
        //String transformation = "DES/ECB/PKCS5Padding"; // 9PQXVUIhaaQ=
        // CBC模式,必须指定初始向量,初始向量中密钥的长度必须是8个字节
        //String transformation = "DES/CBC/PKCS5Padding"; // 9PQXVUIhaaQ=
        // NoPadding模式,原文的长度必须是8个字节的整倍数 ,所以必须把 硅谷改成硅谷12
        String transformation = "DES/CBC/NoPadding"; // 9PQXVUIhaaQ=
        // 指定获取密钥的算法
        String algorithm = "DES";
        String encryptDES = encryptDES(input, key, transformation, algorithm);
        System.out.println("加密:" + encryptDES);
//        String s = dncryptDES(encryptDES, key, transformation, algorithm);
//        System.out.println("解密:" + s);

    }

    /**
     * 使用DES加密数据
     *
     * @param input          : 原文
     * @param key            : 密钥(DES,密钥的长度必须是8个字节)
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @return : 密文
     * @throws Exception
     */
    private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
    
        // 获取加密对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 创建加密规则
        // 第一个参数key的字节
        // 第二个参数表示加密算法
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // ENCRYPT_MODE:加密模式
        // DECRYPT_MODE: 解密模式
         // 初始向量,参数表示跟谁进行异或,初始向量的长度必须是8位
//        IvParameterSpec iv = new IvParameterSpec(key.getBytes());
         // 初始化加密模式和算法
        cipher.init(Cipher.ENCRYPT_MODE,sks);
        // 加密
        byte[] bytes = cipher.doFinal(input.getBytes());
        // 输出加密后的数据
        String encode = Base64.encode(bytes);
        return encode;
    }

    /**
     * 使用DES解密
     *
     * @param input          : 密文
     * @param key            : 密钥
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @throws Exception
     * @return: 原文
     */
    private static String dncryptDES(String input, String key, String transformation, String algorithm) throws Exception {
    
        // 1,获取Cipher对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 指定密钥规则
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
//        IvParameterSpec iv = new IvParameterSpec(key.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, sks);
        // 3. 解密
        byte[] bytes = cipher.doFinal(Base64.decode(input));
        return new String(bytes);
    }
}

摘要算法

又称为消息摘要(Message Digest)或数字摘要(Digital Digest)
它由一个单向Hash加密函数对消息进行计算得到一个定长的字符串。
特点:

  1. 消息摘要是单向、不可逆的
  2. 无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。例如应用MD5算法摘要的消息有128个比特位,用SHA-1算法摘要的消息最终有160比特位的输出
    常见算法:
  • MD5
  • SHA1
  • SHA256
  • SHA512

示例

public class DigestDemo1 {
    
    public static void main(String[] args) throws Exception{
    
        // 原文
        String input = "aa";
        // 算法
        String algorithm = "MD5";
        // 获取数字摘要对象
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        // 消息数字摘要
        byte[] digest = messageDigest.digest(input.getBytes());
//        System.out.println(new String(digest));
        // base64编码
        System.out.println(Base64.encode(digest));
    }
}

非对称加密

非对称加密算法又称现代加密算法。 是计算机通信安全的基石,保证了加密数据不会被破解。 与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey) 和私有密(privatekey),公开密钥和私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密。如果用私有密钥对数据进行加密,只有用对应的公开密钥才能解密。 因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
在这里插入图片描述
特点
加密和解密使用不同的密钥,解决秘钥传递的问题
如果使用私钥加密, 只能使用公钥解密
如果使用公钥加密, 只能使用私钥解密
处理数据的速度较慢, 因为安全级别高
常见算法
RSA、ECC、EIGamal
生成公钥私钥示例

/**
     * 生成密钥对并保存在本地文件中
     *
     * @param algorithm : 算法
     * @param pubPath   : 公钥保存路径
     * @param priPath   : 私钥保存路径
     * @throws Exception
     */
    public static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {
        // 加密算法
        //String algorithm = "RSA";
        //  创建密钥对生成器对象
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        // 生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 生成私钥
        PrivateKey privateKey = keyPair.getPrivate();
        // 生成公钥
        PublicKey publicKey = keyPair.getPublic();
        // 获取私钥字节数组
        byte[] privateKeyEncoded = privateKey.getEncoded();
        // 获取公钥字节数组
        byte[] publicKeyEncoded = publicKey.getEncoded();
        // 对公私钥进行base64编码
        String privateKeyString = Base64.encode(privateKeyEncoded);
        String publicKeyString = Base64.encode(publicKeyEncoded);
        // 打印私钥
        System.out.println(privateKeyString);
        // 打印公钥
        System.out.println(publicKeyString);

        // 保存文件
        writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
        writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));
    }

加解密示例示例

  public static void test04()  throws Exception {
        String input = "测试字符串";
        // 加密算法
        String algorithm = "RSA";
        PrivateKey privateKey = getPrivateKey("C:\\Users\\pcitc\\IdeaProjects\\testPro\\src\\main\\java\\a.pri", algorithm);
        PublicKey publicKey = getPublicKey("C:\\Users\\pcitc\\IdeaProjects\\testPro\\src\\main\\java\\a.pub", algorithm);
        //私钥加密
        String s = encryptRSA(algorithm, privateKey, input);
        System.out.println("====》私钥加密结果:"+s);
        //公钥解密
        String s1 = decryptRSA(algorithm, publicKey, s);
        System.out.println("====》公钥解密结果:"+s1);

        //公钥加密
         s = encryptRSA(algorithm,  publicKey, input);
        System.out.println("====》公钥加密结果:"+s);
        //私钥解密
        s1 = decryptRSA(algorithm, privateKey, s);
        System.out.println("====》私钥解密结果:"+s1);

//        //公钥加密
//        s = encryptRSA(algorithm, publicKey, input);
//        System.out.println("====》公钥加密结果:"+s);
//        //公钥解密   公钥加密结果公钥解密辉报错 BadPaddingException
//        s1 = decryptRSA(algorithm, publicKey, s);
//        System.out.println("====》私钥解密结果:"+s1);
    }

    /**
     * 写入到文件
     * @param file
     * @param publicKeyString
     * @param forName
     * @throws Exception
     */
    private static void writeStringToFile(File file, String publicKeyString, Charset forName) throws Exception {
        System.out.println("文件路径==>"+file.getAbsolutePath());

        FileOutputStream fileOutputStream = null;
        try{
            fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(publicKeyString.getBytes(forName));

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            fileOutputStream.close();
        }
    }

    public static PrivateKey getPrivateKey(String priPath,String algorithm) throws Exception{
        // 将文件内容转为字符串
        String privateKeyString = readFileToString(new File(priPath), Charset.defaultCharset());
        // 获取密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // 构建密钥规范 进行Base64解码
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
        // 生成私钥
        return keyFactory.generatePrivate(spec);
    }

    public static PublicKey getPublicKey(String pulickPath,String algorithm) throws Exception{
        // 将文件内容转为字符串
        String publicKeyString = readFileToString(new File(pulickPath), Charset.defaultCharset());
        // 获取密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // 构建密钥规范 进行Base64解码
        X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
        // 生成公钥
        return keyFactory.generatePublic(spec);
    }
    private static String readFileToString(File file, Charset defaultCharset) throws Exception {
        //FileInputStream fileInputStream = new FileInputStream(file);
        InputStreamReader read = new InputStreamReader(new FileInputStream(file),defaultCharset);//考虑到编码格式
        StringBuffer sb = new StringBuffer();
        try{
            BufferedReader bufferedReader = new BufferedReader(read);
            String lineTxt = null;
            while((lineTxt = bufferedReader.readLine()) != null){
                //System.out.println(lineTxt);
                sb.append(lineTxt);
            }
            return sb.toString();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            read.close();
        }
        return sb.toString();
    }
    /**
     * 解密数据
     *
     * @param algorithm      : 算法
     * @param encrypted      : 密文
     * @param key            : 密钥
     * @return : 原文
     * @throws Exception
     */
    public static String decryptRSA(String algorithm,Key key,String encrypted) throws Exception{
        // 创建加密对象
        // 参数表示加密算法
        Cipher cipher = Cipher.getInstance(algorithm);
        // 私钥进行解密
        cipher.init(Cipher.DECRYPT_MODE,key);
        // 由于密文进行了Base64编码, 在这里需要进行解码
        byte[] decode = Base64.decode(encrypted);
        // 对密文进行解密,不需要使用base64,因为原文不会乱码
        byte[] bytes1 = cipher.doFinal(decode);
        return new String(bytes1);

    }
    /**
     * 使用密钥加密数据
     *
     * @param algorithm      : 算法
     * @param input          : 原文
     * @param key            : 密钥
     * @return : 密文
     * @throws Exception
     */
    public static String encryptRSA(String algorithm,Key key,String input) throws Exception{
        // 创建加密对象
        // 参数表示加密算法
        Cipher cipher = Cipher.getInstance(algorithm);
        // 初始化加密
        // 第一个参数:加密的模式
        // 第二个参数:使用私钥进行加密
        cipher.init(Cipher.ENCRYPT_MODE,key);
        // 私钥加密
        byte[] bytes = cipher.doFinal(input.getBytes());
        // 对密文进行Base64编码
        return Base64.encode(bytes);
    }

数字签名

数字签名(又称公钥数字签名)是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。它是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术来实现的,用于鉴别数字信息的方法。
数字签名是非对称密钥加密技术(私钥加密只有公钥能解密)与数字摘要技术的应用。
数字签名的主要作用就是保证了数据的有效性(验证是谁发的)和完整性。比如电子合同,就跟纸质合同一样。有这个数字签名就可以进行验证合同是你签的且合同没有被私自改动过(就和纸质合同上签名盖章一样)
如下:使用非对称加密和摘要算法,实现一个甲方张三给乙方李四投资的电子合同。
合同内容:甲方 张三投资1个亿给李四。 需要甲方张三进行数字签名

  1. 甲方张三有自己的一对公钥和秘钥。私钥自己持有(不可泄露),公钥分发给大家(包括李四)
  2. 首先采用摘要算法将合同内容进行摘要计算,假如摘要结果为:“DE81…1TE2”
  3. 甲方张三采用私钥对摘要结果进行加密,假设加密结果为"2ERT33…UI9",那么这个加密结果就是张三的数字签名。
  4. 乙方李四持有甲方的公钥,拿到甲方的签名后,可以对数字签名进行验证,使用甲方公钥对数字签名进行解密,得到合同内容摘要(能用甲方公钥解密证明是甲方签的,其他人不可能有甲方私钥),然后对合同内容再次进行摘要计算,对比得到的摘要结果和解密甲方数字签名得到的摘要结果是否相同。如果相同,那么证明该合同未被篡改过且肯定是甲方签名的。
    在这里插入图片描述

数字证书

对数字签名进行验证时,需要用到公钥。如果公钥是伪造的,那我们无法验证数字签名了,也就根本不可能从数字签名确定对方的合法性了。如何保证自己拿到的公钥是合法的而不是被别人伪造的呢?这就是数字证书要实现的功能。数字证书可以保证公钥信息的可信。

如果我们只拿到一个公钥信息,就无法确认该信息是否合法(未被篡改过),如果除了公钥信息我们同时拿到了权威机构数字签名,(根据上文中数字签名的作用)那么这个公钥就十分可信了。
就像我们只有一个四级证书上面没有教育部的章,那么这个证书只是一张纸谁都可以印,但是上边加盖了教育部的(不可伪造的)印章,那么这张证书就会变的很可信。

总结:数字证书就是由(可信的)权威机构签发的,带有权威机构签名(不可伪造和篡改)的公钥信息。
证书的产生和管理
PKI
PKI是一个包括硬件、软件、人员、策略和规程的集合,用来实现基于公钥密码体制的密钥和证书的
产生、管理、存储、分发和撤销等功能。
PKI架构

  1. CA(认证权威):
    证书的发证机构,负责签发、更新、管理(撤销、查询、审计)证书,验证证书合法性(是否在黑名单、是否合法等)。如果用户想开通一个网站生成自己的证书可以向CA发起申请。
  2. RA(注册权威):受理用户的数字证书申请,协助CA验证核实证书申请者的信息,如果验证合法,则提交CA制证。
  3. 证书存放管理(目录服务):
    证书的存储库,提供证书的存储、修改、删除、获取的能力。如:一共签发了1000套证书,那么这些证书都在证书库中。
  4. 终端实体(证书持有者和应用程序):
    拥有公钥、私钥的用户,可以根据需要申请自己的证书。可以是人、设备、进程

CA 也分为不同级别,需要逐级验证。比如 CA1 不被大家信任,于是可以将身份信息和公钥发送给受信任的 CA2,获得自己的数字证书。CA1 在给其他人签署数字证书时,会在后面附上自己的数字证书这样接受者首先利用 CA2 的公钥验证 CA1,获得 CA1 的公钥后再验证发送者这样逐级签署数字证书,形成了一条信任链,最终的根节点就是自签名证书,如 CA2 可以用自己的私钥把自己的公钥和域名加密,生成证书。

在这里插入图片描述
证书的格式
国际标准X.509定义了电子证书的规范格式,包括拥有者身份信息和公开密钥的数据体、经证书权威机构CA的数字签名等内容
在这里插入图片描述

SSL、TLS 、HTTP和HTTPS

SSL:(Secure Socket Layer,安全套接字层)为Netscape所研发,用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,SSL通过互相认证、使用数字签名确保完整性、使用加密确保私密性,以实现客户端和服务器之间的安全通讯。该协议由两层组成:SSL记录协议和SSL握手协议。握手协议用来协商密钥。 记录协议则定义了传输的格式。
TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。该协议由两层组成:TLS记录协议和TLS握手协议。最新版本的TLS 1.0是IETE(工程任务组)指定的一种新的协议,它建立在SSL 3.0协议规范之上,是SSL 3.0的后续版本。两者差别极小,可以理解为SSL 3.1,它是写入了RFC的。
两者作用

  1. 认证用户和服务器,确保数据发送到正确的客户机和服务器,SSL缺省只进行server端的认证,客户端的认证是可选的
  2. 加密数据以防止数据中途被窃取;
  3. 维护数据的完整性,确保数据在传输过程中不被改变

握手协议
如上所述。握手协议就是双方通过公钥算法协商出一份密钥,然后通过对称加密来通信。握手过程如下:
在这里插入图片描述
SSL客户端(也是TCP的客户端)在TCP链接建立之后,发出一个ClientHello来发起握手,这个消息里面包含了自己可实现的算法列表和其它一些需要的消息,SSL的服务器端会回应一个ServerHello,这里面确定了这次通信所需要的算法,然后发过去自己的证书(里面包含了身份和自己的公钥)。Client在收到这个消息后会生成一个秘密消息,用SSL服务器的公钥加密后传过去,SSL服务器端用自己的私钥解密后,会话密钥协商成功,双方可以用同一份会话密钥来通信了。

HTTP和HTTPS
HTTP 是一种协议,全称叫作:超文本传输协议(HTTP,HyperText Transfer Protocol),是互联网上应用最为广泛的一种网络协议。所有的 WWW 文件都必须遵守这个标准。
HTTPS 也是一种超文本传送协议,(HTTPS,Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版。即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。用于安全的 HTTP 数据传输。
HTTPS 和 HTTP 的区别主要为以下四点:
https 协议需要到 ca 申请证书,目前市面上的免费证书也不少,收费的也都比较贵。
http 是超文本传输协议,信息是明文传输,https 则是具有安全性的 ssl 加密传输协议。
http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
http 的连接很简单,是无状态的;HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 http 协议安全。
在这里插入图片描述

如果对你有帮助烦请顺手点个赞,这是对我最大的鼓励和认可

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

智能推荐

语言毕业设计选题及源代码_区块链毕业设计论文「11」-程序员宅基地

文章浏览阅读615次。区块链作为一种崭新的、颠覆性的技术,是国内外活跃的研究领域和毕业设计选题方向。 本文列出最新的一组区块链方面的论文,希望可以对选择区块链毕业设计的同学们有所帮助, 这是汇智网编辑整理的区块链毕业设计论文系列中的第11篇。区块链相关链接: - 以太坊智能合约与Dapp入门教程 - 以太坊去中心化电商Dapp实战教程 - 以太坊ERC721数字资产实战教程 - 比特币数据分析ETL工具 - Fabri..._区块链大作业及源代码

HTML、CSS精美按钮输入框图形样式_好看的输入框样式-程序员宅基地

文章浏览阅读3.4k次,点赞3次,收藏27次。HTML、CSS精美按钮输入框图形样式_好看的输入框样式

C++内存管理,const、mutable、static、编译过程_c++ static const mutable-程序员宅基地

文章浏览阅读2k次,点赞2次,收藏4次。回答问题可以的。变量修改的本质是存储空间中的数据被改变,我们通过变量名、指针等方式改变数据都是找到数据的存储位置,对存储空间进行操作。换句话说,空间的存储位置决定了一个变量能不能被修改。局部变量存放在栈区,程序运行完毕释放内存。而加了const修饰之后,,我们不可以使用变量名对这块内存进行修改,却可以通过其他方式对修改内存从而达到对变量的修改。全局变量存放在数据段,加const修饰之后,存放在只读数据段,是无法对内存进行操作的。所以一个数据能不能被修改,还是看它存放的位置。变量名和变量我们首_c++ static const mutable

Android安卓 自定义mapbox地图比例尺_android mapbox 地图比例尺-程序员宅基地

文章浏览阅读2.8k次。在给mapbox地图添加比例尺的时候,我没有找到mapbox自带的比例尺,所以就自己写了一个。和其他自定义比例尺原理其实都差不多。首先,加载mapbox地图,这个就不再详细叙述,照着mapbox官网的教程打下来就行了。定义一个自定义View,MapScaleView,在这里计算每一级比例尺在屏幕上需要绘制的长度。计算比例尺的原理是获取屏幕中心的一点的每像素代表的实际距离,因为在同一纬度上每..._android mapbox 地图比例尺

安卓屏幕信息基础知识复习_安卓手机屏幕倍数-程序员宅基地

文章浏览阅读656次。在Android中,像素(px)、分辨率、密度(dpi)和尺寸之間存在著密切的關係。**像素(px)**是屏幕上顯示圖像的最小單位。每個像素都可以顯示一種顏色,多個像素組合在一起可以顯示複雜的圖像。是指屏幕上像素的數量。它通常表示為寬度和高度的乘積,例如1920x1080。分辨率越高,屏幕上可以顯示的細節就越多。**密度(dpi)**是指屏幕上每英寸的像素數量。它用於衡量屏幕的清晰度。密度越高,同樣大小的圖像就會顯得更清晰。是指屏幕的物理大小。它通常以英寸為單位表示。_安卓手机屏幕倍数

poj 1659 Havel-Hakimi定理(图解序列能否成图)_可图解的序列-程序员宅基地

文章浏览阅读540次。题意:给定图解序列(一系列非负整数,这些书)_可图解的序列

随便推点

Jquery学习笔记-程序员宅基地

文章浏览阅读66次。Jquery学习笔记jquery简介:(1)jquery是干什么的呢?l为了简化JavaScript的开发,一些JavsScript库诞生了.JavaScript库封装了很多预定义的对象和实用函数。能帮助使用者建立有高难度交互的Web2.0特性的富客户端页面,并且兼容各大浏览器l当前流行的JavaScript库有...

用python做一个随机题目生成器-程序员宅基地

文章浏览阅读662次。你好!要用 Python 做一个随机题目生成器,你可以使用 Python 的 random 模块来生成随机数。下面是一个简单的例子,它会生成一道加法题:import random# 生成两个随机数num1 = random.randint(1, 10)num2 = random.randint(1, 10)# 计算答案answer = num1 + num2# 打印题目和答..._随机题目生成器

C语言-设计模式-程序员宅基地

文章浏览阅读811次,点赞13次,收藏21次。设计模式的书相信很多人都看过。对于设计模式这样一种方法,相信不同的人有不同的理解。

项目中到底该不该用 Lombok?_项目总要不要使用lombok-程序员宅基地

文章浏览阅读221次。Lombok 作为一款非常流行的工具插件,肯定有它自身的优势所在,到底建不建议在日常开发中使用,我个人其实是一个中立的态度,如果你们团队的人都喜欢它,那推荐你使用,在使用之前,最好培训一下,有哪些坑点,避免踩坑。如果多数人不太喜欢用它,那就不推荐你使用,很多公司禁止你使用它的原因,其实这种插件有点类似那种流氓插件,工作原理不是官方所认可的方式来实现,假如某天新版本的 jdk 突然把这个漏洞给堵住了,那么项目想要升级 jdk,就比较困难。_项目总要不要使用lombok

蓝色音箱改装电源_基于汽车中控音箱系统升级的几种方法-程序员宅基地

文章浏览阅读127次。众所周知,不同配置的汽车在购买的时候,就那么一点点配置就要差几千元,为了节约,避免不必要的费用,其实汽车上一些简单的配置我们是可以自己购买汽车后DIY的。比如音箱,灯光,中控,雷达,倒车影像,辅助变道系统(BSM盲区监测系统),当然还有些加装主动刹车功能的(这个不建议加装)等等一切和车身舒适系统相关的都可以选择性加装。如本文中的音箱系统,很多汽车购买后发现是两个音箱,音质只能说能发出声音来,谈不..._汽车音响电源如何升级

Terminate called after throwing an instance of ‘ros::serialization::StreamOverrunException‘_terminate called after throwing an instance of 'ro-程序员宅基地

文章浏览阅读546次。后来还去ROS WIki看了一下,首先得确认代码没有问题(这个很重要),有些问题编译是不报错得,我是在融合坐标时出现的这个问题,是因为我的数据类型不一样导致得,最后把数据类型全部设置为一致就没有在报错了。_terminate called after throwing an instance of 'ros::serialization::streamov

推荐文章

热门文章

相关标签