Skip to content

Latest commit

 

History

History
571 lines (426 loc) · 37.7 KB

ch01.md

File metadata and controls

571 lines (426 loc) · 37.7 KB

第一章 计算机基础

大纲


1. 二进制

整数

  • 二进制表示
    二进制即逢二进一,在电路板中用高低电平来表示0,1
    1条电路只能表示两种状态:0 或 1,故1条电路最多只能表示2个数字,范围是十进制的0..1
    2条电路可以表示4 (2的2次方) 种状态:00, 01, 10, 11. 故2条电路最多可以表示4个数字,范围是十进制的0..3 (0 到 2^2-1)
    8条电路可以表示256 (2的8次方) 种状态,故8条电路最多可以表示256个数字,范围是十进制的0..255 (0 到 2^8-1)
    8条电路在计算机中表示8 bits. 8 bits = 1 Byte
    Java中byte 类型变量占1个字节 (1 Byte = 8 bits), 表示的范围是从 -128..127

    Q1: 刚才说到8条电路就是8 bits,他的范围是0..255,那byte也是8 bits,为什么他的范围不是 0..255,反而是-128..127?
    A1:

    • 因为负数本身是一个很常见的情况,那对于8条电路来说,怎么表示负数呢?
    • 8条电路, 我们规定最左侧的一条表示正负,0表示正数,1表示负数。这条电路不参与数值表示。
    • 那么8条电路的最大值就是: 0-1111111 (1个0表示正数,7个1表示数值)。7个1所代表的最大数值是 +127
    • 那么8条电路的最小值就是: 1-1111111 (1个1表示负数,7个1表示数值)。7个1所代表的最小数值是 -127
    • 你可能会问,这个范围不是 -127..127 吗?-128怎么来的?
    • 在Java中,数字都是以补码的形式存储的。正数的补码和他的原码、反码是一样的;负数的补码等于他的反码+1;
    • 127的原码反码补码为 0111-1111.
    • -128补码的计算方式为,取出128的原码1000-0000,逐位取反得到0111-1111,加1之后又变为了 1000-0000
    • 因为所有的数字都是以补码形式存在,那么当计算机看到1000-0000的时候,他就是指-128, 而不是128.
    • 128的二进制是1000-0000,这个是不能用8 bits来表示的,因为他跟-128会发生歧义。
    • 这里有具体的解释
  • 原码 反码 补码
    正数的补码和他的原码、反码是一样的;负数的补码等于他的反码+1;
    举例来说:35的原码、反码、补码是:0010-0011
    -35
    原码是:1010-0011
    反码是:1101-1100
    补码是:1101-1101

-35的补码的另外一个解法:求得35的原码,逐位取反,然后加1,得到跟上面的结果是一样的。

  • 加减运算

计算机内部用补码存储的一个好处就是,减法也可以用补码的加法来实现。比如

  00100011 --> 35
+ 11011011 --> -37 (补码)
----------
  11111110 --> -2 (补码)
  • 位移运算

带符号位移 << >>
带符号位移表示符号位参与移动。这种情况下,只有负数右移的情况高位补1,其他情况(包括正数左移、右移;负数的左移)都是空位补0
负数右移:因为负数的最高位是符号位,用1表示负数。当右移之后,应该保持符号位不变。
右移: -35 右移1位: 1101-1101 >> 1 = 1110-1110 (补码), 再取补码得到: 1001-0010 = -18 (近似除以2)
正数右移: 35. 0010-0011 >> 1 = 0001-0001 = 17 (近似除以2)

其他情况比如: 负数左移, -35 << 1 = -70. 他的计算过程如下: -35 的补码是: 1101-1101 左移一位, 空位补0, 结果为: 1011-1010, 注意此处的结果为补码. 想得到他所表示的数字需要取反再加1(补码的补码等于原码) 1011-1010 取反 = 1100-0101 加1 = 1100-0110 = -70.

正数左移: 35左移1位: 0010-0011 << 1 = 0100-0110 = 70.
总体来说在不溢出的情况下,左移1位相当于乘以2; 右移1位近似除以2
正数左移的结果可能是正数也可能是负数; 负数左移的结果可能是负数也可能是正数.

比如byte 类型的 64左移一位: 0100-0000 << 1 = 1000-0000 = -128 (正数左移得到负数)
-96左移一位: 1010-0000 << 1 = 0100-0000 = 64 (负数左移得到正数)

无符号位移 >>>
注意不存在 <<< 无符号左移.
在无符号右移的情况下,符号位和正常的数字一样,一起参与移动. 无论是正数还是负数.高位直接补0.
对于int(32位)来说,右移1位的结果等于右移33位的结果.也就是说右移的实际位数是 n%32.
同理,对于 long(64位) 来说, 右移1位等于右移65位,右移5位等于右移69位. 也就是说实际位数是 n%64

2. 浮点数

浮点数在计算机中的表示方法类似于数学中的科学计数法. 科学计数法的表示是 a x 10^n (aen). 也就是一个常数 乘以 10的 n 次方.

以32位浮点数为例,他在计算机中的表示方法如下: 32位即32bit

第一个 bit 表示符号位
紧接着后面 8 bit 表示指数(也就是 n 次方的 n)
还剩下23 bit, 用来表示有效数字(也就是 科学计数法 中的 a)

符号位, 1 为负数; 0 为正数.

8 bit的指数又叫做阶码. 他所能代表的范围不是 0..256(2^8), 而是 -126..127

其中23 bit 的有效数字可以全部为0, 这种情况代表有效数字为 1.0
1这个数字是默认存在的,这样的话用23bit 可以达到24个 bit 的效果.
也就是说如果23bit 全部为1的情况下等于二进制的1.111...11 (小数点后共23个1), 这是一个无限接近于2的值.

所以32bit 的浮点数,最大可以表示: 2*2^127. 2^127 ~= 1.7 X 10^38. 所以最大值即: 2 x 1.7 x 10^38.

  • 浮点数表示实例: -16 = 1/1000-0011/000..000(23个0)
1 - 代表负数

阶码: 1000-0011 - 这个二进制的10进制数值是131. 131 - 127 = 4. 也就是 2的4次方.

有效数字: 尾数部分等于0.

也就是1.0 x 2^4 = 16.

解释一下为什么阶码是131. 而不直接是4.
简单来说,当需要表示小数的时候需要用到2的负数次方. 所以阶码不能从0开始,而是从-126开始的. 127只是一个中点值. 任何数值的指数部分的值都要减去127得到真正的指数值,然后再求出2的指数次方. 这样的话2的-1次方就可以得到一个0.5的值.当用1.0*0.5的时候就得到了一个浮点数.

详细一点来说的话就是,阶码的表示方法实际上是用移码表示的. 所谓移码就是把一个数值映射到正数域,其特点是可以直观的反映两个真值的大小,对计算机来说不用考虑负号的问题.

[TBC-1] 此处需要解释的更详细.

  • 加减运算

    • 零值检测
    • 对阶操作
    • 尾数求和
    • 结果规格化
    • 结果舍入 [TBC-2] 需要加一个实例来解释对每个步骤的说明

3. 字符集与乱码

  • ASCII

    起初计算机为用0-1信号表示不同的字符,先考虑到的是英文的26个字符大写和小写加上0-9这10个数字,这样就至少有62个字符,除此之外还有一些特殊字符,比如~!@#这样的,加起来一定是超过了64个(我想键盘上的英文字母加数字加上特殊字符一共也不会超过127个). 这里提到了超过64是因为64这个数字是2的6次方.6次方即为6bit. 如果超过了6bit 所能表示的范围,那么至少是需要7个 bit 来表示这些字符的.
    再加上一个奇偶校验位,所以最后决定用8bit 来表示一个字符.这就是1Byte = 8bit 的由来.也就是 ASCII.

  • 汉字

    当计算机在中国设计的时候肯定需要用到汉字.而汉字的数量众多,用1Byte (8个 bit 才能表示127个字符)肯定是不够的,那么肯定得扩展.所以就在 ASCII 的基础上进行扩展,保持对 ASCII 的兼容.
    一个字节只能表示128个字符,所以汉字需要采用双字节进行编码(双字节就是2Byte,他可以表示65535个字符,现在汉字数量是91251个,很明显不够对吧?这是在GB2312中收录了 6763 个常用汉字, GBK (k == kuo 是扩展的意思) 在GB2312基础上进行了扩展,支持繁体字).
    ASCII 码其实就是一种字符编码约定.比如约定 ASCII=65 就是表示A. 97就是表示 a,这是规定好的.这个也就是我们常常会去查阅的 ASCII 码表.
    类似的汉字的编码表在保留了前128个 ASCII 之外增加了其他的数字与汉字的映射关系.也就是说无论是GBK \ GB2312 还是 Unicode \ UTF-8 \ UTF-16 分别规定了自己的码表,确定了该编码方式能表示的字符(不仅仅是汉字还有其他非英文国家的字符).

  • 乱码是怎么回事

    当我们保存文字到记事本或者数据库的时候(其实都是保存到了磁盘),都需要为记事本或者数据库指定一个编码方式,当以指定的编码方式保存之后就要用与这个编码方式兼容的编码来读取;否则就会出现乱码.
    举个例子来说, 假设 22909 用 Unicode 编码是 '好' 这个字, 并且存到了记事本中, 如果我们用非 Unicode 编码来读取这个文件,恰好这个编码方式与 Unicode 不兼容的话,显示出来的就是乱码.

  • UTF-8 / UTF-16 The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

  • Java 中的 char 是用 UTF-16存储在内存的. UTF-16占 2 bytes (16 bits). 他不是用低 8 位去迎合 ASCII 码表,而是规定了一个 Code Points的概念,每个 Code Point 可以对应一个任意长度bytes的字符.

  • 例如这个 SOF问题

    public class UTF8 {
        public static void main(String[] args){
            String s = "ヨ"; //0xFF6E
            System.out.println(s.getBytes().length);//length of the string
            System.out.println(s.charAt(0));//first character in the string
        }
    }
    
    output:
    >>
    3
    

3. TCP/IP

网络分层:

  1. 应用层 (典型协议: HTTP / SMTP)
  2. 传输层 (典型协议: TCP / UDP)
  3. 网络层 (典型协议: IP)
  4. 链路层

程序在发送消息时, 是由应用层发起, 应用层按照既定的协议打包数据, 随后由传输层加上传输双方的端口号; 网络层加上双方的IP地址; 链路层加上双方的MAC地址. 并将数据拆分成数据帧, 经过多个路由器和网关之后到达目标机器

  • IP协议

IP协议的作用是把各种数据包传递给对方. 是无连接, 无状态的, 不能保证数据帧是否有序到达.
IP报文在IP报头中有目标机器的IP地址. 并且在链路层会给将要发送的数据加上MAC地址.
IP 协议使用 ARP (Address Resolution Protocol) 来查找到 MAC 地址对应的目标主机.
ARP 协议的作用是根据IP地址查找MAC地址对应的主机. 他的工作流程类似于快递包裹的投递.

-- ARP协议的工作流程
当我们要投递一个包裹给美国的朋友, 我们会把快递交给离我们最近的快递公司, 这个快递公司也许不负责国际业务, 但他会将这个包裹送到负责国际业务的相关公司进行中转, 这个包括到达国际业务部门时, 国际业务部门发现这个快递是送往美国的, 就会把这个快递送给负责美国业务的航空公司, 然后这个快递送到了美国之后, 再下发到具体的州/市/县, 最终送达到某小区的某户人家

类似的, 当我们通过互联网发送一个消息给位于美国的朋友, 我们的应用程序将数据打包之后发送给我们设备所连接的路由器, 路由器可能本身不知道目标地址的那个MAC对应的主机是哪一台, 路由器就把他交给他的上级节点, 他的上级节点如果通过IP地址找到了MAC地址对应的主机,则直接传递给那台主机;如果找不到目标主机就继续往上传递,直到那台能识别出IP地址所对应的 MAC地址的网络设备; 最后这台网络设备将数据传递给目标主机

  • TTL IP报文中在 IP报头中有一个 TTL(8 bit) 属性. 该属性代表此报文的生存时间, 他是一个数字, 这个数字指定了该数据包所能记过的最多路由器总数. 当一个报文通过网络传递给另外一个主机时,通常这个过程不是一下就能传递到的,而是可能会经过多个物理网络才能到达目标主机. 每经过一个主机就将此数字减去1. 当该字段的值变为0时,数据包就会被丢弃. 并由最后一个路由器负责发送一个ICMP (Internet Control Message Protocal) 给源主机, 以避免源主机无休止的发送报文. 经常使用的 ping / telnet 就是基于 ICMP 的网络状态监测工具.
  • MTU (Maximum Transmission Unit) 最大传输单元. 当数据包在不同的物理网络当中传递时,由于不同的硬件的特性不同,对数据帧的最大长度有不同的限制. 这个限制被称为最大传输单元. 那么不同的物理网之间就需要对数据进行分片,这个分片工作通常是由路由器完成的.
  • TCP建立连接

    • TCP是面向连接的,确保数据在两台设备之间有序可靠到达的协议.
    • TCP报文头中包含了源主机的IP地址和端口号 以及 目标主机的IP地址和端口号, 这4个元素确定了唯一一条TCP连接.
    • TCP是区分服务端和客户端的. 在建立连接之前, 服务端先启动并监听某个端口, 客户端发起对服务器端的连接请求.
    • TCP连接的建立是通过客户端和服务器端的三次握手来达成的.
  • 三次握手是什么?

    三次握手指的是建立连接的三个步骤:

    • 第一次握手: 客户端发送一个数据包, 将SYN置为1, 表示希望建立连接. 假设这个包的序列号是 x. 注意第一次握手完整的过程不仅仅是客户端发送连接请求这一步, 同时还包括, 服务端接收到客户端发来的信息
    • 第二次握手: 服务端收到这个数据包, 看到SYN是1, 得知这个客户端是想要建立连接, 就发送数据包给客户端, 其中 SYN / ACK 都为1, 表示服务器端已经收到了连接请求, 并请求开始跟客户端进行通信(SYN位). 同时发送序列号 (y=x+1, 与ACK位配合) 给客户端 注意第二次握手不仅仅是服务器端发送信息给客户端这一步,同时还包括, 客户端接收到服务端发来的信息
    • 第三次握手: 客户端收到服务端的这个数据包后, 发送数据包给服务端, 其中 ACK 为1, 表示已经收到了服务器端的确认信息, 客户端已经准备好跟服务端通信了. 同时发送序列号 (y+1), 表示收到了服务端的SYNC请求. 注意第三次握手不仅仅是客户端发送消息给服务端,同时还包括, 服务器端接收到客户端发来的信息
  • 为什么TCP建立连接需要三次握手?

三次握手的主要目的有两个: 信息对等防止超时.

  • 关于信息对等, 双方只有确定4类信息才能建立连接, 即双方都要确认: 自己发送数据的能力, 自己接收数据的能力, 对方发送数据的能力, 对方接收数据的能力.
第 N 次握手 客户端 - 自己发报能力 客户端 - 自己收报能力 客户端 - 对方发报能力 客户端 - 对方收报能力 服务端 - 自己发报能力 服务端 - 自己收报能力 服务端 - 对方发报能力 服务端 - 对方收报能力
第 1 次握手 NO NO NO NO NO YES YES NO
第 2 次握手 YES YES YES YES NO YES YES NO
第 3 次握手 YES YES YES YES YES YES YES YES
  • 关于防止请求超时导致脏连接

通常网络报文的生存时间(TTL)要比TCP建立连接超时时间要长

如果两次握手就能创建连接的话, 就可能会出现下面的情景.

客户端发送请求给服务器端
客户端 --SYN(1)--> 服务端
由于网络原因,TCP超时,但连接建立的请求报文的TTL较长所以还在网络上传输.
* --报文--还在网络上传输
* 但TCP已经发生了超时

所以客户端会收到通知,然后客户端就会重新发送连接请求
客户端 --SYN(2)--> 服务端
服务端 --SYN/ACK--> 客户端

* 如果两次握手就创建连接的话,此时客户端和服务端已经可以进行数据传输了

客户端 <--package--> 服务端
(双方进行数据传输)

传输完毕之后, 双方断开连接.
客户端 <-- XX --> 服务端

假设此时最开始的那个连接建立请求 SYN(1) 到达了服务端.
(如果两次握手就能创建连接的话), 服务端此时就会创建一个TCP连接, 并发送 SYN(1)/ACK(1) 给客户端.
客户端的状态因为不是SYN_SENT, 所以会直接丢弃服务端的这个报文,最终导致服务端产生了一个脏连接.

[TBC-3] 在这里插图

那么三次握手为什么就可以防止脏连接的出现呢?

  1. 当服务器端收到SYN(1)这个请求时,也一样会处理,并发送SYN(1)/ACK(1)给客户端
  2. 客户端收到这个报文之后,因为没有处在SYN_SENT状态,所以会直接丢弃这个消息,即:不会发送 ACK(1) 给服务端
  3. 而服务端因为长时间没有收到客户端发来的ACK确认报文,最终超时而导致连接创建失败,因此不会出现脏连接的出现

  • TCP断开连接

TCP断开连接是通过 4 次挥手的过程来完成的.
TCP 断开连接可以是任意一方发起.即 可以由客户端发起也可以由服务器端发起

4次挥手是什么?

  1. A机器想要断开连接, A 发送 FIN 信号给 B.
  2. B收到之后回复 A: ACK, 表示B已经收到了 A的断开请求, 只是现在还有数据没有发送完,所以现在还不能断开(此时 A 已经不能发送消息给 B了, A: FIN_WAIT_2)
  3. B在将所有数据都发送给 A 之后,会发送 FIN/ACK 信号给 A,表示我的数据发送完了,现在可以断开了,只不过我在等你的确认消息. (B: CLOSE_WAIT)
  4. A 回复 ACK 给 B, 代表A 现在要断开连接了.(A: TIME_WAIT)
  • 为什么需要4次挥手?

当第4 步完成之后,A进入 TIME_WAIT状态. A会等待 2MSL(Maximum Segment Lifetime, 1MSL默认是 2 分钟), 如果在等待的时间内没有再收到 B 发送来的数据包,则断开连接; 如果 B 收到了 A发送过来的 ACK 消息,则断开连接

如果第 4 步的消息由于网络原因无法正常送达 B机器, 则 B机器会认为是 A没有收到第三步他发送过去的 FIN/ACK 消息,那么 B 就会再次发送 FIN/ACK 给 A. A收到之后会再次发送 ACK 并重新计时;

如果没有第四次挥手:

  1. B 在第三步发送的 FIN/ACK 消息,A可能没有收到,则 A无法进入 CLOSED 状态
  2. A 在收到 B发来的 FIN/ACK,并发送 ACK 之后立刻断开连接的话,则 B可能无法收到 A发来的 ACK, 则 B可能无法进入 CLOSED 状态.

4. HTTPS

  • 对称加密和非对称加密

对称加密: 加密和解密用的是同一个密钥. 典型的算法是 DES/AES

非对称加密: 加密和解密用的是不同的密钥. 名字分别是:公钥和私钥. 公钥加密的数据只能用私钥解密;私钥加密的数据只能用公钥解密. 典型算法是 RSA

公钥是公开的,任何人都可以拿到; 私钥是私有的,只有自己持有.

非对称加密的适用场景:

  1. 数据加密: A要发送数据给 B, 则 A 需要先拿到 B 的公钥,用公钥加密再发送.此时只有持有 B 的私钥的人可以解密这个数据
  2. 数据签名: A 要证明某数据确实是自己发的,则 A用自己的私钥加密要证明的数据, 则所有知道 A 的公钥的人都可以尝试用 A 的公钥进行解密,如果解密成功则说明是 A 发出来的.因为 A 的公钥只能解密由 A的私钥加密的数据.

一旦私钥泄密,将不能保证上述两个场景的数据安全性.

  • 消息摘要 & 数字签名

消息摘要是一种算法(典型算法如: MD5/SHA-1), 这个算法可以对任意长度的数据进行计算得到一个固定长度的字符串,这个字符串称为原文的消息摘要. (BTW: 因为任意长度的数据有无数种,而固定长度的字符串能代表的范围是有限的,所以不可避免的就会发生两个过多个原文经过消息摘要算法得到相同的消息摘要. 这个现象称作哈希碰撞.)

通常来说,在做数据签名的时候,其他人看到的数据并不是直接显示 A 的私钥加密的数据,因为这样的数据其他人是不能直接看到他的明文的(必须先得到 A的公钥然后用公钥解密). 那么这就造成有些场景下不太方便. 比如公司老板同意给所有员工发 100 个月的工资当做年终奖. 那么这则消息如果只是用老板的私钥进行加密就不太容易看明白.

更方便的做法是用消息摘要加上数据签名的方式,也就是简称数字签名.

具体做法是: 先用消息摘要算法对"每个人发 100 个月的工资当做年终奖"这个原文进行计算得到消息摘要.然后再用老板的私钥对消息摘要进行加密. 最后把 "原文+消息摘要算法+消息摘要明文+消息摘要密文" 这几部分同时发出去.

拿到这个数据的人,可以直接看到"原文", 也可以看到消息摘要的密文. 然后如果觉得感兴趣,想进一步验证这个消息是不是我们老板发出来的, 那就去拿到老板的公钥, 用老板的公钥对消息摘要密文进行解密.

  1. 如果解密成功,就可以得到被加密的那个消息摘要的原文,则说明这个"消息摘要密文"是用老板私钥加密的,也就是说一定是老板发出来的,但现在仍然不能直接说"原文"就是老板发出来的
  2. 我们需要对比一下第一步解密得到消息摘要的原文是否与整体数据当中的那个消息摘要明文是否一致.
  3. 如果不一致说明老板想说的一定不是 "每个人发 100 个月的工资当做年终奖". 这种情况可能的场景是,公司某人跟老板说: 老板,我们给每个人发 100 个月的工资当做年终奖怎么样? 老板说不行, 发 x 个月的. 然后这个人很高兴就把"每人发 x 个月的年终奖"的消息摘要发送给了老板, 然后老板用自己的私钥对这个消息摘要进行了签名,意思就是同意. 这个人得到老板私钥加密的数据之后, 发布公司公告时,写的是"每人发100 个月工资当年终奖", 加上此文字的消息摘要(还有一个情况见第 4 点)并附上老板的私钥加密数据. 这种情况我们用老板的公钥对数据解密之后得到的消息摘要其实是对"每人发 x 个月的工资当年终奖"的计算结果.
  4. 如果一致也不能就完全肯定"原文"就一定是老板的本意. 比如上述第 3 点里面某人附上的消息摘要不是"每人发 100 个月的工资当年终奖"的,而是的确是"每人发 x 个月的工资当年终奖"的消息摘要. 这个情况我们用公钥解密出来的数据就跟此消息摘要是一致的. 这也不能说明发 100 个月工资当年终奖就是老板的本意. 那么怎么破呢? 此时就需要用到数字签名当中的消息摘要算法了, 因为这些算法都是公开的, 我们可以用指定的算法对原文"每人发 100 个月的工资当年中奖"这段文字进行计算消息摘要,结果我们就会发现这个摘要跟数字签名当中的摘要不同,则说明消息还是被人篡改了(作为被奖励 100 个月工资的你可能会空欢喜一场, 但接着看吧!)
  5. 那么数字签名是怎么用的? 这个人被拆穿之后,换了一位大家都信得过的人再发一遍公告,他是这么操作的: "每人发 200 个月的工资当年终奖" + SHA1 + SHA1('原文') + 私钥加密(SHA1('原文')). 这种情况我们再去验证一遍就会发现老板原来是要发 200 个月的工资当年终奖啊!
  • HTTPS连接建立过程
  1. 客户端发起请求, ClientHello. 请求当中带有客户端所支持的 SSL 版本和加密组件 (加密算法和密钥长度) 列表.
  2. 服务器端发送 ServerHello 作为回应. 其中包含了选定的 SSL 版本和加密组件. (从客户端发送过来的 SSL 版本列表和 加密组件列表中选择)
  3. 服务器端发送 Certificate 报文, 报文中包含了包含证书
  4. 服务器端发送 ServerHelloDone 给客户端
  5. 客户端验证证书有效性
  6. 客户端发送 Pre-MasterSecret 给服务器端 (Pre-MasterSecret用证书公钥加密)
  7. 服务器端用私钥解密得到 Pre-MasterSecret
  8. 双方根据 Pre-MasterSecret 计算出来 MasterSecret (Session Secret) 以后用这个对称密钥进行加解密

  • 这证书里面存了什么?

证书里面存的信息包括这个证书是发给谁的(机构名称), 联系人邮箱, 公钥信息, 签名算法. 等信息

  • 这些信息有啥用?

这些信息可以证明持有证书的人确实是证书里面的人或机构.

  • 怎么证明的?

通过私钥. 这些证书是由某个大家(包括你-的计算机-在内)都信任的人用他的私钥来对这些信息进行签名之后的结果.
你信任这个人,所以你信任由他作保证的证书.

  • 谁给他的证书? 如何验证这个证书有效性?

证书是由 CA (Certificate Authority) 签发的. CA 就是上面提到的所有人都信任的第三方. 在我们的操作系统内部都内置了一系列的 root CA 称之为根证书, 当我们拿到由这些根证书机构签发的证书之后,我们用这些根证书的公钥去解密签名, 得到签名原文; 然后用证书中指定的签名算法对证书中的信息进行签名计算, 然后对比计算结果和签名原文, 如果一致则说明证书是有效的.

  • 我自己能给自己发一个这样的证书吗?

不能. 因为你没有 Root CA 证书的私钥. 无法对其他人的证书进行签名. 计算你自己做了一个私钥, 对证书进行签名, 当其他程序验证这个证书有效性的时候, 发现这个证书的 root CA 没有在他的操作系统(或应用程序内部, 比如 Firefox ) 内置列表中,因此造成证书校验失败.

  • 所有的证书都是由 Root CA 签发的吗?

不, 还有一些二级证书代理商. 这种情况下,大概就可以这样理解:

  • 我是 Root CA, 大家都信任我;
  • 我证明张三 就是 张三,大家可以信任张三;
  • 张三证明李四就是李四,大家可以信任李四.

这样就构成了一个信任链. 从技术上来说, 李四的证书的校验过程是这样的: 要验证李四的证书就必须验证给李四签发证书的机构是合法有效的. 那就是先验证张三的证书, 张三的证书是由 Root CA 签发的, 参考上面的过程, 用系统内置的 Root CA 的公钥去验证(用 Root CA 私钥签发的)张三的证书的有效性; 验证通过后, 再用张三证书中的公钥 去验证(用 张三 私钥签发的)李四证书的有效性.

这个链可以很长, 中间任何一个步骤验证失败都导致最终结果失败.

  • 命令生成一个证书, 以及相对应的私钥
➜  EasyCoding git:(master) ✗ openssl req -x509 -sha256 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365
Generating a 2048 bit RSA private key
.+++
..........................................................+++
writing new private key to 'key.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:CN
State or Province Name (full name) []:BJ
Locality Name (eg, city) []:FS
Organization Name (eg, company) []:are
Organizational Unit Name (eg, section) []:easycoding
Common Name (eg, fully qualified host name) []:wliu
Email Address []:[email protected]
➜  EasyCoding git:(master) ✗ ls
LICENSE   README.md cert.pem  key.pem   notes
➜  EasyCoding git:(master) ✗ ll
total 32
-rw-r--r--  1 wliu  staff   1.0K Apr 21 18:33 LICENSE
-rw-r--r--@ 1 wliu  staff   137B Apr 21 20:37 README.md
-rw-r--r--  1 wliu  staff   1.2K Apr 25 21:21 cert.pem
-rw-r--r--  1 wliu  staff   1.8K Apr 25 21:21 key.pem
drwxr-xr-x  6 wliu  staff   192B Apr 25 21:16 notes
➜  EasyCoding git:(master) ✗ cat cert.pem
-----BEGIN CERTIFICATE-----
MIIDcDCCAlgCCQDQweyh/UgzfzANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJD
TjELMAkGA1UECAwCQkoxCzAJBgNVBAcMAkZTMQwwCgYDVQQKDANhcmUxEzARBgNV
BAsMCmVhc3ljb2RpbmcxDTALBgNVBAMMBHdsaXUxHzAdBgkqhkiG9w0BCQEWEDMy
OTA1NTc1NEBxcS5jb20wHhcNMTkwNDI1MTMyMTIwWhcNMjAwNDI0MTMyMTIwWjB6
MQswCQYDVQQGEwJDTjELMAkGA1UECAwCQkoxCzAJBgNVBAcMAkZTMQwwCgYDVQQK
DANhcmUxEzARBgNVBAsMCmVhc3ljb2RpbmcxDTALBgNVBAMMBHdsaXUxHzAdBgkq
hkiG9w0BCQEWEDMyOTA1NTc1NEBxcS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQC5HFX8dzaxQDJ6EoYT2xIn8nWjmpWZCvZZdscJXgDiwk/yx86d
PnViTBFFXS/uemjac0cZw+1jncMgDTw7wpEym1vGPDxKj8+gp1Xt8Ce7aRVo/5Nu
2dlVnuHywB+5L/jVpKTlUWh3emzUxWB1LkYPG7SOJqq1g44ZdYK07rE/05mTuz4Q
KvQX3r3l6IrN0E+ahUtCffsrVamkceu9T6odWGuM9Xe19EFKAKOAhfv5za7Prs1L
j+/zrZqXprYGYFWg4TRMp4auQm+Q6fguXDV74q31GQE29IKAgO+AJOJ3I8A+a3kT
jcPzHjd0GINvTnVnhb2O3i0BDRj1jAO/aI21AgMBAAEwDQYJKoZIhvcNAQELBQAD
ggEBABZpefb8GlOKFjb/96Wl/vjCWuiLiIOANYn+dZb85IlD16cFZUE+m9cxZ+7v
zoW5fUFkAa7CdqTA1BHRb8y/HlbKaEHwNCunpzPUaBw352g6RiVRdUKhC/wN/WLn
fQyLEPUyGUiz8ryyUzftvRvNt3A7U4F7OgmNsGH1nocLo4cJNXRmp4oO9VkGBS9v
Ow02IrLs9rVe34D3GbizDkQ5mBzhoscLI4VN5z+hHHBGQ7KeOZKFY6W0EVsBy1hM
J5dkkLYLTQ237r4l0bGHzZtG+pJpTTkoXt6mCRnYsqMdC812AGpMJD5sn7kKNNDA
vg5SItmmtqaXloT9vZUlbu/dtw0=
-----END CERTIFICATE-----
➜  EasyCoding git:(master) ✗ cat key.pem
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIe8DQKE3MLFcCAggA
MB0GCWCGSAFlAwQBKgQQJ//I1T3BZyJxXTWEOsaW1QSCBNDBewsnQacbYunZDGVW
LJpw/6G7u9iEU66RWtVtM77rjMAbtSQqJn+OE3IS+4McAHS+E8bcRwEltM2jgYI5
vOsJX8y06QLHCbVZAhN/cpcR3uCqT6iZupWW2F/bzbBBl+VohmzvZhCcvoc1BsqF
PbEr/RjNuQgvUUemBIt/5fw1el2xMqkHjOZT+f/4vrBvHWAxliz+EYBzKMHwqnoq
0qY0KIc+I9IBv32PM4OX57qSOD1D2/E/H5Jxwaew5lEEaQsPJKRC2E5UR9TSlokZ
56Ue2fJIMerx6kwRCYrqBpZOK9UgA8kDUJB3hoSZj/Vxv5JkYPu+5JP/W8Lb1/4u
ZHIBVojAA5Lgv93wSJ7sG0u76fuVIizXJsKir5gPiWvm0zi1XfQugHOwVRoQY9OE
bOxNvWKY6LTraVduz3UkWBVDCUaJkUxnLiP4lz1f7oojhtIuWrzFTF4cPDb3HB7V
xlJ+F6BM0KS8XHnAJ6GlEjXXQfPC9XiwS61rl56LibJ54NUJewgGspIYKT5Hc5vR
yRHfyD6w0bqhYVRFGQmCw25AzUVPE9d2rgNAw66iHHypEiKMvffZpohfO0HC3wp/
Y3sBwTUQPVsR+We4ZeArR3A4jElqYySRL9H5JfvLZFwpywBMloaTfK1bBrmpXnx/
xsGoPiilj4dcgZER5sNiimWc7648igXP1r83lW+9X0Cszyvfbx1kZrJfdhz5JBon
kBZ38qerJM2/W6lkBfdZC6X8FlPepg9YXAtofZp3A3DxExrRW81GuwPoyav/m6C0
dLG069XVMF3xVUN+SZwcavvQ0whz6j+iTvRCCVcgqQlyLd9vd8eEwrnsMGdI0HQ0
KTl4UKi+OgRZ1LNOcCIlMYmNSH5EbHGCQQfsb/swa7AebfyY5gcfRHgHwSYpSpio
oG6WQnFPBE7gniW/DgtS5bcsahMdWy7DY3zOiGQiQ8FRf5PuKkgxxFEc7ESjBp4L
Roi1OUQ6V6fgSl9q8MtZaRC11nek7g9q9m33DcNU1Cay6U2h7Vgxp3kk1HKvmdd5
nz02V8pi1zR1x6r7TUNGXGOYgkuP3fwsovnESykL/J4MQyr2OcpBlttX0E6vcYpB
RPLc3yoSOAKR8/zsTPyZBFB6iVzM5/cuAfEigeDoz+bviWy1OT+s+/PiZonK68oT
swFZCyI+ljgewr6zaboebfhy9bUY2veAj/s0hXMVvKoBG1SX4zhqP00mdttsl/Yf
JyBO2Bv6BuEbCX9PJx2eE2fBoRvwOvxEQlx/M3DVuugNLdu0Fv9tavvWtRZkovU+
ZVjZQXGq7Sk8Im0xHJh8dZoj5aZl/Z9TEnuAI4/Uhq11YpXW9bNClKdqBMGNE64R
u6zWjAufuIzotKSk3P07Q7G2ej4rMJoOta0dAtTrp22xRi2k0rr4jRGUbPkWa4KU
t8B+S8rHXF8gnVSRqMB67d97o3bMeQES5MQyFKrAIC7v41x2ga2RkKd835tmesxM
PFpznuSMfHHQKCRyOxsrvj0O7F0gUwQCO7h3Lxm2ztqLVij5mUIJs/EVrSJU5sro
cHnF9QWaON0EdpCt5cD1+LEk/UGHPgtfxj9hOT3LsKygXCQwEy8u7MbwuBNME88T
fDvWL3QO7lUqHgJt9fJ4rZfWbA==
-----END ENCRYPTED PRIVATE KEY-----
  • 查看证书信息:
➜  EasyCoding git:(master) ✗ openssl x509 -in cert.pem -text
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 15042564410877424511 (0xd0c1eca1fd48337f)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=CN, ST=BJ, L=FS, O=are, OU=easycoding, CN=wliu/[email protected]
        Validity
            Not Before: Apr 25 13:21:20 2019 GMT
            Not After : Apr 24 13:21:20 2020 GMT
        Subject: C=CN, ST=BJ, L=FS, O=are, OU=easycoding, CN=wliu/[email protected]
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b9:1c:55:fc:77:36:b1:40:32:7a:12:86:13:db:
                    12:27:f2:75:a3:9a:95:99:0a:f6:59:76:c7:09:5e:
                    00:e2:c2:4f:f2:c7:ce:9d:3e:75:62:4c:11:45:5d:
                    2f:ee:7a:68:da:73:47:19:c3:ed:63:9d:c3:20:0d:
                    3c:3b:c2:91:32:9b:5b:c6:3c:3c:4a:8f:cf:a0:a7:
                    55:ed:f0:27:bb:69:15:68:ff:93:6e:d9:d9:55:9e:
                    e1:f2:c0:1f:b9:2f:f8:d5:a4:a4:e5:51:68:77:7a:
                    6c:d4:c5:60:75:2e:46:0f:1b:b4:8e:26:aa:b5:83:
                    8e:19:75:82:b4:ee:b1:3f:d3:99:93:bb:3e:10:2a:
                    f4:17:de:bd:e5:e8:8a:cd:d0:4f:9a:85:4b:42:7d:
                    fb:2b:55:a9:a4:71:eb:bd:4f:aa:1d:58:6b:8c:f5:
                    77:b5:f4:41:4a:00:a3:80:85:fb:f9:cd:ae:cf:ae:
                    cd:4b:8f:ef:f3:ad:9a:97:a6:b6:06:60:55:a0:e1:
                    34:4c:a7:86:ae:42:6f:90:e9:f8:2e:5c:35:7b:e2:
                    ad:f5:19:01:36:f4:82:80:80:ef:80:24:e2:77:23:
                    c0:3e:6b:79:13:8d:c3:f3:1e:37:74:18:83:6f:4e:
                    75:67:85:bd:8e:de:2d:01:0d:18:f5:8c:03:bf:68:
                    8d:b5
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         16:69:79:f6:fc:1a:53:8a:16:36:ff:f7:a5:a5:fe:f8:c2:5a:
         e8:8b:88:83:80:35:89:fe:75:96:fc:e4:89:43:d7:a7:05:65:
         41:3e:9b:d7:31:67:ee:ef:ce:85:b9:7d:41:64:01:ae:c2:76:
         a4:c0:d4:11:d1:6f:cc:bf:1e:56:ca:68:41:f0:34:2b:a7:a7:
         33:d4:68:1c:37:e7:68:3a:46:25:51:75:42:a1:0b:fc:0d:fd:
         62:e7:7d:0c:8b:10:f5:32:19:48:b3:f2:bc:b2:53:37:ed:bd:
         1b:cd:b7:70:3b:53:81:7b:3a:09:8d:b0:61:f5:9e:87:0b:a3:
         87:09:35:74:66:a7:8a:0e:f5:59:06:05:2f:6f:3b:0d:36:22:
         b2:ec:f6:b5:5e:df:80:f7:19:b8:b3:0e:44:39:98:1c:e1:a2:
         c7:0b:23:85:4d:e7:3f:a1:1c:70:46:43:b2:9e:39:92:85:63:
         a5:b4:11:5b:01:cb:58:4c:27:97:64:90:b6:0b:4d:0d:b7:ee:
         be:25:d1:b1:87:cd:9b:46:fa:92:69:4d:39:28:5e:de:a6:09:
         19:d8:b2:a3:1d:0b:cd:76:00:6a:4c:24:3e:6c:9f:b9:0a:34:
         d0:c0:be:0e:52:22:d9:a6:b6:a6:97:96:84:fd:bd:95:25:6e:
         ef:dd:b7:0d
-----BEGIN CERTIFICATE-----
MIIDcDCCAlgCCQDQweyh/UgzfzANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJD
TjELMAkGA1UECAwCQkoxCzAJBgNVBAcMAkZTMQwwCgYDVQQKDANhcmUxEzARBgNV
BAsMCmVhc3ljb2RpbmcxDTALBgNVBAMMBHdsaXUxHzAdBgkqhkiG9w0BCQEWEDMy
OTA1NTc1NEBxcS5jb20wHhcNMTkwNDI1MTMyMTIwWhcNMjAwNDI0MTMyMTIwWjB6
MQswCQYDVQQGEwJDTjELMAkGA1UECAwCQkoxCzAJBgNVBAcMAkZTMQwwCgYDVQQK
DANhcmUxEzARBgNVBAsMCmVhc3ljb2RpbmcxDTALBgNVBAMMBHdsaXUxHzAdBgkq
hkiG9w0BCQEWEDMyOTA1NTc1NEBxcS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQC5HFX8dzaxQDJ6EoYT2xIn8nWjmpWZCvZZdscJXgDiwk/yx86d
PnViTBFFXS/uemjac0cZw+1jncMgDTw7wpEym1vGPDxKj8+gp1Xt8Ce7aRVo/5Nu
2dlVnuHywB+5L/jVpKTlUWh3emzUxWB1LkYPG7SOJqq1g44ZdYK07rE/05mTuz4Q
KvQX3r3l6IrN0E+ahUtCffsrVamkceu9T6odWGuM9Xe19EFKAKOAhfv5za7Prs1L
j+/zrZqXprYGYFWg4TRMp4auQm+Q6fguXDV74q31GQE29IKAgO+AJOJ3I8A+a3kT
jcPzHjd0GINvTnVnhb2O3i0BDRj1jAO/aI21AgMBAAEwDQYJKoZIhvcNAQELBQAD
ggEBABZpefb8GlOKFjb/96Wl/vjCWuiLiIOANYn+dZb85IlD16cFZUE+m9cxZ+7v
zoW5fUFkAa7CdqTA1BHRb8y/HlbKaEHwNCunpzPUaBw352g6RiVRdUKhC/wN/WLn
fQyLEPUyGUiz8ryyUzftvRvNt3A7U4F7OgmNsGH1nocLo4cJNXRmp4oO9VkGBS9v
Ow02IrLs9rVe34D3GbizDkQ5mBzhoscLI4VN5z+hHHBGQ7KeOZKFY6W0EVsBy1hM
J5dkkLYLTQ237r4l0bGHzZtG+pJpTTkoXt6mCRnYsqMdC812AGpMJD5sn7kKNNDA
vg5SItmmtqaXloT9vZUlbu/dtw0=
-----END CERTIFICATE-----

--8--