PKI的简单理解和实现
Public Key Infrastructure(PKI),中文叫做公开密钥基础设施,也就是利用公开密钥机制建立起来的基础设施。
PKI的简单理解
PKI的核心是身份证明书的发行
PKI的主要目的是用来发行“身份证明书”,在互联网相互通信的时候,如果能相互确认身份证明书,那么我们就知道自己是在跟对的人通信。
网络世界中,我们需要一个信得过的发证机关来发行身份证明书,同时自己要好好保管自己的身份证明书,就像派出所给你发了公民身份证,自己要好好保管一样。
PKI的世界里,这个身份证明书,被叫做“证明书”。发行“证明书”的机关叫做“认证机关”。还有一个就是统一管理证明书的证书“档案库”。这三个东西加起来,就是PKI的主要构成要素。
构成PKI的要素只有三个
构成PKI的主要要素就是下面三个概念
- 证明书 Cert
- 认证机关 CA
- 证书库
说到底,PKI指的是证明书的制作和分发的一种机制。在这个机制的保障前提下,进行可信赖的网络通信。即安全的网路通信保障机制。
比如说,你要和一个自称比尔的男人通信。这个自称比尔的男人,会在通信的最开始,通过网络将证明书发给你,那么通过这个证明书,就证实了他就是比尔。
然后,你用这个“证明书中的公钥”,将你要发送给比尔的内容进行加密,然后发送给比尔。
用“证明书中的公钥”加密过的内容,只能用比尔自己才有的另一个“私钥”才能解密。这样的话,如果你发送给比尔的内容被他人窃取的话,他人也无法解密。
但如何保证比尔的证明书是正确的呢?
这个认证机关就至关重要了,认证机关的可信度,直接与证书的可信度挂钩,也就是与整个PKI机制的可信度息息相关。
认证机关对比尔的公钥进行了数字签名,并生成了证书。比尔拿着认证机关给的证书,在一开始发送身份证明书给我时,就夹带了这个认证证书,而我拿到比尔的身份证明书后,再得到认证机构的公钥。用认证机构的公钥的验证比尔的认证证书是否是CA颁发的。只要我相信CA不会认错人,那我就相信CA的结果,即这个信息确实是比尔发给我的。
假如我想和比尔通讯,流程如下:
- 比尔找CA验明正身,请求获得一个证书
- CA验明以后,CA使用自己的私钥对比尔的公钥进行签名,生成比尔的证书
- 比尔拿着证书向我证明,自己就是比尔
- 我选择向CA询问他的公钥,用来对证书进行验证,得到比尔的公钥,所以这是比尔的证书
- 我在用比尔的公钥对消息进行加密后发给比尔
- 比尔拿到后用自己的私钥解密即可
PKI的简单实现
有了以上的理论基础后,我选择使用GO语言对以上的流程做简单的实现。
使用GO的RSA算法实现简单加密、解密、签名、验证签名。
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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
| package main
import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/pem" "os" )
const bits = 2048 const FilePath = "./pki/certs/"
func GenerateRSAKey(username string) { privateKey,_ := rsa.GenerateKey(rand.Reader,bits) X509PrivateKey := x509.MarshalPKCS1PrivateKey(privateKey) privateKeyFile,_ := os.Create(FilePath + username + "_privateKey.pem") defer privateKeyFile.Close() privateBlock := pem.Block{Type: "RSA Private Key",Bytes: X509PrivateKey} pem.Encode(privateKeyFile,&privateBlock)
publicKey := privateKey.PublicKey X509PublicKey, _ := x509.MarshalPKIXPublicKey(&publicKey) publicKeyFile, _ := os.Create(FilePath + username + "_publicKey.pem") defer publicKeyFile.Close() publicBlock := pem.Block{Type: "RSA Public Key", Bytes: X509PublicKey} pem.Encode(publicKeyFile, &publicBlock) }
func Get_Sign(msg []byte,path string)[]byte{ privateKey:=GetRSAPrivateKey(path) hash := sha256.New() hash.Write(msg) bytes := hash.Sum(nil) sign, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, bytes) if err!=nil{ panic(sign) } return sign }
func Verify_Sign(msg []byte,sign []byte,path string) bool{ publicKey := GetRSAPublicKey(path) hash := sha256.New() hash.Write(msg) bytes := hash.Sum(nil) err := rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, bytes, sign) return err==nil }
func RSA_Encrypt(plainText []byte, path string) []byte { publicKey := GetRSAPublicKey(path) cipherText, _ := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText) return cipherText }
func RSA_Decrypt(cipherText []byte,path string) []byte{ privateKey := GetRSAPrivateKey(path) plainText,_ := rsa.DecryptPKCS1v15(rand.Reader,privateKey,cipherText) return plainText }
func GetRSAPrivateKey(path string)*rsa.PrivateKey{ file, err := os.Open(path) if err!=nil{ panic(err) } defer file.Close() info, _ := file.Stat() buf:=make([]byte,info.Size()) file.Read(buf) block, _ := pem.Decode(buf) privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) return privateKey }
func GetRSAPublicKey(path string) *rsa.PublicKey{ file, err := os.Open(path) if err!=nil{ panic(err) } defer file.Close() info, _ := file.Stat() buf:=make([]byte,info.Size()) file.Read(buf) block, _ := pem.Decode(buf) publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes) if err!=nil{ panic(err) } publicKey := publicKeyInterface.(*rsa.PublicKey) return publicKey }
|
模拟B向A发送消息的流程,中间省略一些消息传递的流程,重点关注身份验证和信息安全的部分。
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
| package main
import ( "fmt" "os" )
func main() { GenerateRSAKey("A") GenerateRSAKey("B") GenerateRSAKey("CA")
A_pub_file, _ := os.Open(FilePath + "A_publicKey.pem") defer A_pub_file.Close() info, _ := A_pub_file.Stat() A_pub := make([]byte,info.Size()) A_pub_file.Read(A_pub)
A_sign := Get_Sign(A_pub,FilePath + "CA_privateKey.pem")
f := Verify_Sign(A_pub,A_sign,FilePath + "CA_publicKey.pem") if f{ fmt.Println("verify is success!") } de_msg := RSA_Encrypt([]byte("hello world."),FilePath + "A_publicKey.pem")
msg := RSA_Decrypt(de_msg,FilePath + "A_privateKey.pem") fmt.Println(string(msg)) }
|
输出结果:
1 2
| verify is success! hello world.
|
参考:
5分钟让你知道什么是PKI - 知乎 (zhihu.com)