GO实现RSA加密

本文详细介绍了非对称加密的基本概念,包括其历史背景、工作原理以及与对称加密的区别。通过具体的代码示例,展示了如何使用非对称加密进行数据加密和解密,以及如何利用私钥进行签名和公钥进行签名验证的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是非对称加密

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 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值