什么是非对称加密
1976年以前,所有的加密方法都使用对称加密算法:加密和解密使用同一套规则。例如:甲使用密钥 A 加密,将密文传递给乙,乙仍使用密钥 A 解密。如果密钥 A 在甲传递给乙的过程中泄露,或者根据已知的几次密文和明文推导出密钥 A,则甲乙之间的通讯将毫无秘密。
1976年,两位美国计算机学家 Whitfield Diffie 和 Martin Hellman,提出了一种崭新构思,可以在不传递密钥的情况下,完成解密。这被称为 Diffie-Hellman密钥交换算法 假如甲要和乙通讯,甲使用公钥 A 加密,将密文传递给乙,乙使用私钥 B 解密得到明文。其中公钥在网络上传递,私钥只有乙自己拥有,不在网络上传递,这样即使知道了公钥 A 也无法解密。反过来通讯也一样。只要私钥不泄漏,通信就是安全的,这就是非对称加密算法。
使用场景1
公钥用于上锁(加密)。
私钥用于解锁(解密)。
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"os"
)
//Genkeys 生成秘钥对
func Genkeys() {
privateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
//通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
x509_Privatekey := x509.MarshalPKCS1PrivateKey(privateKey)
//创建一个用来保存私钥的以.pem结尾的文件
fp, _ := os.Create("privateKey.pem")
defer fp.Close()
//将私钥字符串设置到pem格式块中
pem_block := pem.Block{
Type: "PUBLIC KEY",
Bytes: x509_Privatekey,
}
//转码为pem并输出到文件中
pem.Encode(fp, &pem_block)
//处理公钥,公钥包含在私钥中
publickKey := privateKey.PublicKey
//接下来的处理方法同私钥
//通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
x509_PublicKey, _ := x509.MarshalPKIXPublicKey(&publickKey)
pem_PublickKey := pem.Block{
Type: "PRIVATE KEY",
Bytes: x509_PublicKey,
}
file, _ := os.Create("publicKey.pem")
defer file.Close()
//转码为pem并输出到文件中
pem.Encode(file, &pem_PublickKey)
}
//使用公钥进行加密
func RSAencrypt(path string, msg []byte) []byte {
//首先从文件中提取公钥
fp, _ := os.Open(path)
defer fp.Close()
//测量文件长度以便于保存
fileinfo, _ := fp.Stat()
buf := make([]byte, fileinfo.Size())
fp.Read(buf)
//下面的操作是与创建秘钥保存时相反的
//pem解码
block, _ := pem.Decode(buf)
//x509解码,得到一个interface类型的pub
pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
//加密操作,需要将接口类型的pub进行类型断言得到公钥类型
cipherText, _ := rsa.EncryptPKCS1v15(rand.Reader, pub.(*rsa.PublicKey), msg)
return cipherText
}
//使用私钥进行解密
func RSAdecrypt(path string, cipherText []byte) []byte {
//同加密时,先将私钥从文件中取出,进行二次解码
fp, _ := os.Open(path)
defer fp.Close()
fileinfo, _ := fp.Stat()
buf := make([]byte, fileinfo.Size())
fp.Read(buf)
block, _ := pem.Decode(buf)
PrivateKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
//二次解码完毕,调用解密函数
afterDecrypter, _ := rsa.DecryptPKCS1v15(rand.Reader, PrivateKey, cipherText)
return afterDecrypter
}
func main() {
content:="今晚打老虎"
fmt.Printf("原文: %s\n",content)
Genkeys() //生成秘钥对文件
cipher :=RSAencrypt("./PublicKey.pem",[]byte(content)) //加密内容
fmt.Printf("加密后内容: %s\n",base64.StdEncoding.EncodeToString(cipher))
origin:= RSAdecrypt("./PrivateKey.pem",cipher)
fmt.Printf("解密后内容: %s\n",string(origin))
}
输出
原文: 今晚打老虎
加密后内容: Ox4+I2CHgWGtek2Nn3ELUD+xHRwPztlYlEsFK3matx+hs7707c4goZftxcNsW7xKDn8so0IN5py2kxdTdxjyE1X0oyIOGF6eulzUWj7ty6eYFIW4dqT0YGnFJUEU4uOtskQavb4zYACiUp0TGT2PpXfCl12xgsugDIjlOWJ60JyfAsvDl2odsfuCEzyBqlinr+8diIy3yu6XOz10fwVb2QQ8ZgvRjf60siPrwVpkcmnlKemthi5cIMZNUa7UE+qLTzYBI8XaynA3TNc/0JFWKGLdP7Q/owMZWuzwDIIigENs0hBTmYWkHcZypes889Co+EBIrxKiV67fNqb/u0KZJw==
解密后内容: 今晚打老虎
使用场景2
私有密钥用于“上锁”(加密得到hash值签名)。
公有密钥用于“解锁”(验证签名)。
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"os"
)
//使用私钥签名,path是私钥路径,msg是要签名的信息
func RsaSign(path string, msg []byte) []byte {
//签名函数中需要的数据散列值
//首先从文件中提取公钥
fp, _ := os.Open(path)
defer fp.Close()
fileinfo, _ := fp.Stat()
buf := make([]byte, fileinfo.Size())
fp.Read(buf)
block, _ := pem.Decode(buf)
PrivateKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
//加密操作,需要将接口类型的pub进行类型断言得到公钥类型
hash := sha256.Sum256(msg)
//调用签名函数,填入所需四个参数,得到签名
sign, _ := rsa.SignPKCS1v15(rand.Reader, PrivateKey, crypto.SHA256, hash[:])
return sign
}
func VerifySign(path string, signText []byte, plainText []byte) bool {
//首先从文件中提取公钥
fp, _ := os.Open(path)
defer fp.Close()
//测量文件长度以便于保存
fileinfo, _ := fp.Stat()
buf := make([]byte, fileinfo.Size())
fp.Read(buf)
//下面的操作是与创建秘钥保存时相反的
//pem解码
block, _ := pem.Decode(buf)
//x509解码,得到一个interface类型的pub
pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
//签名函数中需要的数据散列值
hash := sha256.Sum256(plainText)
//验证签名
err := rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hash[:], signText)
if err != nil {
return false
} else {
return true
}
}
func main() {
content:="I am Enzo"
fmt.Printf("原文: %s\n",content)
hash:=RsaSign("./PrivateKey.pem",[]byte(content))
fmt.Printf("RSA签名: %s \n",base64.StdEncoding.EncodeToString(hash))
result:=VerifySign("./publicKey.pem",hash,[]byte(content))
fmt.Printf("验证结果: %v \n",result)
}
输出:
原文: I am Enzo
RSA签名: JHWw6t6ZRItPwQkWk/DuhQVqhFXa+AgpJoZlDhfNmJrviw9JGlMoDGzaGHKp88T9kO6MiLJjK62EsZ8bHRfEr6vs/b0yU8v7Cj6VCpirHWQ/H1+K5Y4+Yfw5hFmd26bch43tCo6z+NaakRl2Nwu32zqaDTdLoNt68Ia81YUM6i3Nl/5mH89cuklizTezpvyUmrucXrajEBD6KSqmm4Ggxw5tVJBl5H6I9eb2xRBJcrZk2x2MRH4H+neXKQsAImmI2pyseikklu9ImV9cX87gBPFgV6s7xHOhFwn5JWgxspcFLexA+Y7pBZYJwPlFq8aaXbV2VvEPWT0qY/c85DTppg==
验证结果: true