TLS with Go

TLS with Go

原文见:https://ericchiang.github.io/post/go-tls/

虽然之前也接触一些 openssl 的编程,但是对证书颁发,证书链的一些细节依然有些似懂非懂。完成这篇文章之后解决了之前的很多困惑,果然实践动手是加固理论的最好方式。

下面的实践是基于Go的TLS,但是搞懂之后别的语言也一样的。

在阅读本文之前,需要先了解以下知识:
数字签名
证书链

公私钥的加解密

先从最基本的公钥和私钥的加密开始,由私钥加密的数据,只有公钥可以解开。go 的 crypto/rsa 包里直接提供了生成公钥和私钥的方法。

以下是生成一对公钥和私钥,其中公钥存在 privKey.PublicKey 里

// create a public/private keypair
// NOTE: Use crypto/rand not math/rand
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
    log.Fatalf("generating random key: %v", err)
}

接下来,我们使用生成的公钥对一些数据进行加密

plainText := []byte("hello world")
// use the public key to encrypt the message
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, &privKey.PublicKey, plainText)
if err != nil {
    log.Fatalf("could not encrypt data: %v", err)
}
log.Printf("%s\n", strconv.Quote(string(cipherText)))

观察输出,加密后的数据已经是不可读的了。接下来,用私钥对加密数据进行解密

decryptedText, err := rsa.DecryptPKCS1v15(nil, privKey, cipherText)
if err != nil {
    log.Fatalf("error decrypting cipher text: %v", err)
}
log.Printf("%s\n", decryptedText)

可以看到,数据被正常的解密之后,就可以看到了明文了。

这是网络中数据安全传输最简单也最基础的一步,通过加密数据,我们可以防止传输过程中数据明文被人获取。

数字签名

公私钥除了加解密之外的另一个应用是,对给定的信息创建一个数字签名。这些签名可以保证被签名文件的有效性,也就是没有被修改过。

具体的做法,首先对传输的信息进行hash运算(这里使用 SHA256),然后用私钥在hash的结果上生成签名。

//对明文进行hash运算
hash := sha256.Sum256(plainText)
fmt.Printf("The hash of my message is: %#x\n", hash)
// The hash of my message is: 0xe6a8502561b8e2328b856b4dbe6a9448d2bf76f02b7820e5d5d4907ed2e6db80

//用私钥在 hash 结果上生成签名
signature, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, hash[:])
if err != nil {
    log.Fatalf("error creating signature: %v", err)
}

接下来,使用公钥对信息以及该信息对应的签名进行认证,来确认信息没有被伪造被修改。可以看到前2种情况,由于信息和签名都对不上,认证失败。

//用上文生成的公钥对明文和签名进行认证,以确认传输过程中信息没有被修改
verify := func(pub *rsa.PublicKey, msg, signature []byte) error {
    hash := sha256.Sum256(msg)
    return rsa.VerifyPKCS1v15(pub, crypto.SHA256, hash[:], signature)
}

fmt.Println(verify(&privKey.PublicKey, plainText, []byte("a bad signature")))
// crypto/rsa: verification error
fmt.Println(verify(&privKey.PublicKey, []byte("a different plain text"), signature))
// crypto/rsa: verification error
fmt.Println(verify(&privKey.PublicKey, plainText, signature))
// <nil>

因此数字签名可以用于保证我们收到的信息的正确性。

生成自签名证书

crypto/x509 是用来生成数字证书的包。首先,要知道一个证书分为两部分: 公钥+证书持有者信息。

第二部分信息包括序列号,有效期,采用的签名算法等等。我们将这部分信息用通用的函数封装起来,作为一个证书模板。

//证书模板,通过该模板默认设置一些证书需要的字段,比如序列号,组织信息,有效期等等
func CertTemplate() (*x509.Certificate, error) {
    //生成随机的序列号 (不同组织可以有不同的序列号生成方式)
    serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值