非对称加密
对称加密存在的问题
- 当通信对象很多时会面临众多秘钥的有效管理问题。(秘钥管理困难)
- 对于一个新的数据通信对象,密钥怎样进行传输的问题。(秘钥分发困难)
非对称加密
加密解密使用不相同同的钥匙
加密流程
对称加密与非对称加密对比
- 对称加密
- 秘钥数量:1
- 效率:高,适合大文件加解密
- 非对称加密
- 秘钥数量:2
- 公钥:public key,任何人都可以持有。公共的
- 私钥:private key,只有自己持有,任何人都不可以拥有
- 公钥与私钥一一对应,
- 公钥加密,只有自己的私钥可以解密
- 私钥签名,只有自己的公钥可以解密
- 生成过程:
- 选定一个随机数=> 生成私钥 =》 公钥 (不能反推)
- 效率:低,不适合大文件加解密
应用非对称加密的场景
- 通信加密
公钥加密,私钥解密
- https
验证服务器,数字证书,使用ca认证公钥
- 签名(防止篡改)
哈希+非对称加密
- 网银U盾
验证client,U盾相当于私钥,公钥在服务端
- github ssh(secure shell)登录
- ssh是一种网络协议,主要用于计算机之间的加密登录与数据传输
- ssh登录的时候没有ca认证,需要用户自己确认登录主机的指纹,点击yes后把远程主机的指纹存放到本地的know_hosts中,后续登录会跳过警告。
- ssh-keygen -t rsa,演示
RSA非对称加密算法
密文=明文^ E mod N(RSA加密)====> {E, N } ==> 公钥
明文=密文^D modN(RSA解密)====》{D, N} ==> 私钥
核心思想:利用大素数的因式分解困难
素数:除了1和本身能整除,其他数字无法整除的数
go语言实现创建公钥私钥
基本概念
x509: 证书规范
der:公钥私钥的一种编码格式
pem: PEM编码主要用于TLS密钥和证书。
base64:数据编码格式,可逆的
pkcs: 公钥密码的发展而制订的一系列标准。(PKCS 全称是 Public-Key Cryptography Standards )
pkcs1、pkcs8:用的比较多,可以把pkcs1人工转为pkcs8,目前pkcs8比较流行
创建私钥
流程
- 创建私钥
- 对私钥进行编码,生成der格式的字符串
- 将der字符串拼装到pem格式的数据块中
- pem格式进行base64编码,得到最终的私钥
代码
func generateRsaKeyPair(bit int) error {
//rsa
// 1. 创建私钥, GenerateKey函数使用随机数据生成器random生成一对具有指定字位数的RSA密钥。
// func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error)
priKey, err := rsa.GenerateKey(rand.Reader, bit)
if err != nil {
return err
}
// 2. 对私钥进行编码,生成der格式的字符串
//x509包:公钥标准, func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte
derText, err := x509.MarshalPKCS8PrivateKey(priKey)
if err != nil {
return err
}
// 3. 将der字符串拼装到pem格式的数据块中
// type Block struct {
// Type string // 得自前言的类型(如"RSA PRIVATE KEY")
// Headers map[string]string // 可选的头项
// Bytes []byte // 内容解码后的数据,一般是DER编码的ASN.1结构
// }
block := pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil, //头信息,键值对
Bytes: derText,
}
f1, err := os.Create("rsaPriKey.pem")
if err != nil {
return err
}
defer f1.Close()
// 4. pem格式进行base64编码,得到最终的私钥
// err = pem.Encode(os.Stdout, &block)
err = pem.Encode(f1, &block)
if err != nil {
return err
}
return nil
}
创建公钥
流程
- 创建私钥
- 通过私钥得到公钥
- 对公钥进行编码,生成der格式的字符串
- 将der字符串拼装到pem格式的数据块中
- pem格式进行base64编码,得到最终的公钥
代码
func GenerateRsaPubKey(priKey *PrivateKey) error {
// 1. 创建私钥后
// 2. 通过私钥得到公钥
pubKey := priKey.PublicKey
// 3. 对公钥进行编码,生成der格式的字符串
//注意要使用地址,否则报错
derText, err := x509.MarshalPKIXPublicKey(&pubKey)
if err != nil {
return err
}
// 4. 将der字符串拼装到pem格式的数据块中
block := pem.Block{
Type: "RSA PUBLIC KEY",
Headers: nil,
Bytes: derText,
}
f1, err := os.Create("rsaPublicKey.pem")
if err != nil {
return err
}
defer f1.Close()
// 5. pem格式进行base64编码,得到最终的公钥
// err = pem.Encode(os.Stdout, &block)
err = pem.Encode(f1, &block)
if err != nil {
return err
}
return nil
}
注意在生成公钥的时候MarshalPKIXPublicKey
后面的要要传地址&pubKey
go语言实现公钥加密,私钥解密
公钥加密
流程
- 读取公钥文件
- 解码,得到block
- 得到der
- 得到公钥
- 加密
代码
func getRsaPubKey(filename string)(*rsa.PublicKey,error){
//1. 读取公钥文件
info, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
//2. 解码,得到block,
// block, rest := pem.Decode(info)
block, _ := pem.Decode(info)
//3. 得到der
der := block.Bytes
//4. 得到公钥
// func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error)
// ParsePKIXPublicKey解析一个DER编码的公钥。这些公钥一般在以"BEGIN PUBLIC KEY"出现的PEM块中。
// derText, err = x509.MarshalPKIXPublicKey(&pubKey) //这是编码过程
pubInterface, err := x509.ParsePKIXPublicKey(der) //这是解码过程
if err != nil {
return nil, err
}
//断言
pubKey, ok := pubInterface.(*rsa.PublicKey)
//断言失败,返回错误信息
if !ok {
return nil, errors.New("pubKey no ok!")
}
return pubKey, nil
}
//5. 加密
func rsaEncryptData(filename string,src []byte)([]byte,error){
pubKey,err:=getRsaPubKey(filename)
if err!=nil{
return nil,err
}
// EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error)
encryptInfo, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, src)
if err != nil {
return nil, err
}
return encryptInfo, nil
}
私钥解密
流程
- 读取私钥文件
- 解码,得到block
- 得到der
- 得到私钥
- 解密
代码
func getRsaPriKey(filename string)(*rsa.PrivateKey,error){
//1. 读取私钥文件
info, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
//2. 解码,得到block,
block, _ := pem.Decode(info)
//3. 得到der
der := block.Bytes
//4. 得到私钥
priKeyInter, err := x509.ParsePKCS8PrivateKey(der)
if err != nil {
return nil, err
}
//断言
priKey, ok := priKeyInter.(*rsa.PrivateKey)
//断言失败,返回错误信息
if !ok {
return nil, errors.New("priKey no ok!")
}
return pubKey, nil
}
//5. 解密
func rsaDecryptData(filename string,src []byte)([]byte,error){
pubKey,err:=getRsaPriKey(filename)
if err!=nil{
return nil,err
}
info, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, src)
if err != nil {
return nil, err
}
return info, nil
}