加密算法之证书

公钥传输问题?

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

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

如何验证公钥?

  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)

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]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。