0%

加密算法之证书

公钥传输问题?

我们知道,通过用非对称加密对对称加密的密钥进行加密然后在网络中传输,解决了对称加密密钥的不安全传输问题,而非对称加密的公钥是不需要保密的,即可以在网络中传输。那么问题来了,
公钥在传输的过程中有没有可能被攻击呢?答案是有的,假设攻击者在传输过程中劫持了发送方发送的公钥,用自己的公钥替代了真正的公钥,那么接收方收到的就是假的公钥,这样在密文传输
过程中,接收方用的始终是假的公钥,同时劫持者也可以在网络中解密数据,从而达到攻击目的。

这样便引发了一个问题,如何验证公钥?

如何验证公钥?

  1. 发送方对公钥进行签名

    发送方将自己的公钥签名后发送出去,接收方收到后用公钥进行签名验证,很明显,这样做也是不可靠的,原因跟上面提到的一样:公钥无法认证。

    为此如果引入第三方认证机构(证书颁发机构(CA))进行中转如何呢?

  2. 发送方自己生成密钥对,交由CA签名并发送给接收方

    然后将自己的身份信息和公钥发送给CA,CA用自己的公私钥来签名收到公钥信息,然后发送给接收方,同样,这样做也不能避免发送方发送出来的
    数据是可靠的,因为中间人可以对公钥进行替换。

  3. 申请者向CA发起密钥生成请求,由CA生成密钥并将密钥对发送给申请人,而其他人则需要安装证书才能与申请人进行数据传输

    CA生成公钥-私钥对后通过自己的公钥对私钥或者公钥签名后发送给申请人,接收者用CA的公钥验证签名,然后收到数据。这样在整个过程中无论是发送方还是接收方都只需要一次认证即可,而CA的
    公钥一般是提前安装在了PC上,所以对于CA的公钥,不存在传输隐患。

    注意:用于验证签名的CA公钥,我们称之为根证书。由证书颁发机构颁发,并被预先安装在电脑或者软件中。

证书内容

证书内容如下图:

1. 证书算法: 证书算法指明了使用的签名算法,比如使用SHA-1的RSA或者使用SHA-2的ECDSA,还指明了参数(比如位长度)

2. 颁发者: 证书是谁颁发的

3. 有效期: 为一段时间,指明证书有效期限

4. 主题: 包含证书申请人的身份信息,比如某个人或机构的名字

5. 主题的公钥: 指需要证书保护的公钥,除了公钥本身外,还包含算法和算法参数

6. 签名: 此签名覆盖了证书所有其他的域

注意,每个签名都包含两个公钥算法:一个是受保护的公钥算法,另一个被证书用来签名,且两个算法并无关联

证书申请

命令行生成

参照openssl教程

代码生成(Golang)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package main

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"io/ioutil"
"math/big"
mRand "math/rand"
"net"
"os"
"time"
)

func main() {
//获取根证书
caBytes, err := ioutil.ReadFile("conf/root.cert")
if err != nil {
return
}
caBlock, _ := pem.Decode(caBytes)
rootCert, err := x509.ParseCertificate(caBlock.Bytes)
if err != nil {
return
}

privateKey, _ := rsa.GenerateKey(rand.Reader, 1024)
cert := x509.Certificate{
SerialNumber: big.NewInt(mRand.Int63()), //证书序列号
Subject: pkix.Name{ //这里填写证书主题
Country: []string{"cn"},
Organization: []string{"cn", "company"},
OrganizationalUnit: []string{"test"},
Locality: []string{"Beijing"},
Province: []string{"Beijing"},
StreetAddress: []string{"ChangAn Street"},
},
NotAfter: time.Now().Add(7 * 24 * time.Hour), //有效期
NotBefore: time.Now(),
BasicConstraintsValid: true, //
IsCA: false,
EmailAddresses: []string{"test@gmail.com"},
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
}
//parent如果为自己则表示自签证书,此处表示CA签名的证书,如果是CA签发,则公钥需要是根证书的公钥
//certBytes, err := x509.CreateCertificate(rand.Reader, &cert, &cert, &privateKey.PublicKey, privateKey)
certBytes, err := x509.CreateCertificate(rand.Reader, &cert, rootCert, &rootCert.PublicKey, privateKey)
if err != nil {
return
}

file, err := os.Create("conf/cert.pem")
if err != nil {
return
}
block := &pem.Block{
Type: "CERTIFICATE",
Bytes: certBytes,
}
if err = pem.Encode(file, block); err != nil {
return
}
file.Close()
block = &pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
}
file, err = os.Create("conf/private.pem")
if err = pem.Encode(file, block); err != nil {
return
}
file.Close()
}

引用资料

《维基百科——根证书》

《深入浅出密码学——常用加密技术原理与应用》

《Linux命令大全》

最后

这里只是关于证书的简要介绍,详细了解还需要阅读相关书籍。

如有错误,还请指正!

Thanks!

附上代码链接[github.com/pyihe/secret]